[ANN] 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
http://www.zedshaw.com/

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 3/6/06, Zed Shaw <zedshaw@zedshaw.com> wrote:
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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

<snip>

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.

> 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

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 Mon, Mar 06, 2006 at 10:20:38PM +0900, Austin Ziegler wrote:

On 3/6/06, Zed Shaw <zedshaw@zedshaw.com> wrote:

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?

···

On 3/6/06, Austin Ziegler <halostatue@gmail.com> 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.

--
R. Mark Volkmann
Partner, Object Computing, Inc.

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

···

On 3/6/06, Austin Ziegler <halostatue@gmail.com> wrote:

--
-- Jim Weirich

--
Posted via http://www.ruby-forum.com/\.

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.

···

On 3/6/06, Jim Weirich <jim@weirichhouse.org> wrote:

Mark Volkmann wrote:
> On 3/6/06, Austin Ziegler <halostatue@gmail.com> 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'

--
R. Mark Volkmann
Partner, Object Computing, Inc.

Mark Volkmann wrote:

···

On 3/6/06, Jim Weirich <jim@weirichhouse.org> 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 Weirich

--
Posted via http://www.ruby-forum.com/\.

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, Jim Weirich <jim@weirichhouse.org> wrote:

Mark Volkmann wrote:
> On 3/6/06, Jim Weirich <jim@weirichhouse.org> 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.

--
R. Mark Volkmann
Partner, Object Computing, Inc.

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

···

On 3/7/06, Mark Volkmann <r.mark.volkmann@gmail.com> 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.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca