Problem trying to get a constant with correct scope

I’m trying to get a constant inside a class (but i have to do it outside
the declaration)

module A
class B
end
class C
end
end

How to get constant B from inside C but executed from outside first
declaration?
After module A is declared, trying :

puts A::C.class_eval(“B”)

failed and const_get is not working too.

But if i do something like this:
module A
class B
end
class C
$test_binding = binding
end
end

puts eval(“B”,$test_binding)

it’s working… Is using the binding is the only way to get correct
scope and resolve constant correctly from inside class C?

On Nov 30, 4:15 pm, Alexandre M. [email protected] wrote:

How to get constant B from inside C but executed from outside first
declaration?
After module A is declared, trying :

puts A::C.class_eval(“B”)

failed and const_get is not working too.
Your goal is confusing. module A contains the “B” constant, not class
C. How does “A::B” not satisfy your needs? What exactly are you trying
to do?

pharrington wrote:

On Nov 30, 4:15�pm, Alexandre M. [email protected] wrote:

How to get constant B from inside C but executed from outside first
declaration?
After module A is declared, trying :

puts A::C.class_eval(“B”)

failed and const_get is not working too.
Your goal is confusing. module A contains the “B” constant, not class
C. How does “A::B” not satisfy your needs? What exactly are you trying
to do?

Sorry for the shortcut in my explanation. In fact, my test case is a bit
more dynamic. I’m developing a DSL that evaluate blocks that can contain
a line like this:
A_CONSTANT some,args,…etc.

So i’m trying to get the constant dynamically and not statically :

I have something like :
class ConstSearcher
def self.method_missing(sym,*args)
puts const_get(sym)
end
end

module A
class B
end
class C < ConstSearcher
puts B # << static constant lookup is working
end
end

But performing a dynamic lookup is not : A::C.instance_eval(“B 11111”)
:
NameError: (irb):3:in const_get': uninitialized constant A::C::B from (irb):13 from (irb):3:inmethod_missing’
from (eval):1
from :0

i tried several methods (eval with binding…etc.) without any success.
Does i have to loop through parent modules and perform a const_get on
each module ? (generating a huge performance penalty).

Currently, i’m using something like

class Module
def dyn_const_get(sym)
list = name.split(’::’).inject([Object]) {|hierarchy,name| hierarchy
<< hierarchy.last.const_get(name)}
result = nil
while !list.empty? && result.nil?
begin
lookup_in = list.pop
result = lookup_in.const_get sym
rescue
end
end
result
end
end

And performing : A::C.dyn_const_get(:B) returns
A::B

But that’s a very bad option in terms of performance… I’m wondering if
there are any other options?

On Nov 30, 2009, at 5:47 PM, Alexandre M. wrote:

   lookup_in = list.pop

But that’s a very bad option in terms of performance… I’m
wondering if
there are any other options?

Posted via http://www.ruby-forum.com/.

Would your DSL rather do something with const_missing instead of
method_missing? (see Module#const_missing) I suppose that you could
set A::C::B = A::B

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

On Nov 30, 5:47 pm, Alexandre M. [email protected] wrote:

    result = lookup_in.const_get sym

But that’s a very bad option in terms of performance… I’m wondering if
there are any other options?

Posted viahttp://www.ruby-forum.com/.

As far as I know the only way to do this is to traverse the
inheritance hierarchy :\

pharrington wrote:

On Nov 30, 5:47�pm, Alexandre M. [email protected] wrote:

� � � � result = lookup_in.const_get sym
But that’s a very bad option in terms of performance… I’m wondering if
there are any other options?

Posted viahttp://www.ruby-forum.com/.

As far as I know the only way to do this is to traverse the
inheritance hierarchy :\

Ok, so that’s a bad news…

Rob wrote:

Would your DSL rather do something with const_missing instead of
method_missing? (see Module#const_missing) I suppose that you could
set A::C::B = A::B
-Rob

Nope, because the block I’m trying to evaluate is “A_CONSTANT
some,parameters”, so i expect to parse the parameters as well for this
constant. Moreover, the const_missing doesn’t solve the issue as i still
have to lookup through parent’s modules to get the constant dynamically
as it is performed statically…

On Nov 30, 6:10 pm, Alexandre M. [email protected] wrote:

constant. Moreover, the const_missing doesn’t solve the issue as i still
have to lookup through parent’s modules to get the constant dynamically
as it is performed statically…


Posted viahttp://www.ruby-forum.com/.

If constant lookup is causing a significant impact on your project’s
performance, mayhaps a good idea would be to create a tree of commonly
used constants (whatever that means for your app) for fast lookup?

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:inblock in irb_binding’
from (irb):5:in instance_eval' from (irb):5:infoo’
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…)

Should’nt this constant lookup be consistent between static and
const_get?

irb(main):004:2> def self.foo(&b)
irb(main):012:0>
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.

Walton H. wrote:

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.

Oh, thanks, at least the eval is working on constants with 1.9, this is
good to know.

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.

I understand the current const_get behavior, but still, it would be nice
to have something equivalent to fully resolving a constant in a faster
way without going through the eval way.

I was thinking about a const_get with an aditionnal parameter like
def const_get(symbol, check_module_hierarchy=false) {}, still living
this method in the module.