Forum: Ruby eval versus load and plugins

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
61396c69040bbc56dbad1c5c71ac27d2?d=identicon&s=25 Rover Rhubarb (rhubarb)
on 2007-07-27 13:25
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?
Ad7805c9fcc1f13efc6ed11251a6c4d2?d=identicon&s=25 Alex Young (regularfry)
on 2007-07-27 13:47
(Received via mailing list)
Rover Rhubarb 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.

> 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
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2007-07-27 19:11
(Received via mailing list)
Rover Rhubarb wrote:
> 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"
Ce8b03e5750097942c58e12b46724312?d=identicon&s=25 Giles Bowkett (Guest)
on 2007-07-27 21:32
(Received via mailing list)
> > 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 Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
This topic is locked and can not be replied to.