> Let's say I'm doing some metaprogramming from another class and I > want to do something in B's full lexical class scope.
then you will need to use continuations.
a @ http://codeforpeople.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama
Well, let's say that that something is a new class I want to define within that scope. And I'd like the innards of that class to be able to take advantage of the the natural, idiomatic lookup rules, where the interpreter traipses up the ancestor chain.
To be more clear, let's say I have
X = :bad module A X = :good class B #...let us say I want to execute something here where X == :good end end
And I'd like to execute something from outside that lexical scope (let's say from my metaprogramming classes) within that [A, A::B] lexical scope.
I guess what I'm asking is: is there any way of faking lexical scope (for the purposes of metaprogramming)?
Robert Klemme wrote: > 2008/5/2 ara.t.howard <ara.t.how...@gmail.com>:
>> On May 1, 2008, at 3:31 PM, Ruby Talk wrote:
>>> Let's say I'm doing some metaprogramming from another class and I want to
>> do something in B's full lexical class scope.
> What exactly is this "something"?
>> then you will need to use continuations.
> It depends of course what should be achieved. A simple constant > lookup is easily done via #const_get. Other things can be achieved > via #instance_eval.
Thanks for your suggestion. I'm a little hazy on how this would help. If I defined a proc or code block or whatever elsewhere, it's bound to the lexical scope where it was defined. How does calling it from the continuation help given that?
Anyway, maybe that's not what you were thinking, and it's likely I'm missing the obvious here. I'm not the best at problem solving with continuations.
> On May 1, 2008, at 3:31 PM, Ruby Talk wrote: >> Let's say I'm doing some metaprogramming from another class and I >> want to do something in B's full lexical class scope.
> then you will need to use continuations.
> a @ http://codeforpeople.com/ > -- > we can deny everything, except that we have the possibility of being > better. simply reflect on that. > h.h. the 14th dalai lama
On Thu, May 1, 2008 at 8:31 PM, Ruby Talk <rubyt...@postful-inc.com> 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.
> Ara - could you shed some light on how continuations would help here? > I don't see it myself.
ingore me, i'm insane. i was thinking of evil.rb.
a @ http://codeforpeople.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama
> Well, let's say that that something is a new class I want to define > within that scope. And I'd like the innards of that class to be able to > take advantage of the the natural, idiomatic lookup rules, where the > interpreter traipses up the ancestor chain.
> To be more clear, let's say I have
> X = :bad > module A > X = :good > class B > #...let us say I want to execute something here where X == :good > end > end
> And I'd like to execute something from outside that lexical scope (let's > say from my metaprogramming classes) within that [A, A::B] lexical scope.
> I guess what I'm asking is: is there any way of faking lexical scope > (for the purposes of metaprogramming)?
For constant lookup there is:
robert@fussel /cygdrive/c/Temp $ ruby lex.rb 2
robert@fussel /cygdrive/c/Temp $ ruby lex.rb 2 2
robert@fussel /cygdrive/c/Temp $ cat lex.rb
class Module def lex_lookup(c) name.split('::').inject([TOPLEVEL_BINDING,[]]) do |(b,o),n| b = (b.const_get n rescue eval(n,b)) [b, o << b] end.last.reverse.each do |cl| return cl.const_get(c) if cl.const_defined? c end raise NameError, c end end
X=1 class Foo X=2 class Bar puts lex_lookup("X") end puts lex_lookup("X") end
robert@fussel /cygdrive/c/Temp $
You can easily extend that to include top level constants as well as other evaluations.