From: Sean O'Halpin Date: 2008-05-03T10:54:14+09:00 Subject: Re: Is there some way to execute a block within an arbitrary lexical scope? On Thu, May 1, 2008 at 8:31 PM, Ruby Talk wrote: > Is there some way to execute a block within a certain lexical scope? > > Let's say the scope I want is inside B: > module A > class B > # .. wanna get in here > end > end > > And I wanted something like: > > method_returning_B_in_lexical_scope_of_A.class_eval do > ... > end > > As most of you know 'A::B.class_eval' does not cut it, since A would not be > in the nesting. > > The obvious reason I want this is to take advantage of the nesting for > lookups. > > Thanks for any ideas! > > -- Ara Vartanian > > Hi, there doesn't appear to be any form of block invocation that changes how constants are looked up. Some experiments: X = :bad module A X = :good class B #...let us say I want to execute something here where X == :good end end # as you state, this doesn't work A.module_eval { X } # => :bad # nor this A.instance_eval { X } # => :bad # nor this A::B.new.instance_eval { X } # => :bad # this does of course module A X # => :good end # and this module A class B X # => :good end end # ...but this surprised me class A::B X # => :bad end # this doesn't work either context_A = A.module_eval { binding } eval("X", context_A) # => :bad # you have to use a string context_A = A.module_eval "binding" eval("X", context_A) # => :good # but again context_B = A::B.module_eval "binding" eval("X", context_B) # => :bad # so you can't parameterize this which means you have to do something # like: def eval_in_namespace(namespace, str) constants = [] namespace.split(/::/).reject{|x| x.empty?}.inject(Module.const_get(self.class.to_s)) { |prev, this| (constants << prev.const_get(this)).last } prefix = constants.map{ |x| "#{x.class.to_s.downcase} #{x}"}.join(';') suffix = constants.map{ 'end'}.join(';') eval "#{prefix}; #{str}; #{suffix}" end eval_in_namespace("A::B", "X") # => :good # not very pretty :S # of course, you could just use: A::X # => :good # but not A::B::X # => :bad # !> toplevel constant X referenced by A::B::X Ara - could you shed some light on how continuations would help here? I don't see it myself. Regards, Sean