Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You can try the following hack:</p> <pre><code>class Proc def call_with_vars(vars, *args) Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &amp;self) end end </code></pre> <p>To be used like this:</p> <pre><code>irb(main):001:0* lambda { foo }.call_with_vars(:foo =&gt; 3) =&gt; 3 irb(main):002:0&gt; lambda { |a| foo + a }.call_with_vars({:foo =&gt; 3}, 1) =&gt; 4 </code></pre> <p>This is not a very general solution, though. It would be better if we could give it <code>Binding</code> instance instead of a Hash and do the following:</p> <pre><code>l = lambda { |a| foo + a } foo = 3 l.call_with_binding(binding, 1) # =&gt; 4 </code></pre> <p>Using the following, more complex hack, this exact behaviour can be achieved:</p> <pre><code>class LookupStack def initialize(bindings = []) @bindings = bindings end def method_missing(m, *args) @bindings.reverse_each do |bind| begin method = eval("method(%s)" % m.inspect, bind) rescue NameError else return method.call(*args) end begin value = eval(m.to_s, bind) return value rescue NameError end end raise NoMethodError end def push_binding(bind) @bindings.push bind end def push_instance(obj) @bindings.push obj.instance_eval { binding } end def push_hash(vars) push_instance Struct.new(*vars.keys).new(*vars.values) end def run_proc(p, *args) instance_exec(*args, &amp;p) end end class Proc def call_with_binding(bind, *args) LookupStack.new([bind]).run_proc(self, *args) end end </code></pre> <p>Basically we define ourselves a manual name lookup stack and <code>instance_exec</code> our proc against it. This is a very flexible mechanism. It not only enables the implementation of <code>call_with_binding</code>, it can also be used to build up much more complex lookup chains:</p> <pre><code>l = lambda { |a| local + func(2) + some_method(1) + var + a } local = 1 def func(x) x end class Foo &lt; Struct.new(:add) def some_method(x) x + add end end stack = LookupStack.new stack.push_binding(binding) stack.push_instance(Foo.new(2)) stack.push_hash(:var =&gt; 4) p stack.run_proc(l, 5) </code></pre> <p>This prints 15, as expected :)</p> <p><strong>UPDATE:</strong> Code is now also available <a href="https://github.com/niklasb/ruby-dynamic-binding" rel="noreferrer">at Github</a>. I use this for one my projects too now.</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