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.

Reply via email to