From: David Masover Date: 2009-12-09T08:18:50+09:00 Subject: Re: Example Ruby Code On Tuesday 08 December 2009 03:03:18 pm Christopher Davidson wrote: > Marnen Laibow-Koser wrote: > > Christopher Davidson wrote: > >> Can anybody explain how this code actually works in simple terms if > >> possible :). > >> > >> def animals > >> yield "Tiger" > >> yield "Giraffe" > >> end > >> > >> animals { |x| puts "Hello, #{x}" } > > > > Go read about blocks in Ruby. If you don't understand something once > > you've done that, hopefully you'll have a more specific question to > > ask... > > I read about Blocks and thought I understood this quite well, I > understand how this is working nearly, the only thing I don't understand > is how the |x| can be calling the defined yields earlier? Is |x| a > special scenario? No, that's not what's happening. If you understand the Javascript example Phrogz gave, go with that. I'm going to try an example in Ruby... A block is a block of code. It's like a function or a method, only it's not tied to anything yet. Let's rework this example. I'm going to show you a step- by-step reworking, from stuff I'm guessing everyone already knows, to this. Since I have no idea how much you know, I'm not going to explain too much, so stop me where you get confused: def say_hello(x) puts "Hello, #{x}" end def animals say_hello "Tiger" say_hello "Giraffe" end Just a simple method. If you understand how animals works, you should understand how say_hello works in the above. SayHello = proc {|x| puts "Hello, #{x}" } def animals SayHello.call "Tiger" SayHello.call "Giraffe" end Here, SayHello is just a global constant which holds that proc. You can see where it's kind of like a method, but not really. You can't just do SayHello("Tiger"), you have to do SayHello.call("Tiger"). But if you know what constants are, you know it can also be a variable: def animals(block) block.call "Tiger" block.call "Giraffe" end say_hello = proc {|x| puts "Hello, #{x}" } animals(say_hello) That's still doing the same thing, but using a variable instead of a constant. And of course, you could do that last part shorter: say_hello = proc {|x| puts "Hello, #{x}" } animals(say_hello) And why do you need to assign it to a variable? You can just pass it in: animals(proc {|x| puts "Hello, #{x}" }) So where are we? def animals(block) block.call "Tiger" block.call "Giraffe" end animals(proc {|x| puts "Hello, #{x}" }) Ruby actually has a little bit of syntactic sugar here, which Bertram Scharpf showed you. Let's take a step back: def animals(block) block.call "Tiger" block.call "Giraffe" end say_hello = proc {|x| puts "Hello, #{x}" } animals(say_hello) Now, it turns out that the following is almost exactly the same: def animals(&block) block.call "Tiger" block.call "Giraffe" end say_hello = proc {|x| puts "Hello, #{x}" } animals(&say_hello) The difference is, that ampersand is telling Ruby that this is _the_ block for the animals function. That means you can make it a lot shorter: def animals yield "Tiger" yield "Giraffe" end say_hello = proc {|x| puts "Hello, #{x}" } animals(&say_hello) You're almost there -- see, those yields are just block.call. And the block is still there inside animals, it's just invisible. And the final step is just: def animals yield "Tiger" yield "Giraffe" end animals {|x| puts "Hello, #{x}" } See, when you call animals that way, it uses that block as the default block. And when you call yield, you're calling the default block. Now, I lied. It'll actually be a lambda, not a proc. But proc is close enough, it makes sense here, and it's shorter to write.