Lloyd Zusman wrote:
> Suppose I have a file named 'modtest' which contains the following two
> lines:
> 
>   X = 1
>   Y = 2
> 
> Then, I execute this ruby code:
> 
>   mod = Module.new {
>     load('modtest')
>   }
>   p mod.constants
> 
> When this code runs, I see this:  []
> 
> In other words, it's an empty array, which means that I'm not seeing the
> constants X and Y.
> 
> Why is this?  Is there any way to load the file 'modtest' so that the
> resulting anonymous module indeed contains these constants?

It's not particularly loading that's causing the problem. The same 
behavior occurs in

   mod = Module.new {
     XYZ = 1
   }
   p mod.constants

We can find out where that constant goes with this bit of code:

   ObjectSpace.each_object(Module) do |obj|
     if obj.constants.include?("XYZ")
       puts "#{obj}::XYZ = #{obj::XYZ.inspect}"
     end
   end

The output:

[]
t.rb:8: warning: toplevel constant XYZ referenced by Class::XYZ
Class::XYZ = 1
t.rb:8: warning: toplevel constant XYZ referenced by Module::XYZ
Module::XYZ = 1
Object::XYZ = 1

The output says XYZ is toplevel.  The constant is added in the top level 
scope because that is the scope of the block in which the constant 
assignment happens. Here's another example:

   module Foo; end

   module Bar
     $block = proc { XYZ = 1 }
   end

   Foo.module_eval(&$block)

   p Bar::XYZ # ==> 1
   p Foo::XYZ # ==> uninitialized constant

Looks weird at first, but it's because constants are statically 
(lexically) scoped. XYZ occurs in a block whose scope is Bar, so that's 
where the constant is defined when the block is called.

You can get around this by using the string form of module_eval. A 
string is not associated with its lexical scope in the way a proc is.

   mod2 = Module.new
   mod2.module_eval "X2 = 12"
   p mod2.constants   # ==> ["X2"]

So just use #read instead of #load, and pass that string to module_eval.