Ruby Details: clone and dup

Another post that’s mostly a reminder to self. 😉

Over at Know Ruby: clone and dup Aaron Lasseigne explained the differences between dup and clone.

However there’s another difference, and that’s the way the methods reproduce the methods an object can respond to. As is so often the case, a short session in a Ruby REPL (like irb or pry) helps to see things in action:

[1] pry(main)> o = Object.new
=> #<Object:0x00000102d298a0>
[2] pry(main)> def o.meth
[2] pry(main)* puts "meth called on object #{self.inspect}"
[2] pry(main)* end
=> :meth
[3] pry(main)> o.meth
meth called on object #<Object:0x00000102d298a0>
=> nil
[4] pry(main)> o_dupped = o.dup
=> #<Object:0x00000102101eb0>
[5] pry(main)> o_dupped.meth
NoMethodError: undefined method `meth' for #
from (pry):7:in `__pry__'
[6] pry(main)> o_cloned = o.clone
=> #<Object:0x00000102138168>
[7] pry(main)> o_cloned.meth
meth called on object #<Object:0x00000102138168>
=> nil

Note that both, clone and dup, return a new object, but only the one returned by clone also has the method defined for object o.
In other words: dup does not replicate an objects singleton methods.

Advertisement

TextMate 1.5.10 … and Ruby 1.9.2

There’s a new version of Textmate available. Cool, thanks! However after installing … I couldn’t run Rake tasks anymore (the keyboard short cut to remember: Shift-Ctrl-R).

In ‘rake_mate.rb’ (line 49, /Applications/TextMate.app/Contents/SharedSupport/Bundles/Ruby.tmbundle/Support/RakeMate/rake_mate.rb). I inserted “.lines” to make it look like this:

tasks = [DEFAULT_TASK] + tasks.lines.grep(/^rake\s+(\S+)/) { |t| t.split[1] }

Additionally I had to ‘re-copy’ the plist.bundle as described on the rvm site.
Now everything works fine again.

Addendum: As mentioned in the rvm guide to using TextMate, I had to (re) move TextMate’s own Builder.rb out of the way:

cd /Applications/TextMate.app/Contents/SharedSupport/Support/lib/ ; mv Builder.rb Builder.rb.backup

Ruby, Sequel and Trees

While working on some tree structure a couple of unit tests failed, when creating some form of summary of said tree structure. First of all here’s a condensed form of the code:

require 'sequel'

DB = Sequel.sqlite
DB.create_table :items do
  primary_key :id
  String :name
  String :foo, :default => 'NOT SET'
  Integer :item_id
end

class Item < Sequel::Model
  one_to_many :items
  def summary
    if items.empty?
      return [ { self.name => self.foo } ]
    else
      items.inject( [] ){ | r, sub_res | r << sub_res.summary }
    end
  end
end

r1 = Item.create :name => 'R1'
r2 = Item.create :name => 'R2'

r1.add_item r2
r2.foo = 'Ding'
#r2.save

[ r1, r2 ].each{ |i|
  puts "Item    : #{ i.id }"
  puts "Direct Foo: #{ i.foo.inspect }"
  puts "Summary   : #{ i.summary.inspect }"
  puts
}

Notice, that I’ve commented out saving r2. The output is:

Item    : 1
Direct Foo: "NOT SET"
Summary   : [[{"R2"=>"NOT SET"}]]

Item    : 2
Direct Foo: "Ding"
Summary   : [{"R2"=>"Ding"}]

What I didn’t expect – and why the unit tests failed – is the ‘NOT SET’ in the r1 summary.

One way to end up with what I originally expected is to save r2. Another way is to set r2.foo before adding r1 to r1:

r2.foo = 'Ding'
r1.add_item r2

How ever I’m still not sure whether this is intended behaviour and why it should behave like this. (If it is, I’d like to know why.)
What do you think?

Pasting Code Is OK

While reading about the DRY principle (for “Don’t repeat yourself”) and the evil of copy-and-paste coding (again), I started thinking what to do instead. Actually, what to do is more or less obvious: Put the code into a place where its accessible to be reused — a method, may be in a new or existing module or class.

So, whenever I feel the ‘need’ to copy code, I now think about cutting it, creating a new method and calling that. Apart form avoiding duplication, the code is now testable immediately by calling the method (instead of getting the surrounding code exercised). And the methods using the code gets shorter.

In the end, it boils down to pasting code being perfectly OK, it’s the copying that causes the trouble.

EURUKO 2007 is over…

So the European Ruby Conference is over for 2007 — a big “Thank you!” to everyone involved: Organisers, the Universitiy of Vienna for the great lecture hall and network we were allowed to use, the Viennese who did a great job getting it done, the speakers — keynote or not — and of course all the attendees.

Euruko 2007 - lecture hall entry I was not very surprised to see that Testing, Quality and Beauty of code was a topic again, as was meta programming and really interesting new applications. For more on that including links to the available slides please see the Euruko 2007 Wiki.

If you like to stay connected and watch the photos we shot in Vienna sign up at Facebook and join the “Eurukobackweb” group. There we’ll also try to get “Euruko 2008” organised. Up to know it’s all open: If you’d like to see it happen in your city or country: Join the group. If you prefer a more sunny season: Join the group. Should you think it should be more organised: Join the group. Or is you “only” like to get in touch with Ruby programmers: Join the group. 🙂

Hope to see as many of you as possible again next year. And a few more new Eurukoristas. It’s fun, interesting and the coffee was excellent (remember? We were in Vienna).

TextMate, Ruby & String Interpolation

While preparing some code example for the Euruko 2007 I noticed a somewhat strange behaviour of TextMate while editing Ruby code. With the Ruby bundle being active, I expect CMD-R (“Apple-R”) to execute the Ruby code a hand. Which it does, unless the text cursor is inside a string interpolation expression.

An example: The first screen shot shows the example code, the cursor being positioned outside the #{ … }.

cursor_outside_srint_interpol.png

After CMD-R is hit, the output is the expected Ruby output as shown below.

outside_result.png

However, if the cursor is inside the string interpolation expression as below

cursor_inside_print_interpol.png

the result of hitting CMD-R doesn’t meet my expectation:


inside_result.png

I wonder why this happens. Apparently the behaviour has to do the the scope the cursor is in. A hint about how to avoid this is greatly appreciated.