A simple gem plugin system. Extracted from mvn2
. Plugins have to be defined in gems for them to be able to be picked up on automatically.
Add this line to your application's Gemfile:
gem 'everyday-plugins'
And then execute:
$ bundle
Or install it yourself as:
$ gem install everyday-plugins
###For conditionally running plugin setup code (or other code) based on installed gems
As of version 1.1.0, there is support for running a block of code based on whether or not certain gems are installed. This is via the EverydayPlugins::Loader
module. You can either extend
it and use the depend
method like any other plugin setup method, or you can use the static EverydayPlugins::Loader.depend
method. The method takes each dependency as a separate argument. If you want to specify more than just the name of the gem (for example, if you want to require a minimum version), you need to put the parameters for that argument into an array.
Here is an example:
EverydayPlugins::Loader.depend(['bundler', '~> 1.5'], 'rake') {
#do stuff here
}
And here is an example using extend
:
class MyLoader
extend EverydayPlugins::Loader
depend(['bundler', '~> 1.5'], 'rake') {
#do stuff here
}
end
###For supporting plugins: See below for info on defining and using plugin types. As for including plugins, use
EverydayPlugins::Plugins.load_plugins '{folder}'
where {folder}
is the folder name you specify for your plugins to be put in. For example, my mvn2
gem uses
EverydayPlugins::Plugins.load_plugins 'mvn2'
###For creating plugins:
The files have to match the pattern {folder}/plugin/*.plugin.rb
in your gem's lib/
folder, where {folder}
is whatever folder path the gem you are adding a plugin to requires. If you do that, when the gem is installed, the gem accepting plugins will automatically pick up on it and load it.
Two examples of this are my gems colorconfig
and mvn2-say
.
The EverydayPlugins::Plugin
module is used for registering a plugin of a defined type. It defines the register
method. You should use extend
so that you can define things statically. There is no need for a build
method because it automatically adds the plugins at the time you call the method.
Here is an example:
register :option, sym: :timer, names: %w(-t --timer), desc: 'display a timer while the build is in progress'
And another:
register(:before_run, order: 2) { |options|
EverydayPlugins::Plugins.set_var :time1, Time.now
EverydayPlugins::Plugins.set_var :thread, options[:timer] ? Thread.new {
start_time = EverydayPlugins::Plugins.get_var :time1
while true
print "\r#{get_timer_message(start_time, Time.now)}"
sleep(0.05)
end
} : nil
}
The register
method takes a first parameter of the plugin type identifier, followed by an optional (but probably necessary) hash of options, and an optional block (usable with most built-in plugin types, required by some).
If you want to define a new plugin type, you can extend the EverydayPlugins::PluginType
. This defines the register_type
and register_variable
methods. Technically, you don't really need to register a variable, but if you want to give it a certain starting value, you will need to register it and pass over the value. register_type
takes a first parameter of the plugin type identifier, followed by a block. The block will always take a first parameter of the list of instances, followed by any additional parameters passed to the plugin when it is called. The block has the task of taking the list of plugin instances and turning it into whatever result the plugin is supposed to have.
Here is an example:
register_type(:command_flag) { |list|
options = EverydayPlugins::Plugins.get_var :options
flags = []
list.each { |flag|
if flag[:block].nil?
flags << " #{flag[:options][:flag]}" if flag[:options].has_key?(:option) && options[flag[:options][:option]] == (flag[:options].has_key?(:value) ? flag[:options][:value] : true)
else
flag[:block].call(options, flags)
end
}
flags.join
}
You might notice in the second plugin example, as well as the plugin type example, methods are called on EverydayPlugins::Plugins
. This is the class that stores all of the plugins and types. It has various methods, but the ones involved in making a plugin are:
EverydayPlugins::Plugins.get(type, *args)
- Gets the result of a plugin type. The first parameter is the plugin type identifier, followed by any additional arguments the plugin type takes.
EverydayPlugins::Plugins.get_var(name)
- Gets a single variable by name
EverydayPlugins::Plugins.get_vars(*names)
- Gets a list of variables by name. Useful for getting a lot of variables in one line.
EverydayPlugins::Plugins.set_var(name, value)
- Sets a single variable of the given name to the given value.
EverydayPlugins::Plugins.set_vars(vars = {})
- Sets a list of variables to the values specified. It use a hash format, so you can do something like
EverydayPlugins::Plugins.set_vars found: true, info_line_last: false
- Sets a list of variables to the values specified. It use a hash format, so you can do something like
- Fork it ( http://github.com/henderea/everyday-plugins/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request