eval versus load and plugins

R

Rover Rhubarb

I'm writing a program with a sort of plugin mechanism. Plugins are
basically single ruby files defining classes. It's not exactly a plugin
mechanism because there an only be one plugin used.

Image the program command being
ruby myApp -plugin plugins/myPlugin.rb


I want to load the plugin which defines its own class (which follows a
certain pattern - since there are no interfaces) then instantiates it.

At the moment I'm using load to load the plugin file. I don't know the
name of the class of the specific plugin, but I assume it has a _global_
method called "new_plugin" which instantiates it.

Since I'm using load I can be sure that the latest plugin loaded will
redefine that global method to instantiate the plugin (I can't call it's
constructor directly because, again, I don't know what name the designer
is going to give the plugin class - though I can expect them to follow
the pattern of defining new_plugin)

Questions:

1. I notice that rails uses eval to load the init.rb files of plugins.
What are the advantages disadvantages of this versus using load?
(Note also this thread about using eval or load - both are suggested but
I dont see why we would use eval over load
http://www.ruby-forum.com/topic/55540#new)

2. Is there some nicer, cleaner way of doing what I'm doing without
having the plugin file define a global method?

3. Is there a neat way of forcing the plugin to match a certain pattern.
I've seen the "interface" support library, but it seems to be
shoehorning Ruby into a Java paradigm. What would be the rubyful way?
Just calling respond_to? on all of the methods I expect and raising
errors?
 
A

Alex Young

Rover said:
I'm writing a program with a sort of plugin mechanism. Plugins are
basically single ruby files defining classes. It's not exactly a plugin
mechanism because there an only be one plugin used.

Image the program command being
ruby myApp -plugin plugins/myPlugin.rb


I want to load the plugin which defines its own class (which follows a
certain pattern - since there are no interfaces) then instantiates it.

At the moment I'm using load to load the plugin file. I don't know the
name of the class of the specific plugin, but I assume it has a _global_
method called "new_plugin" which instantiates it.

Since I'm using load I can be sure that the latest plugin loaded will
redefine that global method to instantiate the plugin (I can't call it's
constructor directly because, again, I don't know what name the designer
is going to give the plugin class - though I can expect them to follow
the pattern of defining new_plugin)

Questions:

1. I notice that rails uses eval to load the init.rb files of plugins.
What are the advantages disadvantages of this versus using load?
(Note also this thread about using eval or load - both are suggested but
I dont see why we would use eval over load
http://www.ruby-forum.com/topic/55540#new)
Not sure off the top of my head. Someone else can probably weigh in here.
2. Is there some nicer, cleaner way of doing what I'm doing without
having the plugin file define a global method?
Make them subclass a base class that you provide, or make them mix in a
module that you specify. That gives you the Class#inherited and
Module#included callbacks to play with, which strikes me as cleaner than
relying on a method override.
3. Is there a neat way of forcing the plugin to match a certain pattern.
I've seen the "interface" support library, but it seems to be
shoehorning Ruby into a Java paradigm. What would be the rubyful way?
Just calling respond_to? on all of the methods I expect and raising
errors?
If the plugin subclasses a base class you specify, you can either check
it manually in the callback (which seems a little clumsy to me), or
provide all the interface members with:

def interface_member
raise NotImplementedError
end

in the base class. The former is probably necessary if you need to
sanity check the class before doing anything with it - you can get away
with the latter otherwise.

HTH
 
J

Joel VanderWerf

Rover said:
2. Is there some nicer, cleaner way of doing what I'm doing without
having the plugin file define a global method?

You can module_eval the file in the context of a new (anonymous, if you
like) module. Here's one way to do that:

[~/tmp] cat main.rb
require 'script' # http://redshift.sourceforge.net/script/

plugin_module = Script.load("plugin.rb")

# either:
plugin_class = plugin_module::pluginClass
p plugin_class.new.foo

# or:
plugin_class = plugin_module.get_the_plugin_class
p plugin_class.new.foo

[~/tmp] cat plugin.rb
class PluginClass
def foo
"FOO"
end
end

def get_the_plugin_class # NOT really global -- in module scope
PluginClass
end

[~/tmp] ruby main.rb
"FOO"
"FOO"
 
G

Giles Bowkett

Questions:
Not sure off the top of my head. Someone else can probably weigh in here.

Here's the code I think you mean:

eval(IO.read(init_path), binding, init_path)

I think the reason it does this is to allow flexible bindings. I
couldn't find "binding" defined in the method anywhere. I really don't
know, so I paraphrased this part of your question and posted it on the
Rails core list.
 

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,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top