Loading a file without cluttering the global namespace

B

Benjamin Hepp

Hello,

I'm trying to build a module-mechanism in ruby so that I am able to load a
ruby-file without cluttering up the global namespace of the program.

For example I want to be able to load a ruby-file, search for methods in
it, possibly execute one of them and then "unload" the file. When I call
Kernel#load with wrap = true, everything of the new file is put into an
anonymous Module, but every other file loaded in the new file itself is
put into the global namespace again.

My questions:

Is it at all possible to prevent this? If so, how to do it?
Can I access the anonymous Module in an easy manner?
How to delete/undefine a class or a method?

Thanks in advance
Benjamin Hepp
 
A

Austin Ziegler

Is it at all possible to prevent this? If so, how to do it?

Not cleanly. There's a few examples of wrapped loads that allow you to
load into a random namespace; I've done one myself as a theoretical
example.

Ultimately, though, this isn't the way that Ruby was meant to be used.

What problem are you trying to solve? There might be another way.

-austin
--=20
Austin Ziegler * (e-mail address removed)
* Alternate: (e-mail address removed)
 
B

Benjamin Hepp

Not cleanly. There's a few examples of wrapped loads that allow you to
load into a random namespace; I've done one myself as a theoretical
example.

Where can I find those examples? I don't know what to search for.

What problem are you trying to solve? There might be another way.

Well I want to write a FastCGI-Server in ruby. Depending on the queried
website it should load the specific ruby-file based on some pattern.

When I now have a file using GD for example, the loaded GD.so would hang
around all the time. If I changed the file so that it wouldn't use GD
anymore I would have to restart the server so that GD.so doesn't lie
around in the memory forever (until the next reboot at least).

Starting a new ruby-interpreter for every file isn't an option because it
would take to long.

Writing the FastCGI-Server in C isn't an option as well because when I
initialize the ruby-interpreter (ruby_init()) a second time, all loaded
files are still available to the interpreter. Otherwise I could have
reinitialized the interpreter every few hours or so.

Benjamin Hepp
 
A

Andrew Walrond

This is what I do in Heretix:

#
# Packages is a container class for all package classes.
# it is used to prevent the Package class names from polluting the global namespace
#
module Packages
# Some package files need to 'require' other package files. The inline function
# ensures that the inclusion occurs within the Packages module as load() and require()
# both pollute the global namespace. If package files need to include other package
# files (eg perl module needs perl.rb) they must use inline() rather than require()
# or load(), which are removed to prevent their use (in the Package.load() function).
#
def Packages.inline(filename)
Packages.module_eval(IO.read(filename),filename)
end
end

def Package.load()

# Load the package classes into the Packages namespace. load() and require()
# both pollute the global namespace, so use some trickery instead. If package
# files need to include other package files (eg perl module needs perl.rb)
# they must use inline() rather than require() or load(), which are removed
# so that relevant warnings are produced when package developers forget...
#
Kernel#remove_method :require
Kernel#remove_method :load
HERETIXDIR.cd {
Dir.glob('core/packages/*.rb').each { |fn| Packages.inline(fn) }
Dir.glob('contrib/packages/*.rb').each { |fn| Packages.inline(fn) }
}

...
 
B

Benjamin Hepp

This is what I do in Heretix:

...

Thanks so far.
By overwriting Kernel#load and Kernel#require I could live with this
method. The only problem I still have is how to load a .so file this way.
I need something like module_eval(IO.read(filename)) for .so files. I
guess this is impossible, right?

Benjamin Hepp
 
J

Joel VanderWerf

Benjamin said:
Hello,

I'm trying to build a module-mechanism in ruby so that I am able to load a
ruby-file without cluttering up the global namespace of the program.

For example I want to be able to load a ruby-file, search for methods in
it, possibly execute one of them and then "unload" the file. When I call
Kernel#load with wrap = true, everything of the new file is put into an
anonymous Module, but every other file loaded in the new file itself is
put into the global namespace again.

My questions:

Is it at all possible to prevent this? If so, how to do it?
Can I access the anonymous Module in an easy manner?
How to delete/undefine a class or a method?

A partial answer is the script library:

http://raa.ruby-lang.org/project/script

It cannot unload a library, and it cannot change what namespace .so
extensions put their definitions in, but:

* It wraps a loaded file (and its "local dependencies") in an instance
of the Script class, which is a subclass of Module.

* You can then assign this Script instance to a local var, constant, or
whatever:

script = Script.load("my-script.rb")

* Top level method defs and constant defs in the wrapped file(s) can be
accessed as methods or constants of this instance:

script.foo()
script::Foo

* The "local dependencies" are defined to be any .rb files that can be
found relative to the dir of the main script. This is handled by
redefining #load and #require in the context of the Script instance. If
the specified path is not found locally (or is a .so), then it falls
back to Kernel#require.

* There's also an autoloading feature.

And there's another library to do this kind of thing:

http://codeforpeople.com/lib/ruby/dynaload/
 
A

Ara.T.Howard

Hello,

I'm trying to build a module-mechanism in ruby so that I am able to load a
ruby-file without cluttering up the global namespace of the program.

For example I want to be able to load a ruby-file, search for methods in
it, possibly execute one of them and then "unload" the file. When I call
Kernel#load with wrap = true, everything of the new file is put into an
anonymous Module, but every other file loaded in the new file itself is
put into the global namespace again.

My questions:

Is it at all possible to prevent this? If so, how to do it?
Can I access the anonymous Module in an easy manner?
How to delete/undefine a class or a method?

Thanks in advance
Benjamin Hepp

i use a similar pattern for loading 'subscriptions' in our near-realtime
system. a subscription is a dynamically loaded class for which and instance
is created and then it's run method is called. to support doing this without
killing the global namespace i write this

http://raa.ruby-lang.org/project/dynaload/

it should be just what you are looking for.

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
 
R

Robert Klemme

Benjamin Hepp said:
Hello,

I'm trying to build a module-mechanism in ruby so that I am able to
load a ruby-file without cluttering up the global namespace of the
program.

For example I want to be able to load a ruby-file, search for methods
in it, possibly execute one of them and then "unload" the file. When
I call Kernel#load with wrap = true, everything of the new file is
put into an anonymous Module, but every other file loaded in the new
file itself is put into the global namespace again.

My questions:

Is it at all possible to prevent this? If so, how to do it?
Can I access the anonymous Module in an easy manner?
How to delete/undefine a class or a method?

Thanks in advance
Benjamin Hepp

I wonder why noone mentioned Kernel#load so far:
http://www.ruby-doc.org/core/classes/Kernel.html#M001744

Did I overlook something?

Kind regards

robert
 
B

Benjamin Hepp

Hello,

Thanks to all the replies.

I will have to live with .so-files polluting my global namespace but the
problem with .rb files is solved now by overwriting load and require.

Greetings
Benjamin Hepp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top