A Curious Use of For Loops In Ruby

I was thinking about the use of for loops in Ruby the other day, triggered by one of the Ruby problems over at rubeque.

Now, a for-loop in Ruby usually looks something like this:

for i in collection
  # i takes each value that's in the collection
end

Interesting things happen when the loop variable (i in the case above) is assigned to a value already before the loop. In particular, interesting things can happen if it’s not even a variable.

Let’s see what one can do with a for-loop in Ruby (or rather to a for-loop). Enter pry (or your favourite Ruby-REPL [Read-Evaluate-Print-Loop]):

pry(main)> for Object.new in [1,2,3]; end
NoMethodError: undefined method `new=’ for Object:Class
from (pry):3:in `block in __pry__’

Oh, that’s interesting: The interpreter does not complain about Object.new not being a variable, but rather that there’s not method ‘new=’ for class Object.

OK. let’s play with this… Let’s assume a class Foo:

class Foo
  def initialize foo
    @foo = foo
  end

  def foo= other
    @foo.unshift other
  end
end

Note that there’s no method named foo for class Foo, just ‘foo=’. Initialising a variable now with, say, an empty Array, there’s a curious way to reverse an Array:

pry(main)> f = Foo.new(res)
=> #<foo:0x007fd392c02368 @foo=[]>
pry(main)>
pry(main)> for f.foo in [:first, 2, 'third']
pry(main)* end
=> [:first, 2, "third"]
pry(main)> pp res
["third", 2, :first]
=> ["third", 2, :first]

There is a way to use an empty loop to reverse an Array. (Note. this does not solve the problem given at rubeque, since a class definition is not allowed inside a method definition). In fact there are more ways than this!

A few new things I learned about for loops in Ruby:

  1. They do not require a variable name as the ‘loop variable’
  2. If one uses what looks like a method call (the ‘f.foo’ in the example above) as the  ‘loop variable’ then…
    1. …the object f refers to, doesn’t even need to respond to that method, but
    2. …instead it needs to respond to ‘method_name=’ (‘foo=’ in the example above).

I don’t know what to think about this, but you probably shouldn’t rely on this behaviour or use it in production code.

Advertisement

More Fun With Rakefiles

After Fun With Rakefiles, here’s another ‘behaviour’ I found in a Rakefile.
Some example code is available on GitHub: https://github.com/s2k/rake-loop.

The Setting

The project team worked on a larger number of modules, each in its own sub directory and a global rake task spec:all to run, well, all the specs for all the modules. Since they could run independently, we used the parallel gem to run RSpec in several processes, so our continuous integration system (or local machine) could use the available CPUs (as opposed to running in Ruby threads, which doesn’t utilise all processors [well, at the time of this writing]).

Also, while most of the RSpec code used the (now) old-style should-notation, some new specs were written using the new expect notation. For more on that topic see e.g. RSpec’s New Expectation Syntax by Myron Marston and the GitHub repo for RSpec expectations.

Trying To Fix A Hack

When working with the Rakefile and RSpec files I noticed something odd: The RSpec files using expect weren’t executed. The reason was some code in the Rakefile which (essentially) did this:

 run(rspec_filename) if File.read(rspec_filename).contains? 'should'

That explains why the newer RSpec code was not executed: It didn’t contain any shoulds. But what was going on?

Right after removing that code and re-running bundle exec rake spec:all, I found out that the command a) didn’t finish in any reasonable amount of time and b) over time there were more and more Ruby processes showing up in the system monitor. What was happening?

Why excluding RSpec files not containing ‘should’ helped

As far as the symptom was concerned, excluding RSpec files that didn’t contain the word ‘should’ helped avoiding the behaviour I observed. In any case, I wanted to also execute the other RSpec files, but I would not add to the hack by executing file which contained either ‘should’ or ‘expect’…

A Rake Feature

When rake is called from the command line in a directory that does not contain a Rakefile, then rake looks for a Rakefile in the parent directory. That’s a feature, since it allows you to have one description of a task in some directory, and use that task in all sub directories. (In our case however, something was going horribly wrong.)

Where It went wrong

I then figured out that the modules where the RSpec files didn’t contain the word ‘should’ also didn’t contain a Rakefile. So, when invoking rake in that case, it would move upwards the folder structure finally get to the project global Rakefile and call the task defined there.

Alas, the ‘global’ Rakefile not only contained a task definition for spec:all, but also a task called spec—which only invoked spec:all in a new shell:

