Loading a module without polluting my namespace

Hey folks!

In my current project I try to load a module dynamically. Which is
basically no problem due to 'require` accepting filenames as well. My
problem is that I’d totally pollute my namespace. I thought of something
like the following:

def load_module(filename)
module NamespaceGuard # Just a random name
require filename
# Take a care of the loaded module
end

My namespace is clean again

end

But Ruby’s syntax apparently forbids module definitions in methods. I’d
be very glad if anyone could help me with this problem.

Hagbard C. wrote:

In my current project I try to load a module dynamically. Which is
basically no problem due to 'require` accepting filenames as well. My
problem is that I’d totally pollute my namespace.

Kernel.load(filename, true) might help. But AFAIK that doesn’t prevent
the source code from doing

class ::Object
def override_something_important

end
end

If you need to protect against untrusted code, have a look at _why’s
sandbox.

Thanks for your reply but I’m afraid that doesn’t solve my problem. I
stumbled upon the optional argument of `load’ as well but it prevents me
from accessing the loaded module. I’m sorry if I wasn’t clear enough. I
would need something like this:

foo.rb

module Foo
def method_a
end

def method_b
end
end

bar.rb

def load_module
load “foo.rb”
puts Foo.methods
end

`Foo’ isn’t known anymore

If I use `load “foo.rb”, true’ I can’t access the loaded module or am I
mistaken?

Security is a minor problem for the moment as it’s just a hobby project.
But I take a look at _why’s sandbox anyway. Thanks for the hint.

Brian C. wrote:

I wish ‘load’ would simply return the anonymous module it has created,
but there are nasty workarounds.

Exactly this behavior I would have loved and needed. What a bummer that
there are just workarounds which are indeed nasty. I guess I have to
live with it. Thanks for your help.

Hagbard C. wrote:

Thanks for your reply but I’m afraid that doesn’t solve my problem. I
stumbled upon the optional argument of `load’ as well but it prevents me
from accessing the loaded module.

I wish ‘load’ would simply return the anonymous module it has created,
but there are nasty workarounds. For example:

$ cat foo.rb
module Foo
def bar
puts “hello”
end
module_function :bar
end
$res = Foo

$ irb --simple-prompt

load “foo.rb”, true
=> true

$res
=> #Module:0xb741b218::Foo

$res.bar
hello
=> nil

Hagbard C. wrote:

def method_b
end
end

bar.rb

def load_module
load “foo.rb”
puts Foo.methods
end

`Foo’ isn’t known anymore

Your example is not quite right.

$ cat foo.rb
module Foo
def method_a
end

def method_b
end
end

$ cat bar.rb
def load_module
load “foo.rb”
puts Foo.instance_methods
end

load_module

$ ruby bar.rb
method_a
method_b

Kernel#require does not namespace anything, no matter how you use it.

Properly written Rubby libraries namespace their classes and modules.
If you own the code you’re requiring, fix it. If not, find an
alternative to the code in question (which I find suspect based on this
lack of namespacing) or perhaps you may find some luck with Kernel#load.

On Jun 13, 2:33 pm, Hagbard C. [email protected] wrote:

# Take a care of the loaded module

end

My namespace is clean again

end

But Ruby’s syntax apparently forbids module definitions in methods. I’d
be very glad if anyone could help me with this problem.

Usually the file you are loading has the “protective” namespace. Eg.

namespace_guard.rb

module NamespaceGuard

end

main.rb

require ‘namespace_guard’

Hagbard C. wrote:

Thanks for your reply but I’m afraid that doesn’t solve my problem. I
stumbled upon the optional argument of load' as well but it prevents me from accessing the loaded module. I'm sorry if I wasn't clear enough. I would need something like this: ... If I useload “foo.rb”, true’ I can’t access the loaded module or am I
mistaken?

That’s correct (you can’t access it without playing tricks like global
vars or searching ObjectSpace).

If security is not your concern, take a look at the script lib I
mentioned before:

http://redshift.sourceforge.net/script

Unlike load(…, true) , Script.load returns the wrapper module.

Hagbard C. wrote:

# Take a care of the loaded module

end

My namespace is clean again

end

But Ruby’s syntax apparently forbids module definitions in methods. I’d
be very glad if anyone could help me with this problem.

You certainly can define modules dynamically:

def make_mod
Module.new do
def self.foo; p “FOO”; end
def bar; p “BAR”; end
end
end

m = make_mod

p m.methods(false) # ==> [“foo”]
p m.instance_methods(false) # ==> [“bar”]

m.foo # ==> “FOO”
x=[]
x.extend m
x.bar # ==> “BAR”

Also, the #load method takes an optional argument that causes it to
wrap the loaded definitions in

$ ri Kernel#load | cat
------------------------------------------------------------ Kernel#load
load(filename, wrap=false) => true

  Loads and executes the Ruby program in the file filename. If the
  filename does not resolve to an absolute path, the file is
  searched for in the library directories listed in $:. If the
  optional wrap parameter is true, the loaded script will be
  executed under an anonymous module, protecting the calling
  program's global namespace. In no circumstance will any local
  variables in the loaded file be propagated to the loading
  environment.

You can use this like so:

$ cat b.rb
def foo
puts “foo in b”
end

$ cat a.rb
load “b.rb”, true # try this without the true

begin
foo
rescue => e
puts e
end

def foo
puts “foo in a”
end

foo

$ ruby a.rb
undefined local variable or method `foo’ for main:Object
foo in a

