Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You can think of blocks as closing over both the set of local variables and the current <code>self</code>. </p> <p>In Ruby, you will <strong>always</strong> have access to local variables, no matter what. The <code>self</code> encapsulates instance methods on the current object as well as instance variables.</p> <p>Consider the following code:</p> <pre><code>class Table def initialize(legs) @legs = legs end def with_legs yield @legs end end </code></pre> <p>And then:</p> <pre><code>def some_calling_method name = "Yehuda" Table.new(4) {|legs| puts "#{name} gnaws off one of the #{legs} legs" } end </code></pre> <p>By Ruby's block semantics, you can be assured that <code>name</code> will be available inside the block, even without looking at the method you're calling.</p> <p>However, consider the following:</p> <pre><code>class Person def initialize(name) @name = name end def gnaw Table.new(4).with_legs do |legs| puts "#{@name} gnaws off one of the #{legs} legs" end end end Person.new("Yehuda").gnaw </code></pre> <p>In this case, we are accessing the <code>@name</code> instance variable from inside the block. It works great in this case, but is not guaranteed. What if we implemented table a bit differently:</p> <pre><code>class Table def initialize(legs) @legs = legs end def with_legs(&amp;block) self.instance_eval(&amp;block) end end </code></pre> <p>Effectively, what we're saying is "evaluate the block in the context of a <strong>different</strong> self." In this case, we are evaluating the block in the context of the table. Why would you do that?</p> <pre><code>class Leg attr_accessor :number def initialize(number) @number = number end end class Table def initialize(legs) @legs = legs end def with_leg(&amp;block) Leg.new(rand(@legs).instance_eval(&amp;block) end end </code></pre> <p>Now, you could do:</p> <pre><code>class Person def initialize(name) @name = name end def gnaw Table.new(4).with_leg do puts "I'm gnawing off one of leg #{number}" end end end </code></pre> <p>If you wanted access to the person object inside of the block, you'd have to do:</p> <pre><code>class Person def initialize(name) @name = name end def gnaw my_name = name Table.new(4).with_leg do puts "#{my_name} is gnawing off one of leg #{number}" end end end </code></pre> <p>As you can see, the use of instance_eval can make it simpler and less bulky to access methods of a far-off object inside a block, but comes at the cost of making the <code>self</code> unaccessible. The technique is usually used in DSLs, where a number of methods are injected into the block, but the self doesn't matter that much.</p> <p>This is what's happening with Tk; they're using instance_eval to inject their own <code>self</code> into the block, which is wiping your <code>self</code> clean.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload