[ANN] GemPlugin 0.1 -- A Mongrel Spinoff

Z

Zed Shaw

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
http://www.zedshaw.com/
 
Z

zedshaw

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

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
http://www.zedshaw.com/
 
M

Mark Volkmann

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

Jim Weirich

Mark said:
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.
 
M

Mark Volkmann

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'

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

Jim Weirich

Mark said:
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.
 
M

Mark Volkmann

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

Austin Ziegler

T24gMy83LzA2LCBNYXJrIFZvbGttYW5uIDxyLm1hcmsudm9sa21hbm5AZ21haWwuY29tPiB3cm90
ZToKPiBPYnZpb3VzbHkgdGhvdWdoLCBmb3IgdGhlIGdlbXMgYWxyZWFkeSBvdXQgdGhlcmUsIHdo
ZW4gYXV0b3JlcXVpcmUKPiBnb2VzIGF3YXkgd2UnbGwgYWxsIGhhdmUgdG8gbGVhcm4gd2hhdCBm
aWxlIHdlIHNob3VsZCBiZSByZXF1aXJpbmcuCgpTb3J0IG9mLiBBcyBmYXIgYXMgSSBrbm93LCB0
aGV5J3JlIGRlcHJlY2F0aW5nIGl0IGFuZCB3YXJuaW5nIG9uCmNyZWF0aW9uIGluIENWUy4gSXQg
d29uJ3QgYWZmZWN0IHVzZXJzIGFueSB0aW1lIHNvb24sIHRob3VnaC4gSQp3b3VsZG4ndCBiZSBz
dXJwcmlzZWQgaWYgYSBmdXR1cmUgdmVyc2lvbiByZWxlYXNlZCBmYWlscyB0byBjcmVhdGUgYQpn
ZW0gdGhhdCBzcGVjaWZpZXMgYW4gYXV0b3JlcXVpcmUuCgpBcyBJIHVwZGF0ZSBteSBzb2Z0d2Fy
ZSB0aGF0IEkgcmVsZWFzZSBhcyBnZW1zIChmYXIgbGVzcyBvZnRlbiB0aGFuIEkKd2FudCByaWdo
dCBub3cgOiggSSBhbSByZW1vdmluZyB0aGUgYXV0b3JlcXVpcmUuCgpJdCBpcyBteSB1bmRlcnN0
YW5kaW5nIGFzIHdlbGwgdGhhdCAjcmVxdWlyZV9nZW0gaXRzZWxmIHdpbGwgYmUKZGVwcmVjYXRl
ZCBpbiBmYXZvdXIgb2Ygc29tZXRoaW5nIGxpa2UgI2FjdGl2YXRlX2dlbS4KCi1hdXN0aW4KLS0K
QXVzdGluIFppZWdsZXIgKiBoYWxvc3RhdHVlQGdtYWlsLmNvbQogICAgICAgICAgICAgICAqIEFs
dGVybmF0ZTogYXVzdGluQGhhbG9zdGF0dWUuY2EK
 

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

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top