On Jun 1, 2013, at 5:35 PM, jin chizhong <lists / ruby-forum.com> wrote:

> When I use a dynamic class, It can not reference constants.
> See follow code and remark.

The reason is that your two examples have different lexical scopes and =
constants are resolved lexically.

> class T
>  def hello
>    puts self.class.constants.join " "    # right, AAA
>    puts AAA                              # right, 1
>  end
> end

Here, AAA is lexically within T so ruby searches T::AAA and ::AAA before =
giving up.

> T::AAA =3D 1
> t =3D T.new
> t.hello

You can see this by doing:

class Demo; def get_T; T; end; end
T =3D 'top'
Demo.new.get_T		# 'top'
Demo::T =3D 'demo'	# now there is ::T and Demo::T
Demo.new.get_T		# 'demo', because Demo::T is searched before ::T


> c =3D Class.new do
>  def hello
>    puts self.class.constants.join " "    # right, AAA
>    puts AAA          # error: uninitialized constant AAA (NameError)
>  end
> end

Here AAA is not lexically in a class so ruby *only* searches ::AAA =
before giving up, which is what you see below when you call inst.hello


> c::AAA =3D 123
> inst =3D c.new
> inst.hello

If you continue from this point:

puts c::AAA	# 123
AAA =3D 456	# set top level AAA
puts c:AAA	# still 123
c.new.hello	# 456 because AAA in hello now finds AAA at the top =
level scope

I think the key to understanding this is to realize that constant lookup =
path is established when the code is parsed and not when the code is =
executed.

You asked if there is a way around this and there sort of is.  If you =
want to force the lookup to start in a particular module then say it =
explicitly:

c =3D Class.new do
 def hello
   puts self.class.constants.join " "    # right, AAA
   puts self.class::AAA                  # forces search to start in c
 end
end

Just to be a bit more complete, ruby also searches the superclasses of =
any class in the lexical scope:

class A
  def lookup_X
    X                  # X is resolved as A::X, ::X
  end
end

class B < A
  def lookup_X_from_B
    X                  # X is resolved as B::X, A::X, ::X
  end
end

A.new.lookup_X         # A::X, ::X
B.new.lookup_X         # still A::X, ::X even though called on instance =
of B
B.new.lookup_X_from_B  # B::X, A::X, ::X =20

Now try setting X =3D 1; A::X =3D 2, and B::X =3D 3 and see what the =
lookup methods return.


Gary Wright