+ # These are class methods for runnable plugins, meant to be
+ # _extended_. Those runnable plugins get a magic *run* method but
+ # need to define their own *runner* and *dummy_runner* to make it
+ # work.
+ #
+ module Run
+
+ # A callback function, called whenever another class or module
+ # includes this one. This is used to build a list of all things
+ # that inherited this class. Having such a list lets us run a
+ # collection of plugins without knowing in advance what they are.
+ #
+ # @param c [Class,Module] the name of the class or module that
+ # included us.
+ #
+ def included(c)
+ @includers ||= []
+ @includers << c
+ end
+
+
+ # Obtain the list of classes and modules that have included this one.
+ #
+ # @return [Array<Class,Module>] the list of classes and modules
+ # that have included this one.
+ #
+ def includers()
+ @includers ||= []
+ return @includers
+ end
+
+
+ # The runner class associated with this plugin. This method must
+ # be supplied by the child class, since they will all have
+ # different runners.
+ #
+ # @return [Class] the runner class associated with this plugin.
+ #
+ def runner()
+ raise NotImplementedError
+ end
+
+
+ # The "dummy" runner class associated with this plugin. This method
+ # must be supplied by the child class, since they will all have
+ # different dummy runners.
+ #
+ # @return [Class] the dummy runner class associated with this
+ # plugin.
+ #
+ def dummy_runner()
+ raise NotImplementedError
+ end
+
+
+ # Run all of the plugins that have included this module.
+ #
+ # @param cfg [Configuration] the configuration options to pass to
+ # each of the plugins.
+ #
+ # @param args [Array<Object>] a variable number of additional
+ # arguments to be passed to the plugins we're running.
+ #
+ def run(cfg, *args)
+ includers().each do |includer|
+ plugin = includer.new(cfg)
+
+ if cfg.i_mean_business then
+ runner = runner().new()
+ else
+ runner = dummy_runner().new()
+ end
+
+ # The splat passes the correct (we hope) number of arguments to the
+ # appropriate runner. The Rm(Dummy)Runner have splats on their
+ # *target arguments as well, to turn ARGV back into an array.
+ runner.run(cfg, plugin, *args)
+ end
+ end