Dynamically loading and executing within a new module?

L

Lloyd Zusman

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?
 
E

ES

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 :)
Lloyd Zusman

E
 
L

Lloyd Zusman

ES said:
[ ... ]

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

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?
 
L

Lloyd Zusman

Lloyd Zusman said:
ES said:
[ ... ]

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

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?
 
C

Christoph

Lloyd said:
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
 
C

Christoph

Lloyd said:
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
 
E

ES

Lloyd Zusman said:
ES said:
[ ... ]

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

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
 
L

Lloyd Zusman

ES said:
[ ... ]

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

Lloyd Zusman

Christoph said:
Lloyd said:
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.
 
L

Lloyd Zusman

Christoph said:
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.
 

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,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top