Archive for the ‘Ruby’ Category

stupid ruby trick #1

Wednesday, December 12th, 2007

Here’s why I like dynamic languages. I have a template (function) in an XSLT application that I invoke with the number of columns in an output table. The template then returns a list of integer values separated by carets “^”.

Each integer is the width of a column as a percentage of the table width. The ideal width for each column depends on the size of the column header label and text in each row, which is a bit of a subjective fiddle, so I can’t really automate setting the proportion of each column, at least not without doing some advanced parsing of the table data.

Of course, all the integers for a given number of columns are supposed to add up to 100 percent, and the list should have only as many integers as there are columns in the table. For tables with 5 or 6 columns, it’s pretty easy to eyeball the sum, and make sure there’s the right number of values, e.g. “10^20^20^30^20″. When the tables get up to 14 or 15 columns, manually adding up all those column widths to 100 for the right number of columns becomes a PITB. Time for a little scripting!

So I whipped up this little one-liner in irb to do the math for me:

  1.  
  2. C:\USAFIPD\Tools\Reports>irb
  3. >> n = "4^10^10^10^6^6^6^5^6^6^6^5^6^5^6^3"
  4. => "4^10^10^10^6^6^6^5^6^6^6^5^6^5^6^3"
  5. >> eval(n.gsub("^","+"))
  6. => 100
  7. >> puts "sum: " + eval(n.gsub("^","+"))  + " cols: " + n.split("^").length
  8. TypeError: cant convert Fixnum into String
  9.     from (irb):3:in +
  10.     from (irb):3
  11. >> puts "sum: " + eval(n.gsub("^","+")).to_s  + " cols: " + n.split("^").length.to_s
  12. sum: 100 cols: 16
  13. => nil
  14.  >>
  15.  

I made a couple of fumbles and educated guesses, based on my experience with Javascript and Perl, e.g. that eval(n.gsub(...)) would add up the digits. Still, I didn’t have to refer to the Pickaxe Book at all!

I’ll stick that into a .rb file for future use, passing in the list of column widths as an arg (once I remember how to get it from ARGV [or is it ARGS?!]). Gee, maybe I could put the body in a loop that keeps prompting me if the sum is not 100, so I can keep fiddling the string until it’s right… hm…

Ruby script: find duplicate files

Tuesday, June 26th, 2007

A quick google for a script that would find duplicate files by name in a directory tree turned up two promising techniques, one a Ruby script posted to OnJava by Bill Siggelkow and the other a bash script using common Unix tools.

Here’s my attempt to reproduce the bash results in Ruby:

  1. #!/usr/bin/env ruby
  2. require ‘find’
  3.  
  4. files = {}
  5. found = {}
  6.  
  7. # read root directory from command line    
  8. ARGV.each do |arg|
  9.   Find.find(arg) do |f|
  10.     if File.file?(f)
  11.       # accumulate the file names
  12.       files[f] = File.basename(f)
  13.     end
  14.   end
  15. end
  16.  
  17. # count up the number of each file name
  18. files.each_value do |base|
  19.   # Ruby doesn’t allow this Perl idiom: found[base]++
  20.   found[base] = 0 if !found[base]
  21.   found[base] += 1
  22. end
  23.  
  24. # print the path of each file found more than once,
  25. # prepended with rm command commented out
  26. found.each do |name,count|
  27.   if count > 1
  28.     files.each do |path,filename|
  29.       if name == filename
  30.         puts "# rm #{path}"
  31.       end
  32.     end
  33.   end
  34. end

Given a directory structure containing files with duplicate names in different directories, the output looks something like this:

# rm /market/fruits/tomato.txt
# rm /market/vegetables/tomato.txt
# rm /market/fruits/pea.txt
# rm /market/vegetables/pea.txt

The output could be piped to a shell script, in which you’d uncomment the “rm” statements for the files that should be deleted (if that’s what you want).

This is all a bit clunky, if you’ve found a better or more Rubyesque way to do this, let me know!