Ruby gives you lots of leeway. I’m almost tempted to say that there is more than one way to do it, but I would rather assume that it is a property of dynamically typed languages which have very flexible hash and array structures and multitude of built-in functionality to deal with them.

Code blocks, that is lambda‘s, are something that every language should have. It enables composition of functionalities and reduces code bloat. Let’s see a simple example of ‘grep’ command line utility.

if( ARGV.length < 2 )
  puts "usage: grep <expression> <files>"
  exit 1
end
 
regex = Regexp.new(ARGV.shift)
ARGV.each do |inFile|
  f = File.open(inFile)
  f.each do |line|
    if( line =~ regex )
      puts "[#{inFile}:#{f.lineno}] #{line}"
    end
  end
end

It is not the prettiest piece of Ruby but it works. In this ‘grep’ utility code blocks are used to perform functionality upon iterable elements. Lambda’s enable some cool features like dispatch tables (bye-bye if-else clauses). Simply choose what you want to do:

m = {
  :write => lambda { |input| puts "Wrote: #{input}" },
  :times_two => lambda { |i| puts "Doubled: " + (i*2).to_s }
}
 
m[:write].call("foo")
m[:times_two].call(2)

This is in my opinion pretty cool, although there is some syntactical cruft. The same in Perl would be (with magical characters too)

%m = (
  write => sub { print "wrote: @_\n" },
  times_two => sub { print "Doubled: " . $_[0]*2 . "\n" },
);
 
$m{write}->("foo");
$m{times_two}->(2);

Well, too many magical characters for real readability (there are ways around them, albeit a bit more verbose), but the programmer performance is awesome.

Then the ‘duck typing‘, ultimate source of funky defects. Compiler warnings are most of the time good, but for a beginner overcoming the syntactical issues is sometimes just trial-and-error. Fortunately the internet is full of good Ruby-sites and the community altogether seems very vibrant and alive.

Consider this piece of code

require 'pp'
 
h_of_a = { 'parent_key' => {
    'key_level_2' => {
      'key_level_3' => {}
    },
    'key_level_2_2' => {
      'key_level_3_2' => {}
    }
  }
}
 
#pp h_of_a
 
h_of_a.keys.each do | key |
  h_of_a[key].each do | i |
    puts "h_of_a.keys.each key type: " + i.class.to_s
  end
end
 
h_of_a.each do |key, value|
  puts "h_of_a.each value type: " + value.class.to_s
end
h_of_a.each_value { |value| puts "val #{value}" }

This prints out the following:

h_of_a.keys.each key type: Array
h_of_a.keys.each key type: Array
h_of_a.each value type: Hash
val key_level_2key_level_3key_level_2_2key_level_3_2

Just forget the second argument (value) for the lambda or iterate over it a little bit differently and you can find yourself bitten by duck typing as the variable type is not what you expect it to be. Can be confusing but seems to be something to learn. The amount of methods available is a bit overwhelming.

Ruby has managed to arouse my interest and I’m waiting eagerly to get my hands real dirty with it.

Post filed under 7 languages, Software Craftsmanship and tagged , , .

Leave a Reply

Your email address will not be published. Required fields are marked *