Module API for the plugin system. This mixin adds the ability to load and install plugins into the extended object.
The Hash of loaded plugin modules, keyed by their downcased and symbolified name (e.g., Strelka::App::Templating => :templating)
The prefix path for loading plugins
If plugins have already been installed, this will be the call frame they were first installed from. This is used to warn about installing plugins twice.
Extension callback – initialize some data structures in the extended object.
# File lib/strelka/plugins.rb, line 123
def self::extended( mod )
super
mod.extend( Loggability )
mod.log_to( :strelka )
mod.loaded_plugins = Strelka::PluginRegistry.new
mod.plugin_path_prefix = mod.name.downcase.gsub( /::/, File::SEPARATOR )
end
Return the list of plugin modules that are in effect for the current app.
# File lib/strelka/plugins.rb, line 279
def application_stack
self.log.debug "Ancestors are: %p" % [ self.class.ancestors ]
return self.ancestors.select {|mod| mod.respond_to?(:plugin_name) }
end
Output the application stack into the logfile.
# File lib/strelka/plugins.rb, line 286
def dump_application_stack
stack = self.application_stack.map( &:plugin_name )
self.log.info "Application stack: request -> %s" % [ stack.join(" -> ") ]
end
Extension callback – add instance variables to extending objects.
# File lib/strelka/plugins.rb, line 157
def inherited( subclass )
super
@plugins ||= []
subclass.loaded_plugins = self.loaded_plugins
subclass.plugin_path_prefix = self.plugin_path_prefix
subclass.plugins_installed_from = nil
subclass.instance_variable_set( :@plugins, @plugins.dup )
end
Install the mixin part of the plugin, in the order determined by the plugin registry based on the run_outside and run_inside specifications of the plugins themselves.
# File lib/strelka/plugins.rb, line 249
def install_plugins
if self.plugins_installed?
self.log.warn "Plugins were already installed for %p from %p" %
[ self, self.plugins_installed_from ]
self.log.info "I'll attempt to install any new ones, but plugin ordering"
self.log.info "and other functionality might exhibit strange behavior."
else
self.log.info "Installing plugins for %p." % [ self ]
end
sorted_plugins = self.loaded_plugins.tsort.reverse
sorted_plugins.each do |name|
mod = self.loaded_plugins[ name ]
unless @plugins.include?( name ) || @plugins.include?( mod )
self.log.debug " skipping %s" % [ name ]
next
end
self.log.info " including %p in %p." % [ mod, self ]
include( mod )
end
self.plugins_installed_from = caller( 1 ).first
end
Load the plugin with the given name
# File lib/strelka/plugins.rb, line 196
def load_plugin( name )
# Just return Modules as-is
return name if name.is_a?( Strelka::Plugin )
mod = self.loaded_plugins[ name.to_sym ]
unless mod.is_a?( Module )
pluginpath = File.join( self.plugin_path_prefix, name.to_s )
require( pluginpath )
mod = self.loaded_plugins[ name.to_sym ] or
raise "#{name} plugin didn't load correctly."
end
return mod
end
Install the mixin part of plugins immediately before the first instance is created.
# File lib/strelka/plugins.rb, line 240
def new( * )
self.install_plugins unless self.plugins_installed?
super
end
Load the plugins with the given names
and install them.
# File lib/strelka/plugins.rb, line 169
def plugins( *names )
self.log.info "Adding plugins: %s" % [ names.flatten.map(&:to_s).join(', ') ]
# Load the associated Plugin Module objects
names.flatten.each {|name| self.load_plugin(name) }
# Add the name/s to the list of mixins to apply on startup
@plugins |= names
# Install the declarative half of the plugin immediately
names.each do |name|
plugin = nil
if name.is_a?( Module )
plugin = name
else
plugin = self.loaded_plugins[ name ]
end
self.log.debug " registering %p" % [ name ]
self.register_plugin( plugin )
end
end
Returns true
if the plugins for the extended app class have
already been installed.
# File lib/strelka/plugins.rb, line 151
def plugins_installed?
return !self.plugins_installed_from.nil?
end
Register the plugin mod
in the receiving class. This adds any
declaratives and class-level data necessary for configuring the plugin.
# File lib/strelka/plugins.rb, line 216
def register_plugin( mod )
if mod.const_defined?( :ClassMethods )
cm_mod = mod.const_get(:ClassMethods)
self.log.debug " adding class methods from %p" % [ cm_mod ]
extend( cm_mod )
cm_mod.instance_variables.each do |ivar|
next if instance_variable_defined?( ivar )
ival = cm_mod.instance_variable_get( ivar )
copy = Strelka::DataUtilities.deep_copy( ival )
self.log.debug " copying class instance variable %s (%p)" % [ ivar, copy ]
instance_variable_set( ivar, copy )
self.log.debug " instance variable %p set to %p in %p" %
[ ivar, self.instance_variable_get(ivar), self ]
end
end
end