From: Walton Hoops Date: 2009-12-02T02:38:35+09:00 Subject: Re: Ruby should support consistent constant lookup (and dynamic) > -----Original Message----- > From: alexandre_mutel@yahoo.fr [mailto:alexandre_mutel@yahoo.fr] > Just a general remark about this problem. Shouldn't Ruby have a builtin > mechanism to resolve dynamically and efficiently constants handling > lexical scopes correctly? > > Seems that in 1.9, we have this features: > irb(main):001:0> class A > irb(main):002:1> BAR = 1 > irb(main):003:1> class B > irb(main):004:2> def self.foo(&b) > irb(main):005:3> instance_eval(&b) > irb(main):006:3> end > irb(main):007:2> end > irb(main):008:1> end > => nil > irb(main):009:0> A::B.foo do > irb(main):010:1* puts BAR > irb(main):011:1> end > 1 > => nil > irb(main):012:0> > > BUT now, try to do it with const_get, and we got a NameError: > irb(main):012:0> A::B.foo do > irb(main):013:1* puts const_get(:BAR) > irb(main):014:1> end > NameError: uninitialized constant A::B::BAR > from (irb):13:in `const_get' > from (irb):13:in `block in irb_binding' > from (irb):5:in `instance_eval' > from (irb):5:in `foo' > from (irb):12 > from E:/Code/Ruby/bin/irb:12:in `
' > > This is quite frustrating when writing a DSL language to not being able > to resolve constants dynamically (without getting a costly module > hierarchy and checking the constant in each module...) irb(main):001:0> class A irb(main):002:1> BAR=1 irb(main):003:1> class B irb(main):004:2> def self.foo(&b) irb(main):005:3> instance_eval(&b) irb(main):006:3> end irb(main):007:2> end irb(main):008:1> end => nil irb(main):012:0> A::B.foo do irb(main):013:1* puts eval('BAR') irb(main):014:1> end 1 => nil Done. A more experienced Rubist may be able to do it without eval, but that works. > Should'nt this constant lookup be consistent between static and > const_get? No, that's not what const_get is for. It's operating on a class not a scope. That's why it's an instance method. The way you calling it is literally equivalent too: A::B.const_get(:BAR) In other words, you are asking for _B's_ constants. Since B, nor any of its ancestors have the constant BAR, an error occurs. Maybe this demonstrates more clearly what I mean: irb(main):001:0> class A irb(main):002:1> BAR=1 irb(main):003:1> def self.BAR irb(main):004:2> BAR irb(main):005:2> end irb(main):006:1> class B irb(main):007:2> end irb(main):008:1> end => nil irb(main):009:0> A.BAR => 1 irb(main):011:0> A::B.BAR NoMethodError: undefined method `BAR' for A::B:Class from (irb):11 from C:/Ruby19/bin/irb:12:in `
' irb(main):012:0> A.const_get :BAR => 1 irb(main):013:0> A::B.const_get :BAR NameError: uninitialized constant A::B::BAR from (irb):13:in `const_get' from (irb):13 from C:/Ruby19/bin/irb:12:in `
' irb(main):014:0> Notice, const_get works the same as the accessor method for BAR.