Loading a file without cluttering the global namespace

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

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

···

On 7/2/05, Benjamin Hepp <benjamin-hepp@t-online.de> wrote:

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

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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) }
        }

  ...

Benjamin Hepp wrote:

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/

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

···

On Sat, 2 Jul 2005, Benjamin Hepp wrote:

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

--

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

===============================================================================

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

···

Benjamin Hepp <benjamin-hepp@t-online.de> wrote:

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

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

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

···

On Sat, 02 Jul 2005 19:30:25 +0900, Austin Ziegler wrote:

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

···

On Sat, 02 Jul 2005 20:32:15 +0900, Andrew Walrond wrote:

This is what I do in Heretix:

...

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

WRT below, see above. Caffeine topup required, perhaps?

:wink:

···

On Sunday 03 July 2005 13:45, Robert Klemme wrote:

Benjamin Hepp <benjamin-hepp@t-online.de> wrote:

I wonder why noone mentioned Kernel#load so far:
module Kernel - RDoc Documentation

Did I overlook something?

Kind regards

    robert

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.

WRT below, see above. Caffeine topup required, perhaps?

:wink:

Darn! I knew it had to be something trivial... :slight_smile:

    robert

···

Andrew Walrond <andrew@walrond.org> wrote:

On Sunday 03 July 2005 13:45, Robert Klemme wrote:

Benjamin Hepp <benjamin-hepp@t-online.de> wrote:

I wonder why noone mentioned Kernel#load so far:
module Kernel - RDoc Documentation

Did I overlook something?

Kind regards

    robert