GemPlugin 0.1 -- A Mongrel Spinoff

Hello folks,

Well I spent the weekend working on the Mongrel
(http://mongrel.rubyforge.org) plugin system, and actually ended up
cracking
it out into a separate sub-project and releasing it under Ruby or LGPL.

The GemPlugin project is a dynamic plugin system that uses RubyGems to
create, manage, and load plugins. It’s used in Mongrel to allow others
to
create commands for people to use without having to be a part of the
Mongrel
project. Other systems could use it no problem and it doesn’t depend on
any
Mongrel code.

The stuff is kind of funky, but take a look at:

http://mongrel.rubyforge.org/gem_plugin_rdoc/

For more information.

== Quick Usage

Plugin Authors do this:

class Snazzy < GemPlugin::Plugin “/commands”

end

Then place this code in a file they will have RubyGems autorequire (I
use
lib/init.rb).

Next they need to add the following to whatever Rakefile code you use to
create your gem:

spec.add_dependency(‘gem_plugin’, ‘>= 0.1’)
spec.add_dependency(‘theapp’, ‘>= 0.1’)
spec.autorequire = ‘init.rb’

Plugin Users do this:

$ gem install snazzy_plugin

System Implementers then setup their system to do this:

GemPlugin::Manager.instance.load “theapp” => GemPlugin::INCLUDE
plug = GemPlugin::Manager.instance.create(“/commands/snazzy”)

And everyone is happy. Read the docs for more information.

== Future Directions

There is already a sample plugin available named mongrel_status which
people
can check out as an example:

http://rubyforge.org/frs/download.php/9029/mongrel_status-0.1.tgz

Or just:

$ gem install mongrel_status

Enjoy! And feedback is welcome.

Zed A. Shaw

On 3/6/06, Zed S. [email protected] wrote:

Hey, Zed. this looks pretty interesting. Just a few points that I think
will require a pretty quick rework:

== Quick Usage

Plugin Authors do this:

class Snazzy < GemPlugin::Plugin “/commands”

end

Then place this code in a file they will have RubyGems autorequire (I
use lib/init.rb).

Next they need to add the following to whatever Rakefile code you use to
create your gem:

spec.add_dependency(‘gem_plugin’, ‘>= 0.1’)
spec.add_dependency(‘theapp’, ‘>= 0.1’)
spec.autorequire = ‘init.rb’

The #autorequire is deprecated at this point and is not recommended in
any way. RubyGems still supports it, but I believe that the next version
will be spouting some warnings at people who use autorequire in building
their gems. Since you’re using a secondary call to do the load, you can
mandate that lib/init.rb is the file to load and have your loader do the
require yourself.

System Implementers then setup their system to do this:

GemPlugin::Manager.instance.load “theapp” => GemPlugin::INCLUDE
plug = GemPlugin::Manager.instance.create(“/commands/snazzy”)

This also seems like you’re using Singleton. I think you should be able
to do this such that you can drop the call to Manager.instance if you
put your load/create etc. as transparent reflections to an instance. I’m
not sure that I did it in the most optimal way in MIME::Types 1.15 that
I released recently, but I had changed MIME::Types from a module to a
class and implemented it such that it was more or less transparent to
the user. You should be able to do it with:

class GemPlugin::Manager
class << self
private :new

  def method_missing(m, *a, &b)
    @__me__ ||= self.new
    @__me__.__send__(m, *a, &b)
  end
end

end

Then it would simply become:

GemPlugin::Manager.load “theapp” => GemPlugin::INCLUDE
plug = GemPlugin::Manager.create(“/commands/snazzy”)

-austin

On Mon, Mar 06, 2006 at 10:20:38PM +0900, Austin Z. wrote:

On 3/6/06, Zed S. [email protected] wrote:

Hey, Zed. this looks pretty interesting. Just a few points that I think
will require a pretty quick rework:

> The #autorequire is deprecated at this point and is not recommended in > any way. RubyGems still supports it, but I believe that the next version > will be spouting some warnings at people who use autorequire in building > their gems. Since you're using a secondary call to do the load, you can > mandate that lib/init.rb is the file to load and have your loader do the > require yourself. > Man that just sucks. I'll have to think about this, but off the top of my head doing a require of init.rb won't work. I'll have to __FILE__ crap and re-implement the autorequire code.

Maybe I can chat with the rubygems folks and get it put back in. It
really makes these plugins work perfectly with minimal effort.

class and implemented it such that it was more or less transparent to
end
end

I’ll play with this, I agree that the instance stuff is really annoying.
I also don’t like the include/exclude stuff and will probably change
that out for something more succinct.

Zed A. Shaw

On 3/6/06, Austin Z. [email protected] wrote:

spec.autorequire = ‘init.rb’

The #autorequire is deprecated at this point and is not recommended in
any way. RubyGems still supports it, but I believe that the next version
will be spouting some warnings at people who use autorequire in building
their gems. Since you’re using a secondary call to do the load, you can
mandate that lib/init.rb is the file to load and have your loader do the
require yourself.

Maybe I misunderstood this, but I thought “require_gem {gem-name}”
used the autorequire attribute to know which file from the gem to
load. Is that correct? If so, what will happen to require_gem when
autorequire goes away?

Mark V. wrote:

On 3/6/06, Austin Z. [email protected] wrote:

spec.autorequire = ‘init.rb’

The #autorequire is deprecated at this point and is not recommended in
any way. RubyGems still supports it, but I believe that the next version
will be spouting some warnings at people who use autorequire in building
their gems. Since you’re using a secondary call to do the load, you can
mandate that lib/init.rb is the file to load and have your loader do the
require yourself.

Maybe I misunderstood this, but I thought “require_gem {gem-name}”
used the autorequire attribute to know which file from the gem to
load. Is that correct? If so, what will happen to require_gem when
autorequire goes away?

The preferred way of requiring files is to use a plain require. Unless
something tricky is going on, this will work with both gem and non-gem
installed software (assuming you load rubygems beforehand if you are
using gem installs).

The require_gem is really only needed if you want a particular version
of gem installed, in which case you just add the require_gem statement
in a nice, centrally controlled location in your code (because you don’t
want to spread version dependencies throughout your code base), and do
the normal requires.

This is probably with an example:

If you want you use the foo file in the foobar gem, just do whereever
needed in your code base:

require ‘foo’

(you may need to require rubygems if your system doesn’t make that
automatic).

If you want to make sure you use version 3.1.4 of the gem foobar, then
in one central location put:

require_gem ‘foobar’, ‘= 3.1.4’

And whereever you need the foo file, write:

require ‘foo’

Require_gem is a mix of two concepts, the specifying of the gem
version, and the requiring of a specific (autorequire) file. This
conceptual confusion has caused several subtle bugs in the gems software
over time.

The autorequire feature is a holdever from the days when regular
requires didn’t work in rubygems. It avoided the need to do a
require_gem and a regular require. Since the regular require is all
that is needed today, autorequire is a holdover from the past.

I haven’t looked at Zed’s issues in detail yet, so I can’t comment on
his use in the pluggin system.


– Jim W.

On 3/6/06, Jim W. [email protected] wrote:

require yourself.

require ‘foo’

The problem I have with this is that maybe all I know is that I want
to use the foobar gem in my code. How am I supposed to know that the
main file I should require is foo.rb? Maybe the main file of each gem
should always have the same name as the gem.

Mark V. wrote:

On 3/6/06, Jim W. [email protected] wrote:

require yourself.

require ‘foo’

The problem I have with this is that maybe all I know is that I want
to use the foobar gem in my code. How am I supposed to know that the
main file I should require is foo.rb? Maybe the main file of each gem
should always have the same name as the gem.

I suggest specifying standard practices when creating plugins. Naming
the main include the same as the gem name is one possiblity. Or naming
the main include “GEMNAME/init.rb”. Just pick a standard and make it
the standard for defining plugins.


– Jim W.

On 3/7/06, Jim W. [email protected] wrote:

should always have the same name as the gem.

I suggest specifying standard practices when creating plugins. Naming
the main include the same as the gem name is one possiblity. Or naming
the main include “GEMNAME/init.rb”. Just pick a standard and make it
the standard for defining plugins.

I like your first suggestion best … main include has the same name as
the gem.

Obviously though, for the gems already out there, when autorequire
goes away we’ll all have to learn what file we should be requiring.

On 3/7/06, Mark V. [email protected] wrote:

Obviously though, for the gems already out there, when autorequire
goes away we’ll all have to learn what file we should be requiring.

Sort of. As far as I know, they’re deprecating it and warning on
creation in CVS. It won’t affect users any time soon, though. I
wouldn’t be surprised if a future version released fails to create a
gem that specifies an autorequire.

As I update my software that I release as gems (far less often than I
want right now :frowning: I am removing the autorequire.

It is my understanding as well that #require_gem itself will be
deprecated in favour of something like #activate_gem.

-austin