From: Jeremy Kemper Date: 2009-08-11T07:45:36+09:00 Subject: Re: instance_variables vs. local_variables On Mon, Aug 10, 2009 at 3:43 PM, Joel VanderWerf wrote: > David Whetstone wrote: >> >> So the implication here is that there is no way to define a local variable >> at run time.  Investigating this question is, in fact, what lead me the >> above discovery.  This is disappointing if true. >> >> I can use method_missing to simulate late binding of local variables, but >> it is inefficient to have method_missing called every time such a variable >> is referenced. (No, I have not profiled to see if this is really a >> performance concern, it just smells bad to me.) >> >> Am I correct?  Is what I would like to do currently impossible? > > If you are eval-ing code, then you can eval against a binding, and define > locals at run time in that binding: > > def get_empty_binding >  binding > end > b = get_empty_binding > > eval("a=1", b) > p eval("a", b) # ==> 1 > > Not sure this is what you're looking for. This means re-parsing that code (just "a" here) on every call, a considerable expense. One place where injecting locals into the current binding would be useful is for compiling ERB templates into methods. The template accepts a hash of local variables. Ideally, we could emit code like def compiled_erb(locals = {}) locals.each { |k, v| eval "#{k} = locals[#{k.inspect}]" } ... ERB source ... end at the top of the generated method. This would be more efficient than evaling the locals in a binding then evaling the ERB in that binding. The next best solution is to generate different methods for each set of locals: def call_erb(locals = {}) specialized_method = "compiled_erb_#{locals.keys.join}" compile_erb(locals) unless respond_to?(specialized_method) send specialized_method, *locals.values end leading to specialized methods like def compiled_erb_abc(a = nil, b = nil, c = nil) ... ERB source ... end def compiled_erb_foobarwhatever(foo = nil, bar = nil, whatever = nil) ... ERB source ... end The can lead to an explosion of methods if you pass arbitrary arguments, but in practice the set of locals keys is finite and small. This is the approach Rails uses [1]. Merb works similarly, but uses one method name and regenerates with different args lists. Exploring this scenario is a fun way to get more deeply acquainted with Ruby, but in the end I wish these hacks were unnecessary. Making an ERB template behave like a method seems natural, but Ruby disagrees. Best, jeremy [1] http://github.com/rails/rails/blob/master/actionpack/lib/action_view/template/renderable.rb#L55-68