Okay, blocks are a grammatical construct, the do ... end and the
{ ... } in ruby. Procs are objects representing a piece of code and a
binding. A block creates a proc, and passes that proc in to the method
just before the block. Inside that method, magically, you can call
'yield', and it will run the proc, regardless of your method
arguments. If you'd prefer less magic, you can put in your arguments
explicitly and receive a Proc object to play with:
def some_method(arg1, arg2, &ourproc)
...
end
and a variable called ourproc will appear inside that method, which
should be either nil, or a Proc object, depending on if you passed one
or not. Similarly, you can avoid the block grammar magic by passing a
proc directly in to a method like this: some_method(1, 2,
&a_local_proc); And you can make a Proc by doing proc { ... } or the
same with the do syntax, or you can more verbosely make a proc using
Proc.new { ... }. both of those return a Proc object, a piece of code
stored in a variable. With that a_local_proc or ourproc, we can do
ourproc[] to call it, or ourproc.call(), and in both of those brackets
we can provide arguments which become the | a, b, c | arguments of the
proc. Yield works similarly with arguments.
Finally, binding. A proc has a binding. You can imagine a binding is
like a hash which contains all the variable names accessible in a
certain place, and their values. This means that when you do proc
{ ... } you get back an object which you can call, but when you call
it, the variables inside that proc will all be the ones from where it
was in the code, not from where you called it. This is the same as how
functions in javascript work. It is possible to both change the
binding, and run a proc in some other place without changing it's
binding permanently (as with instance_eval and friends) for much hacky
fun. Markaby and Shoes make use of that freedom a lot to do a lot of
their trickery.