I introduced the bug shown below into my code the other day and wanted to better understand the implications.
File.open('test.txt').readlines do |line|
puts "#{line} test"
end
File.open.readlines does exactly as expected and returns an array containing all of the lines in the file. But immediately following that array is a block. The array returned by readlines calls no member methods, each for instance. I’m assuming the block has nothing calling it, therefore it does nothing. In other languages this may have thrown a compiler warning or in C the block would be considered a nested scope and it would execute. But as shown, Ruby (1.9.2) happily runs with no errors, and no output generated by puts.
For completeness here’s the corrected version.
File.open('test.txt').each_line do |line|
puts "#{line} test"
end
I would like to understand the behavior of the first example. Is my assumption correct in that the block is essentially anonymous and didn’t execute because nothing called it?
Here is what is happening in your particular example. When you call
The block is being passed to the readlines method. The block is not passed to the array that is returned by the readlines method. This is a valid case and thus the ruby interpreter does not complain.
Here is a simpler scenario to illustrate this
Let’s say I had a class defined as follows
Now if I call
There will be no error from the interpreter and the “hello” will not be printed.
If I yield to the block in bar as follows
Then the puts will be executed and you should see hello printed
In summary blocks are passed to methods not objects and you can pass a block to any method in ruby even one which does not expect it.