Requiring a file into a different namespace

[“a”,“b”].each do |name|
sandbox = Module.new { require “#{name}.rb” }

survey = sandbox::Survey.new

puts survey.name

end

This is what I’d like to do, but ‘name’ is out of scope and when I
hardcode it, it seems like require is pulling class Survey from the file
into the global namespace rather than the anonymous module’s namespace.
It’s weird.

Anyone have a solution for requiring a file into a different namespace?

On Jun 7, 2006, at 5:19 PM, Michael J. wrote:

hardcode it, it seems like require is pulling class Survey from the

Search the mailing list archives, this was discussed very recently.

Use #load. Not tested but it will be something like:

[“a”,“b”].each do |name|
sandbox = Module.new { load “#{name}.rb” }

survey = sandbox::Survey.new

puts survey.name

end

Jacob F. wrote:

Unfortunately, this won’t work. You can’t even do this directly:

Ah crud. I actually meant:

module_eval File.read("#{name}.rb")

(I’ve made that booboo twice now!) Sorry about that.

T.

Michael J. wrote:

hardcode it, it seems like require is pulling class Survey from the file
into the global namespace rather than the anonymous module’s namespace.
It’s weird.

It’s not weird. Require (or load) is going to load the script normally
and return true or false; that line is (except for order of execution)
the same as this:

x = require “#{name}.rb”
sandbox = Module.new { x }

If what you want is for the script’s code to be evaluated in the
context of the module, you need to use module_eval, as seen in the
latest ruby-dev summary:

sandbox = Module.new
sandbox.module_eval File.read("#{name}.rb")

Cheers,
Dave

On 6/7/06, [email protected] [email protected] wrote:

Use #load. Not tested but it will be something like:

[“a”,“b”].each do |name|
sandbox = Module.new { load “#{name}.rb” }

survey = sandbox::Survey.new

puts survey.name

end

Unfortunately, this won’t work. You can’t even do this directly:

$ cat a.rb
sandbox = Module.new{ module Survey; end }
p sandbox::Survey rescue puts “sandbox has no Survey”
p Survey rescue puts “there is no top level Survey”

$ ruby a.rb
sandbox has no Survey
Survey

So, you can see, the Survey module is defined at the top level, rather
than inside the anonymous sandbox. The same thing happens for
module_eval, instance_eval and class_eval in block form. However, in
string form, module_eval does the trick:

$ cat b.rb
sandbox = Module.new
sandbox.module_eval “module Survey; end”
p sandbox::Survey rescue puts “sandbox has no Survey”
p Survey rescue puts “there is no top level Survey”

$ ruby b.rb
#Module:0x402a3cc0::Survey
there is no top level Survey

This is simply enough extended for getting the string to be eval’d via
File.read:

$ cat source.rb
module Survey; end

$ cat target.rb
sandbox = Module.new
sandbox.module_eval File.read(“source.rb”)
p sandbox::Survey rescue puts “sandbox has no Survey”
p Survey rescue puts “there is no top level Survey”

$ ruby target.rb
#Module:0x402a3bf8::Survey
there is no top level Survey

What I really want to know is this: Kernel#load allows a parameter
that wraps the loaded file in an anonymous module, so as not to
pollute the global namespace. But that anonymous module is discarded
– as far as I can tell, the only use for this style of load is if the
only portion of the file you’re interested in is the side effects.

I suggest one of two changes.

  1. Change Kernel#load to return the anonymous module when the wrap
    parameter is true. Currently, the return value of Kernel#load is
    always true (failure results in an exception), so there should be no
    code relying on the current return value.

  2. Since the wrap parameter can only be true or false right now,
    change that parameter to accept a module. The behavior when that
    parameter is false/nil/true is unchanged for backwards compatibility,
    but if the parameter is a module, load the file into that module
    instead of into a new anonymous module.

How do these ideas sound to people?

Jacob F.

Jacob F. wrote:

How do these ideas sound to people?

Sounds good. Although I think the most recent develpoment “trial” is
#require_into.

T.

Jacob F. wrote:

always true (failure results in an exception), so there should be no
code relying on the current return value.

Until then, http://raa.ruby-lang.org/project/script may be useful.