Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Use Ruby2Ruby</strong></p> <pre><code>def save_for_later(&amp;block) return nil unless block_given? c = Class.new c.class_eval do define_method :serializable, &amp;block end s = Ruby2Ruby.translate(c, :serializable) s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}') end x = 40 s = save_for_later { |y| x + y } # =&gt; "lambda { |y|\n (x + y)\n}" g = eval(s) # =&gt; #&lt;Proc:0x4037bb2c@(eval):1&gt; g.call(2) # =&gt; 42 </code></pre> <p>This is great, but it does not close over free variables (like <code>x</code>) and serialize them along with the lambda.</p> <p>To <a href="https://stackoverflow.com/questions/503583/how-do-you-access-the-symbol-table-in-ruby">serialize variables</a> also, you can iterate over <code>local_variables</code> and serialize them as well. The problem, though, is that <code>local_variables</code> from within <code>save_for_later</code> accesses only <code>c</code> and <code>s</code> in the code above -- i.e. variables local to the serialization code, not the caller. So unfortunately, we must push the grabbing of local variables and their values to the caller.</p> <p>Maybe this is a good thing, though, because in general, finding all free variables in a piece of Ruby code is <a href="http://en.wikipedia.org/wiki/Undecidable" rel="nofollow noreferrer">undecidable</a>. Plus, ideally we would also save <code>global_variables</code> and any loaded classes and their overridden methods. This seems impractical.</p> <p>Using this simple approach, you get the following:</p> <pre><code>def save_for_later(local_vars, &amp;block) return nil unless block_given? c = Class.new c.class_eval do define_method :serializable, &amp;block end s = Ruby2Ruby.translate(c, :serializable) locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}') end x = 40 s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y } # =&gt; "lambda { |y| _ = 40; x = 40;\n (x + y)\n}" # In a separate run of Ruby, where x is not defined... g = eval("lambda { |y| _ = 40; x = 40;\n (x + y)\n}") # =&gt; #&lt;Proc:0xb7cfe9c0@(eval):1&gt; g.call(2) # =&gt; 42 # Changing x does not affect it. x = 7 g.call(3) # =&gt; 43 </code></pre>
 

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