namespace :spec do
  desc 'runs all rspec suites'
  task :all => :clean do
    # do stuff, in particular:
    sh "cd #{spec_dir}/../; bundle exec rake spec > #{report_folder}/#{module_name}.tmp 2>&1"
  end

 desc 'delete old report files'
 task :clean do
   FileUtils.rm_rf report_folder
 end
end

task :spec do
  sh 'bundle exec rake spec:all'
end

Notice that the global Rakefile expects a Rakefile containing a definition for the task ‘spec’ to be defined somewhere (see line 5 in the code snippet above), probably in the sub directory where rake is called.

Alas, if there is no Rakefile, rake will step up the directory structure, eventually find the global Rakefile call the task ‘spec’… and restart running ‘spec:all’ again, only to run into the exact same situation again and therefore start a loop.

Lessons Learned

  • Using the parallel gem made a bad situation worse, but it also helped finding the real problem by maximising the effect.
  • It’s probably a good idea to call rake tasks from within a rake task using the methods Rake itself provides (invoke and execute). There’s a discussion on stack overflow named How to run Rake tasks from within Rake tasks?
  • If something goes wrong, fix the underlying issue, rather than working around the problem. It’ll save later generations a lot of work.
  •  Generally speaking, it’s a good idea not to let specialised rake tasks (like running RSpec in some sub directory) end up invoking a more global rake task. That’s especially true if that more global task is going to invoke the more specialised one in turn.

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.

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?

A Pure Ruby Readline

 

As found on Github via RubyCorner on DEV_MEM.dump_to(:blog) – Multimedia systems blog.

For all of those who a running Ruby on a Windows machine (known not to be the ideal place to use the readline library) or on some flavour of Unix (where the library might not be available, at least not from scratch), there is now a pure Ruby implementation available: The pure Ruby readline on Github.

Euruko 2009 – back from Barcelona

These two days with Ruby enthusiasts form all over the world not just Europe was great. Nicely located at citilab, with very good public transportation to the city centre of Barcelona, there was enough space inside as well as out side the building to talk to the other attendees, just relax in the sun or work with the notebook. Two wi-fi networks inside and outside the building could deal well with all the notebooks and mobile phones connected to it. This worked very good indeed.

The presentations I liked most where the ones introducing really exciting and new stuff. First and foremost there’s Rhodes, which enables the creation of native mobile applications with Ruby and HTML. And of course Matz’ keynote was very entertaining as well. More really new stuff was about Adhearsion a way to build voice enabled application with Ruby (and Rails). Then some of the presentations were a really good show. Most notably Javier’s talk about gosu, a framework for games and Pablo’s presentation about Archaeopteryx which was probably the loudest presentation I’ve ever heard. 🙂

The only thing that was a tad bit disturbing for me was that I didn’t have one of the mobile microphones available and was kind of stuck behind the table as well as the phones themselves, as they seemed to go silent now and then. Aslak dealt with this best I think, repeatedly saying “Hello?” directly into the microphone whenever it went silent.

I think this year was the first time Twitter was heavily used during Euruko, reusing a bot made for Scotland on Rails. and this helped enhancing the communication and connecting people even more than in previous years. A special “Thank you” to all for the other attendees who gave me direct feedback about the presentation as well as the corresponding discussion about it, including but not limited to: Andrew Miller, Tim Becker, Mike Just, Dave Frey. Thanks a lot, indeed.

More summaries are available from Javier and Tomasz

Next year Euruko will take place in Krakow, Poland and I’m already looking forward to going there.

Citation of the Day

In his keynote this morning David Heinemeier-Hansson described legacy software as ‘a thing of the past, we don’t like’. For now that’s my favourite quotation of this RailsConfEurope.

Other than that: Roderick van Domburg of Nedforce gave interesting hints at a metric reporting tool for Rails and Saikuro, a cyclomatic complexity analyzer written in Ruby.

Ruby in Munich

It’s time for a new Ruby (and Rails) meeting in Munich. We’ll meet on Wednesday 9th of April starting at 19:00 (CEST) in the Pizzeria Michelangelo.

If youre’ coming, please answer via e-mail or comment by Tuesday (08.04.2008) 12:00 CEST (in order to make a reservation for enough tables). 

Possible topics are: A short report from Euruko2008 which happened in Prague in late March, actually any other Ruby related topics.

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.