diff options
Diffstat (limited to 'lib/mongrel/plugins.rb')
-rw-r--r-- | lib/mongrel/plugins.rb | 78 |
1 files changed, 73 insertions, 5 deletions
diff --git a/lib/mongrel/plugins.rb b/lib/mongrel/plugins.rb index 9778e9b..f312e36 100644 --- a/lib/mongrel/plugins.rb +++ b/lib/mongrel/plugins.rb @@ -1,6 +1,47 @@ require 'singleton' module Mongrel + + # Implements the main method of managing plugins for Mongrel. + # "Plugins" in this sense are any classes which get registered + # with Mongrel for possible use when it's operating. These can + # be Handlers, Commands, or other classes. When you create a + # Plugin you register it into a URI-like namespace that makes + # it easy for you (and others) to reference it later during + # configuration. + # + # PluginManager is used as nothing more than a holder of all the + # plugins that have registered themselves. Let's say you have: + # + # class StopNow < Plugin "/commands" + # ... + # end + # + # Then you can get at this plugin with: + # + # cmd = PluginManager.create("/commands/stopnow") + # + # The funky syntax for StopNow is a weird trick borrowed from + # the Camping framework. See the Mongrel::Plugin *function* (yes, + # function). What this basically does is register it + # into the namespace for plugins at /commands. You could go + # as arbitrarily nested as you like. + # + # Why this strange almost second namespace? Why not just use + # the ObjectSpace and/or Modules? The main reason is speed and + # to avoid cluttering the Ruby namespace with what is really a + # configuration statement. This lets implementors put code + # into the Ruby structuring they need, and still have Plugins + # available to Mongrel via simple URI-like names. + # + # The alternative (as pluginfactory does it) is to troll through + # ObjectSpace looking for stuff that *might* be plugins every time + # one is needed. This alternative also means that you are stuck + # naming your commands in specific ways and putting them in specific + # modules in order to configure how Mongrel should use them. + # + # One downside to this is that you need to subclass plugin to + # make it work. In this case use mixins to add other functionality. class PluginManager include Singleton @@ -8,6 +49,9 @@ module Mongrel @plugins = URIClassifier.new end + # Tell the PluginManager to scan the given path (recursively) + # and load the *.rb files found there. This is how you'd + # setup your own plugin directory. def load(path) Dir.chdir(path) do Dir["**/*.rb"].each do |rbfile| @@ -16,6 +60,9 @@ module Mongrel end end + # Not necessary for you to call directly, but this is + # how Mongrel::PluginBase.inherited actually adds a + # plugin to a category. def register(category, name, klass) cat, ignored, map = @plugins.resolve(category) if not cat @@ -26,17 +73,21 @@ module Mongrel end end - + # Resolves the given name (should include /category/name) to + # find the plugin class and create an instance. It uses + # the same URIClassifier that the rest of Mongrel does so it + # is fast. def create(name, options = {}) category, plugin, map = @plugins.resolve(name) if category and plugin and plugin.length > 0 - STDERR.puts "found: #{category} #{plugin} for #{name}" map[plugin].new(options) else raise "Plugin #{name} does not exist" end end + # Returns a map of URIs->[handlers] that you can + # use to investigate available handlers. def available map = {} @plugins.uris.each do |u| @@ -50,19 +101,36 @@ module Mongrel end + # This base class for plugins reallys does nothing + # more than wire up the new class into the right category. + # It is not thread-safe yet but will be soon. class PluginBase + # See Mongrel::Plugin for an explanation. def PluginBase.inherited(klass) - - PluginManager.instance.register(@@category, klass.to_s.downcase, klass) + name = "/" + klass.to_s.downcase + PluginManager.instance.register(@@category, name, klass) end + # See Mongrel::Plugin for an explanation. def PluginBase.category=(category) @@category = category end end - def Plugin(c) + # This nifty function works with the PluginBase to give you + # the syntax: + # + # class MyThing < Plugin "/things" + # ... + # end + # + # What it does is temporarily sets the PluginBase.category, and then + # returns PluginBase. Since the next immediate thing Ruby does is + # use this returned class to create the new class, PluginBase.inherited + # gets called. PluginBase.inherited then uses the set category, class name, + # and class to register the plugin in the right way. + def Mongrel::Plugin(c) PluginBase.category = c PluginBase end |