Dynamically loading and executing within a new module?

I'm not sure what would be the best way to accomplish the following in
ruby:

I'm writing a program that periodically looks for files in a certain
directory. If it finds new ones, I want it to ...

1. Dynamically create a new module whose name is based somehow upon the
   name of the file.

2. Do a Kernel#load on the file within this newly created module.

3. Invoke a method called #init that is defined in this file (assuming
   that this method is actually defined), and do the invocation within
   the context of that newly-created module.

For example, suppose my directory contains the following files:

  foo.module

···

----------
  def init
    puts "invoking #init within #{self}"
  end

  bar.module
  ----------
  def init
    puts "invoking #init within #{self}"
  end

When my program encounters the "foo.module" file, I'd like it to do the
following:

  - create a module called Foo (the name of the file with ".module"
    stripped off and the first letter capitalized) ... or maybe
    SomethingElse::Foo, to avoid collisions with existing packages

  - do a load() of the "foo.module" file within the context of this
    newly created Foo module (or SomethingElse::Foo module)

  - check to see if the #init method is now defined within the
    Foo module; if so, invoke that as a class method within the
    context of that module (i.e., as if it were invoked like
    Foo#init); this should cause the following message to
    print:

      invoking #init within Foo

What is the recommended way for accomplishing all this within Ruby?

--
Lloyd Zusman
ljz@asfast.com
God bless you.

I'm not sure what would be the best way to accomplish the following in
ruby:

I'm writing a program that periodically looks for files in a certain
directory. If it finds new ones, I want it to ...

1. Dynamically create a new module whose name is based somehow upon the
  name of the file.

2. Do a Kernel#load on the file within this newly created module.

3. Invoke a method called #init that is defined in this file (assuming
  that this method is actually defined), and do the invocation within
  the context of that newly-created module.

For example, suppose my directory contains the following files:

foo.module
----------
def init
   puts "invoking #init within #{self}"
end

bar.module
----------
def init
   puts "invoking #init within #{self}"
end

When my program encounters the "foo.module" file, I'd like it to do the
following:

- create a module called Foo (the name of the file with ".module"
   stripped off and the first letter capitalized) ... or maybe
   SomethingElse::Foo, to avoid collisions with existing packages

- do a load() of the "foo.module" file within the context of this
   newly created Foo module (or SomethingElse::Foo module)

- check to see if the #init method is now defined within the
   Foo module; if so, invoke that as a class method within the
   context of that module (i.e., as if it were invoked like
   Foo#init); this should cause the following message to
   print:

     invoking #init within Foo

What is the recommended way for accomplishing all this within Ruby?

If you don't just want to write an actual module and then call its #init,
you could do something like this. Somewhat pseudo:

Thread.new do
  if fname
    mod = eval fname.capitalize
    data = File.new(fname, 'r') do |f|
             f.read
           end
    mod.module_eval data
    mod.send :init, args
    # ...
  end
end

Or sumptin :slight_smile:

Lloyd Zusman

E

···

On 2/19/2005, "Lloyd Zusman" <ljz@asfast.com> wrote:

ES <ruby-ml@magical-cat.org> writes:

···

On 2/19/2005, "Lloyd Zusman" <ljz@asfast.com> wrote:

[ ... ]

When my program encounters the "foo.module" file, I'd like it to do the
following:

- create a module called Foo (the name of the file with ".module"
   stripped off and the first letter capitalized) ... or maybe
   SomethingElse::Foo, to avoid collisions with existing packages

- do a load() of the "foo.module" file within the context of this
   newly created Foo module (or SomethingElse::Foo module)

- check to see if the #init method is now defined within the
   Foo module; if so, invoke that as a class method within the
   context of that module (i.e., as if it were invoked like
   Foo#init); this should cause the following message to
   print:

     invoking #init within Foo

What is the recommended way for accomplishing all this within Ruby?

If you don't just want to write an actual module and then call its #init,
you could do something like this. Somewhat pseudo:

Thread.new do
  if fname
    mod = eval fname.capitalize
    data = File.new(fname, 'r') do |f|
             f.read
           end
    mod.module_eval data
    mod.send :init, args
    # ...
  end
end

Or sumptin :slight_smile:

Thanks. This makes sense.

However, the "eval fname.capitalize" part doesn't create a new module,
and that's part of what is confusing me about all this. Given a string
"Foo", what do I do to it in order to create a module object with that
name?

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Lloyd Zusman <ljz@asfast.com> writes:

ES <ruby-ml@magical-cat.org> writes:

[ ... ]

If you don't just want to write an actual module and then call its #init,
you could do something like this. Somewhat pseudo:

Thread.new do
  if fname
    mod = eval fname.capitalize
    data = File.new(fname, 'r') do |f|
             f.read
           end
    mod.module_eval data
    mod.send :init, args
    # ...
  end
end

Or sumptin :slight_smile:

Thanks. This makes sense.

However, the "eval fname.capitalize" part doesn't create a new module,
and that's part of what is confusing me about all this. Given a string
"Foo", what do I do to it in order to create a module object with that
name?

Actually, I now realize that I don't need a bona fide named module, but
rather, just a way to associate a name with a module. Therefore, I
think that I can do it more or less like this:

  modhash = Hash.new
  if fname then
    if modhash.has_key?(fname) then
      mod = modhash[fname]
    else
      mod = Module.new
      modhash[fname] = mod
    end
    data = File.new(fname, 'r') do |f|
             f.read
           end
    mod.module_eval data
    mod.send :init, args
  end

Does this make sense?

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Lloyd Zusman schrieb:

However, the "eval fname.capitalize" part doesn't create a new module,
and that's part of what is confusing me about all this. Given a string
"Foo", what do I do to it in order to create a module object with that
name?

use Module#new - for example

···

---
MyNameSpace.const_set fname.capitalize, Module.new
---

You can automate things

class MyModule < Module
    def initialize(fname)
        ::MyNameSpace.const_set fname.capitalize, self
        # maybe add the the MyModule method
       # using the text file ....
     end
end
/Christoph

Lloyd Zusman schrieb:

Actually, I now realize that I don't need a bona fide named module, but
rather, just a way to associate a name with a module. Therefore, I
think that I can do it more or less like this:

modhash = Hash.new
if fname then
   if modhash.has_key?(fname) then
     mod = modhash[fname]
   else
     mod = Module.new
     modhash[fname] = mod
   end
   data = File.new(fname, 'r') do |f|
            f.read
          end
   mod.module_eval data
   mod.send :init, args
end

Does this make sense?

You can also use MyNameSpace#const_get
with a rescue clause

/Christoph

Lloyd Zusman <ljz@asfast.com> writes:

ES <ruby-ml@magical-cat.org> writes:

[ ... ]

If you don't just want to write an actual module and then call its #init,
you could do something like this. Somewhat pseudo:

Thread.new do
  if fname
    mod = eval fname.capitalize
    data = File.new(fname, 'r') do |f|
             f.read
           end
    mod.module_eval data
    mod.send :init, args
    # ...
  end
end

Or sumptin :slight_smile:

Thanks. This makes sense.

However, the "eval fname.capitalize" part doesn't create a new module,
and that's part of what is confusing me about all this. Given a string
"Foo", what do I do to it in order to create a module object with that
name?

Actually, I now realize that I don't need a bona fide named module, but
rather, just a way to associate a name with a module. Therefore, I
think that I can do it more or less like this:

modhash = Hash.new
if fname then
   if modhash.has_key?(fname) then
     mod = modhash[fname]
   else
     mod = Module.new
     modhash[fname] = mod
   end
   data = File.new(fname, 'r') do |f|
            f.read
          end
   mod.module_eval data
   mod.send :init, args
end

Does this make sense?

Yes, but I'm not sure if I understand why you're doing this in the first
place. Why don't you just create a named module, store it in a file and
load
it when requested instead of just storing the code that'll go in the
module?

Lloyd Zusman

E

···

On 2/19/2005, "Lloyd Zusman" <ljz@asfast.com> wrote:

Christoph <chr_mail@gmx.net> writes:

Lloyd Zusman schrieb:

However, the "eval fname.capitalize" part doesn't create a new module,
and that's part of what is confusing me about all this. Given a string
"Foo", what do I do to it in order to create a module object with that
name?

use Module#new - for example

---
MyNameSpace.const_set fname.capitalize, Module.new
---

You can automate things

class MyModule < Module
    def initialize(fname)
        ::MyNameSpace.const_set fname.capitalize, self
        # maybe add the the MyModule method
       # using the text file ....
     end
end
/Christoph

Aha! ... that's a great idea. I love how ruby (like Smalltalk) makes
classes, objects, etc. into first-class objects.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

ES <ruby-ml@magical-cat.org> writes:

[ ... ]

Actually, I now realize that I don't need a bona fide named module, but
rather, just a way to associate a name with a module. Therefore, I
think that I can do it more or less like this:

modhash = Hash.new
if fname then
   if modhash.has_key?(fname) then
     mod = modhash[fname]
   else
     mod = Module.new
     modhash[fname] = mod
   end
   data = File.new(fname, 'r') do |f|
            f.read
          end
   mod.module_eval data
   mod.send :init, args
end

Does this make sense?

Yes, but I'm not sure if I understand why you're doing this in the
first place. Why don't you just create a named module, store it in a
file and load it when requested instead of just storing the code
that'll go in the module?

Because I want to share code (via symbolic links) and associate it with
several modules, each module being named differently, based on the file
in which it resides. Also, I may change the names of these files from
time to time, and when I do, I don't want to also have to remember to
also change the module names contained in these files.

By dynamically naming the modules in the ways we have been discussing,
this allows me to have a unique namespace for each file-based module
that I create, even if several files share the same contents via
symbolic links. And this is ensured no matter how many renames
or symbolic link changes I make.

···

On 2/19/2005, "Lloyd Zusman" <ljz@asfast.com> wrote:

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Christoph <chr_mail@gmx.net> writes:

Lloyd Zusman schrieb:

Actually, I now realize that I don't need a bona fide named module, but
rather, just a way to associate a name with a module. Therefore, I
think that I can do it more or less like this:

modhash = Hash.new
if fname then
   if modhash.has_key?(fname) then
     mod = modhash[fname]
   else
     mod = Module.new
     modhash[fname] = mod
   end
   data = File.new(fname, 'r') do |f|
            f.read
          end
   mod.module_eval data
   mod.send :init, args
end

Does this make sense?

You can also use MyNameSpace#const_get
with a rescue clause

Yes ... makes sense. Thanks.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.