Module PluginFactory
In: lib/pluginfactory.rb

This module contains the PluginFactory mixin. Including PluginFactory in your class turns it into a factory for its derivatives, capable of searching for and loading them by name. This is useful when you have an abstract base class which defines an interface and basic functionality for a part of a larger system, and a collection of subclasses which implement the interface for different underlying functionality.

An example of where this might be useful is in a program which talks to a database. To avoid coupling it to a specific database, you use a Driver class which encapsulates your program‘s interaction with the database behind a useful interface. Now you can create a concrete implementation of the Driver class for each kind of database you wish to talk to. If you make the base Driver class a PluginFactory, too, you can add new drivers simply by dropping them in a directory and using the Driver‘s create method to instantiate them:

Creation Argument Variants

The create class method added to your class by PluginFactory searches for your module using

Synopsis

in driver.rb:

      require "PluginFactory"

      class Driver
              include PluginFactory
              def self::derivative_dirs
                 ["drivers"]
              end
      end

in drivers/mysql.rb:

      require 'driver'

      class MysqlDriver < Driver
              ...implementation...
      end

in /usr/lib/ruby/1.8/PostgresDriver.rb:

      require 'driver'

      class PostgresDriver < Driver
              ...implementation...
      end

elsewhere

      require 'driver'

      config[:driver_type] #=> "mysql"
      driver = Driver.create( config[:driver_type] )
      driver.class #=> MysqlDriver
      pgdriver = Driver.create( "PostGresDriver" )

Authors

  • Martin Chase <stillflame@FaerieMUD.org>
  • Michael Granger <ged@FaerieMUD.org>

License

Copyright (c) 2008-2012 Michael Granger and Martin Chase All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

  * Neither the name of the author/s, nor the names of the project's
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Methods

Constants

VERSION = '1.0.8'   Library version

External Aliases

logger -> log
logger= -> log=

Attributes

default_logger  [RW]  The logger that will be used when the logging subsystem is reset
logger  [RW]  The logger that‘s currently in effect

Public Class methods

Add the @derivatives instance variable to including classes.

Inclusion callback — extends the including class. This is here so you can either ‘include’ or ‘extend’.

Deprecated: use the Logger object at log to manipulate logging instead of this method.

Reset the global logger object to the default

Returns true if the global logger has not been set to something other than the default one.

Public Instance methods

Given the class_name of the class to instantiate, and other arguments bound for the constructor of the new object, this method loads the derivative class if it is not loaded already (raising a LoadError if an appropriately-named file cannot be found), and instantiates it with the given args. The class_name may be the the fully qualified name of the class, the class object itself, or the unique part of the class name. The following examples would all try to load and instantiate a class called "FooListener" if Listener included Factory

  obj = Listener.create( 'FooListener' )
  obj = Listener.create( FooListener )
  obj = Listener.create( 'Foo' )
derivativeClasses()

Alias for derivative_classes

Returns an Array of registered derivatives

Return the Hash of derivative classes, keyed by various versions of the class name.

factoryType()

Alias for factory_type

Returns the type name used when searching for a derivative.

getModuleName( class_name )

Alias for get_module_name

getSubclass( class_name )

Alias for get_subclass

Build and return the unique part of the given class_name either by stripping leading namespaces if the name already has the name of the factory type in it (eg., ‘My::FooService’ for Service, or by appending the factory type if it doesn‘t.

Given a class_name like that of the first argument to create, attempt to load the corresponding class if it is not already loaded and return the class object.

Inheritance callback — Register subclasses in the derivatives hash so that ::create knows about them.

loadDerivative( class_name )

Alias for load_derivative

Calculates an appropriate filename for the derived class using the name of the base class and tries to load it via require. If the including class responds to a method named derivativeDirs, its return value (either a String, or an array of Strings) is added to the list of prefix directories to try when attempting to require a modules. Eg., if class.derivativeDirs returns [‘foo’,’bar’] the require line is tried with both ‘foo/’ and ‘bar/’ prepended to it.

makeRequirePath( modname, subdir )

Alias for make_require_path

Make a list of permutations of the given modname for the given subdir. Called on a DataDriver class with the arguments ‘Socket’ and ‘drivers’, returns:

  ["drivers/socketdatadriver", "drivers/socketDataDriver",
   "drivers/SocketDataDriver", "drivers/socket", "drivers/Socket"]
requireDerivative( mod_name )

Alias for require_derivative

If the factory responds to the derivative_dirs method, call it and use the returned array as a list of directories to search for the module with the specified mod_name.

[Validate]