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