My understanding of Ruby blocks and procs was that they are all closures. Now that I've seen it in use with instance_eval, I'm a little confused. What is the magic-sauce, the under workings when looking at the bare metal, that changes how a block's scope behaves under most common uses when compared to use with instance_eval?
Here is an example you can dump in IRB to see what I mean. I've included both a proc.call and block yield version example. Happily, they both behave the same way.
# Testing block/proc and eval
class Example
def initialize(value)
# value defined in the instance
@value = value
end
def call_a_proc(proc)
proc.call self
end
def yield_to_block
yield self
end
end
# Value defined in the global object
@value = 1
example = Example.new 'a'
# the block/proc that prints @value
proc1 = -> instance { puts @value }
# instance calling/yielding the block/proc that prints @value
proc2 = -> instance { instance.call_a_proc proc1 }
proc3 = -> instance { instance.yield_to_block &proc1 }
# instance_eval of the block that prints @value
proc4 = -> instance { instance.instance_eval &proc1 }
# the block/proc reference @value from the global context, the context in which it was defined (standard closure)
example.call_a_proc proc1
example.yield_to_block &proc1
example.call_a_proc proc2
example.yield_to_block &proc2
example.call_a_proc proc3
example.yield_to_block &proc3
# block/proc has it's context redefined as coming from within the instance.
example.call_a_proc proc4
example.yield_to_block &proc4
I understand that this is the point of the instance_eval method, I'm just not exactly sure how it works.