There’s Something About Mary
Something of an Awakening
I can be a bit of a language snob. This is usually an unfair knee-jerk reaction. Except when it comes to VB, of course :) And I have a bad habit of treating languages as second class citizens once I find myself writing “#!/blah” at the top of a file. Today’s learning has rescued Ruby from my unwarranted judgement and raised into the realms of A Proper Language.
Controversially, no doubt, I blame Larry Wall for some of this. The ubiquity of Perl and The Camel Book in the previous decade spread a laudable message of “make easy things easy and hard things possible.” But this spawned the impression that Perl was a language that would bend in any direction to achieve whatever was required; a language that didn’t really ‘do’ types and that the freedom you had with its types was achieved more by luck than judgement; a floozy of a language. As I say these are my impressions and not a technical treatment of Perl the language. But to this day it tarnishes my first impression of anything beginning “#!/blah.”
I shall work on this and hopefully the 7 Languages in 7 Weeks process will eradicate this thinking.
The Learning
In day 2 we covered arrays, hashes, code blocks, mixins, modules and sets…oh my!
Arrays
This being Ruby, there’s more to arrays than we may expect from our experience of arrays from other languages.
First off, and consistent with duck typing, we can put anything we want inside an array:
irb(main):001:0> a = []
=> []
irb(main):002:0> a.push 'fred'
=> ["fred"]
irb(main):003:0> a.push 34
=> ["fred", 34]
irb(main):004:0> a.push 23.6534
=> ["fred", 34, 23.6534]
irb(main):005:0> a.push ['fred', 'jack', 12.23, 2325]
=> ["fred", 34, 23.6534, ["fred", "jack", 12.23, 2325]]
irb(main):006:0> a
=> ["fred", 34, 23.6534, ["fred", "jack", 12.23, 2325]]
irb(main):007:0> a.each { |element| puts element.class }
String
Fixnum
Float
Array
Ruby’s API on arrays is very complete. And perhaps this is surprising if we assume an array is just an ordered collection of elements allowing random, indexed access. For example, with push, pop and shift methods we can treat our arrays like stacks and queues.
Hashes
Hashes are Ruby’s associative arrays. We can store anything against any object.
irb(main):033:0* h = {}
=> {}
irb(main):034:0> h[:one] = 1
=> 1
irb(main):035:0> h[1] = "one"
=> "one"
irb(main):036:0> h["one"] = :one
=> :one
irb(main):037:0> h
=> {1=>"one", "one"=>:one, :one=>1}
We can iterate over a hash’s keys, values and key-value pairs:
irb(main):038:0> h.keys
=> [1, "one", :one]
irb(main):039:0> h.values
=> ["one", :one, 1]
irb(main):040:0> h.each { |kvp| p kvp }
[1, "one"]
["one", :one]
[:one, 1]
That last example, using each leads us on nicely to blocks.
Blocks
Ruby supports anonymous functions through Code Blocks. We can pass these blocks to methods either as first-class parameters or via Ruby’s yield keyword.
Here’s a simple example using yield:
def one_to_ten
i = 1
while i <= 10
yield i
i += 1
end
end
one_to_ten {|x| puts x}
y = 1
one_to_ten do |x|
y *= x
end
puts y
The code block is defined using either curly braces ({ and }) or by do and end. The convention being that {} is used for single line blocks. In both cases the argument list to the block is given between the two pipe symbols ‘|’.
To pass a block as a parameter we decorate the parameter name with an ampersand (&):
def do_something_with_this(&block)
block.call
end
Modules and Mixins (Magic)
On the face of it Modules in Ruby appear quite innocuous. They define some methods. Good stuff. Then we look a little deeper and see that they are brought into other classes using the include keyword. And then another penny drops. Oh my.
Let me attempt to recreate this story with some simple code.
First we define our Module:
module DrinkSomething
def drink_coffee
puts "Hmm, roasted bean goodness"
end
def drink_tea
puts "Ahhh, infused perfection"
end
end
So far so so. Next up we make use of it:
class OverworkedPerson
include DrinkSomething
end
mw = OverworkedPerson.new
mw.drink_tea
Ok, well that’s a bit wordy. I mean why not just define drink_tea on OverworkedPerson and be done? Well, okay but what if we now bring Ruby’s duck typing into the game. Lets ask something to “quack” inside our module:
module DrinkSomething
def drink_coffee
puts "Hmm, roasted bean goodness"
end
def drink_tea
puts "Ahhh, infused perfection"
end
def go_have_a_drink
if likes_coffee?
drink_coffee
else
drink_tea
end
end
end
See that call to likes_coffee? Where’s that coming from?
class OverworkedPerson
include DrinkSomething
attr :coffee_drinker
def initialize(likes_coffee)
@coffee_drinker = likes_coffee
end
def likes_coffee?
@coffee_drinker
end
end
coffe_worker = OverworkedPerson.new(true)
coffe_worker.go_have_a_drink
tea_worker = OverworkedPerson.new(false)
tea_worker.go_have_a_drink
We’ve updated our OverworkedPerson to expose a drinking preference. And the module uses that through the power of duck typing. With languages such as C# or Java such a contract would need to be made explicit through an interface. Now our OverworkedPerson knows about it’s preference of beverage but stays blissfully unaware of the mechanics of hot drink making. Instead our module acts as a mixin to provide this service based on the implied contract of the likes_coffee? method.
This is how mixins work. For example the enumerable Ruby standard mixin relies on the including class implementing the each method. Powerful stuff.
There’s one more little thing here too. Ruby classes are open. If we want to enhance a standard class with some of our own goodness then we can do so by adding our own include:
class File
include Grep
end
Here we are adding our Grep module to the standard File class.
The Homework
Day 2’s work began in the none-too-shabby setting of Yu-foria, Covent Garden. There I met with Aimee to tackle the first of these problems. Coffee, yoghurt, wifi, code and an apparent lack of appreciation for the market value of fruit made for a good hour.
Printing an Array’s Contents
Aimee and my efforts on this can be found on Aimee’s github repo
Following on from that I had a play with modules and mixins to solve the problem. The results of which can be found in array_each.rb
I don’t think the result is any cleaner than that achieved by the elegance of the each_slice solution shown in Aimee’s repo but it was an instructive play.
Update the Tree’s API
This was an interesting challenge. We were provided a simple tree implementation and our task was to transform it’s API such that it could take, as its constructor parameter, a hash of hashes that represented the tree.
Instinctively I wanted to use what we had learnt about mixins to make the Hash the tree. In retrospect I can see some problems with this: it relies on a specific structure of the hash such that every value is itself a hash yet it applies to all hashes. The code is on github but reproduced here too:
module HashTree
def node_name
keys[0]
end
def children
children_list = []
values[0].each_pair do |k,v|
children_list.push({k => v})
end
children_list
end
def visit(&block)
block.call self
end
def visit_all(&block)
visit &block
children.each { |child| child.visit_all &block }
end
end
class Hash
include HashTree
end
class Tree
attr :node_hash
def initialize(seed_hash = {})
@node_hash = seed_hash
end
def visit(&block)
node_hash.visit &block
end
def visit_all(&block)
node_hash.visit_all &block
end
end
my_tree = Tree.new({'grandpa' => {'dad' => {'child_1' => {}, 'child_2' => {}}, 'uncle' => {'child_3' => {}, 'child_4' => {}}}})
my_tree.visit { |node| puts node.node_name }
puts
puts 'Visiting all'
my_tree.visit_all { |node| puts node.node_name }
A Simple Grep
The challenge was to recreate a simple grep tool. The code below provides the core of a solution but does not tie in with the cli to give a user interface. Using a module the solution below will bestow grep-ability onto anything implements an each method.
module Grep
def grep(match)
line_count = 1
each do |line|
yield({:line_no => line_count, :text => line}) if line =~ Regexp.new(match)
line_count += 1
end
end
end
class File
include Grep
end
def grep_file(filename, match)
File.open(filename) do |file|
file.grep(match) { |match| puts "#{match[:line_no]} #{match[:text]}" }
end
end
A colleague of mine pointed out something interesting. This code does not necessarily look very testable. After all we have an immediate dependency on a concrete type (File) – how can we stub that out in our tests? Now I have now idea what testing idioms exist in Ruby but I suspect duck typing plays a big part in stubbing out dependencies. So now I’m inclined to think that actually this is testable as the bit we care about testing is nicely wrapped up in our module which we can happily include in any object we want for testing purposes.
Quick Summary
I felt today’s work really brought Ruby to life for me. It separated itself from my previous experiences and became a free-standing language. The duck typing proved enormously powerful – especially when combined with the flexibility of modules and mixins.
One thing that came to mind whilst working with all these blocks is that lurking nasty of working with closures and deferred execution. I was just going to link to another post showing this behaviour but a quick google did not bring one up so here’s some code:
def bad_closure_list
my_number_multiplier_list = []
i = 0
while i < 10
my_number_multiplier_list.push lambda {|x| i * x}
i += 1
end
return my_number_multiplier_list
end
def do_something_with_bad_closures(closure_list)
closure_list.each do |closure|
num = closure.call(1)
puts num
end
end
do_something_with_bad_closures(bad_closure_list)
Note the problem happens at line 5 where we capture the loop variable in our closure. We are only ever capturing the same variable for every closure we create. Therefore when we later come to execute out code blocks, each will be referring to the same, single, variable.
Here’s a rather detailed examination of Ruby code blocks.
Teh Codez
Github repo for Ruby day 2