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?

···

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

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

···

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

  ["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?

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

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

Michael Judge wrote:

  ["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.

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

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 Fugal

···

On 6/7/06, transfire@gmail.com <transfire@gmail.com> 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

Jacob Fugal wrote:

···

On 6/7/06, transfire@gmail.com <transfire@gmail.com> 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:

Ah crud. I actually meant:

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

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

T.

Jacob Fugal wrote:

  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?

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

T.

Jacob Fugal wrote:
...

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.

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

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407