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.