However, you don’t get easy access to the anonymous module. If you want
that, I have a little library that may be helpful:

http://redshift.sourceforge.net/script/

Rein H. wrote:

Properly written Rubby libraries namespace their classes and modules.
If you own the code you’re requiring, fix it. If not, find an
alternative to the code in question (which I find suspect based on this
lack of namespacing) or perhaps you may find some luck with Kernel#load.

I happen to be in control of the loaded modules but I think you didn’t
understand my problem correctly. If I use namespace guards (what I
actually do at the moment) the loaded modules remain in existence and
pollute my namespace. So, namespace guards don’t really help me.

@Joel:
The `Script’ library seems to fit my needs quite perfectly. Thank you
for the hint.

On 2010-06-13 18:35:25 -0700, Rein H. said:

Kernel#require does not namespace anything, no matter how you use it.

Properly written Rubby libraries namespace their classes and modules.
If you own the code you’re requiring, fix it. If not, find an
alternative to the code in question (which I find suspect based on this
lack of namespacing) or perhaps you may find some luck with Kernel#load.

Also, properly written, it’s “Ruby”. Oops.

Joel VanderWerf wrote:

However, you don’t get easy access to the anonymous module. If you want
that, I have a little library that may be helpful:

http://redshift.sourceforge.net/script/

This is great, but seems to blows up when requiring other files

http://github.com/dreamcat4/plist4r/blob/master/lib/plist4r/backend/c_f_property_list.rb#L8

http://gist.github.com/471434

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

Best regards

dreamcat4
[email protected]

Thanks for replying,
Will try to come back soon with an example for reproducing this.

Joel VanderWerf wrote:

Dreamcat F. wrote:

http://gist.github.com/471434
Is it possible to simplify the example a bit? I can’t tell where the
missing const is actually defined.

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

There’s an example of using require with script in examples/program2.rb.
Maybe that helps?

Sorry not to be more helpful…

Joel VanderWerf wrote:

Dreamcat F. wrote:

http://gist.github.com/471434
Is it possible to simplify the example a bit? I can’t tell where the

Here is the example2.rb, but modified to reproduce this scenario.

http://github.com/dreamcat4/script/commit/0a89728d

When we run the same ruby code directly (example2-no-wrapper.rb), there
is no error. So the script wrapper is doing something differently than
ruby would normally.

My question:
Can find a way to get around this without touching the loaded source
code?

missing const is actually defined.

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

There’s an example of using require with script in examples/program2.rb.
Maybe that helps?

Sorry not to be more helpful…

Dreamcat F. wrote:

http://gist.github.com/471434
Is it possible to simplify the example a bit? I can’t tell where the
missing const is actually defined.

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

There’s an example of using require with script in examples/program2.rb.
Maybe that helps?

Sorry not to be more helpful…

Here is a fix to the require() and load() methods. Its easier to patch
it there and just not to assume those methods are being given relative
paths.

http://github.com/dreamcat4/script/commit/e7d585b5

Joel VanderWerf wrote:

On Sun, Jul 11, 2010 at 3:07 AM, Dreamcat F. [email protected]
wrote:

http://gist.github.com/471434

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

Yes. The problem is in the way your script references the other files.
You’ve got absolute paths (which makes sense in the no-wrapper case),
but the Script class is expecting relative. The problem goes away
(AFAICT) with this patch:

— /home/vjoel/tmp/dc2/examples/scripts/script.rb 2010-07-13
17:13:47.673562875 -0700
+++ - 2010-07-13 17:15:18.375246675 -0700
@@ -1,6 +1,6 @@
puts “in #{FILE}, line #{LINE}”

-load File.dirname(FILE)+"/sub-script.rb"
+load “sub-script.rb”

OUTPUT = [“input was #{INPUT}”]

@@ -9,10 +9,10 @@
end
end

-require File.dirname(FILE)+’/lib/a-class’
+require ‘lib/a-class’

-require File.dirname(FILE)+’/lib/x-accessor’
-require File.dirname(FILE)+’/lib/x-accessor’ # only loaded once
+require ‘lib/x-accessor’
+require ‘lib/x-accessor’ # only loaded once

Falls back to Kernel.load, since “benchmark.rb” isn’t in the current

dir.
load “benchmark.rb” unless $LOADED_FEATURES.include?(“benchmark.rb”)

Dreamcat F. wrote:

Here is a fix to the require() and load() methods. Its easier to patch
it there and just not to assume those methods are being given relative
paths.

http://github.com/dreamcat4/script/commit/e7d585b5

— a/lib/script.rb
+++ b/lib/script.rb
@@ -52,7 +52,11 @@ class Script < Module

from those sub files.

def load(file, wrap = false)

  • load_in_module(File.join(@__dir, file))
  • if file =~ /^//
  •  load_in_module(file)
    
  • else
  •  load_in_module(File.join(@__dir, file))
    
  • end
    true
    rescue MissingFile
    super
    @@ -70,7 +74,11 @@ class Script < Module
    def require(feature)
    unless @__loaded_features[feature]
    @__loaded_features[feature] = true
  •  file = File.join(@__dir, feature)
    
  •  if feature =~ /^\//
    
  •    file = feature
    
  •  else
    
  •    file = File.join(@__dir, feature)
    
  •  end
     file += ".rb" unless /\.rb$/ =~ file
     load_in_module(file)
    
    end

    1.6.6.1

Joel VanderWerf wrote:

On Sun, Jul 11, 2010 at 3:07 AM, Dreamcat F. [email protected]
wrote:

http://gist.github.com/471434

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

Yes. The problem is in the way your script references the other files.
You’ve got absolute paths (which makes sense in the no-wrapper case),
but the Script class is expecting relative. The problem goes away
(AFAICT) with this patch:

— /home/vjoel/tmp/dc2/examples/scripts/script.rb 2010-07-13
17:13:47.673562875 -0700
+++ - 2010-07-13 17:15:18.375246675 -0700
@@ -1,6 +1,6 @@
puts “in #{FILE}, line #{LINE}”

-load File.dirname(FILE)+"/sub-script.rb"
+load “sub-script.rb”

OUTPUT = [“input was #{INPUT}”]

@@ -9,10 +9,10 @@
end
end

-require File.dirname(FILE)+’/lib/a-class’
+require ‘lib/a-class’

-require File.dirname(FILE)+’/lib/x-accessor’
-require File.dirname(FILE)+’/lib/x-accessor’ # only loaded once
+require ‘lib/x-accessor’
+require ‘lib/x-accessor’ # only loaded once

Falls back to Kernel.load, since “benchmark.rb” isn’t in the current

dir.
load “benchmark.rb” unless $LOADED_FEATURES.include?(“benchmark.rb”)

Dreamcat F. wrote:

Here is a fix to the require() and load() methods. Its easier to patch
it there and just not to assume those methods are being given relative
paths.

Sure, that makes sense. I’ll merge that in the next release. Thanks!

On Sun, Jul 11, 2010 at 3:07 AM, Dreamcat F. [email protected]
wrote:

http://gist.github.com/471434

I noticed that there is a redefinition of require in script.rb. Is that
method meant to be handling that?

http://redshift.sourceforge.net/script/doc/classes/Script.html#M000003

Yes. The problem is in the way your script references the other files.
You’ve got absolute paths (which makes sense in the no-wrapper case),
but the Script class is expecting relative. The problem goes away
(AFAICT) with this patch:

— /home/vjoel/tmp/dc2/examples/scripts/script.rb 2010-07-13
17:13:47.673562875 -0700
+++ - 2010-07-13 17:15:18.375246675 -0700
@@ -1,6 +1,6 @@
puts “in #{FILE}, line #{LINE}”

-load File.dirname(FILE)+"/sub-script.rb"
+load “sub-script.rb”

OUTPUT = [“input was #{INPUT}”]

@@ -9,10 +9,10 @@
end
end

-require File.dirname(FILE)+’/lib/a-class’
+require ‘lib/a-class’

-require File.dirname(FILE)+’/lib/x-accessor’
-require File.dirname(FILE)+’/lib/x-accessor’ # only loaded once
+require ‘lib/x-accessor’
+require ‘lib/x-accessor’ # only loaded once

Falls back to Kernel.load, since “benchmark.rb” isn’t in the current

dir.
load “benchmark.rb” unless $LOADED_FEATURES.include?(“benchmark.rb”)

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs