Eval versus load and plugins


#1

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?


#2

Rover R. wrote:

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


#3

Rover R. wrote:

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


#4

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.

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.


Giles B.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org