ddplugin is a library for managing plugins.
Designing a library so that third parties can easily extend it greatly improves its usefulness. ddplugin helps solve this problem using plugins, which are classes of a certain type and with a given identifier (Ruby symbol).
This code was extracted from Nanoc, where it has been in production for years.
Many projects can make use of plugins. Here are a few examples:
a text processing library with filters such as
an image processing library with filters such as
a database driver abstraction with connectors such as
a document management system with data sources such as
In ddplugin, the filters, connectors and data sources would be plugin types, while the actual plugins, such as
database would be plugins.
A typical way to use plugins would be to store the plugin names in a configuration file, so that the actual plugin implementations can be discovered at runtime.
ddplugin requires Ruby 2.3 or higher.
ddplugin adheres to Semantic Versioning 2.0.0.
If your library where you want to use ddplugin has a gemspec, add ddplugin as a runtime dependency to the gemspec:
spec.add_runtime_dependency 'ddplugin', '~> 1.0'
If you use Bundler instead, add it to the
gem 'ddplugin', '~> 1.0'
Plugin type are classes that extend
class Filter extend :: end class DataSource extend :: end
To define a plugin, create a class that inherits from the plugin type and sets the identifier, either as a symbol or a string:
class ERBFilter < Filter # Specify the identifier as a symbol… identifier :erb end class HamlFilter < Filter # … or as a string … identifier 'haml' end class FilesystemDataSource < DataSource # … or even provide multiple. identifiers :filesystem, :file_system end class PostgresDataSource < DataSource # … or mix and match (not sure why you would, though) identifier :postgres, 'postgresql' end
To find a plugin of a given type and with a given identifier, call
.named on the plugin type, passing an identifier:
Filter.named(:erb) # => ERBFilter Filter.named('haml') # => HamlFilter DataSource.named(:filesystem) # => FilesystemDataSource DataSource.named(:postgres) # => PostgresDataSource
In a real-world situation, the plugin types could be described in the environment:
% cat .env DATA_SOURCE_TYPE=postgres
DataSource.named(ENV.fetch('DATA_SOURCE_TYPE')) # => PostgresDataSource
… or in a configuration file:
% cat config.yml data_source: 'filesystem'
config = YAML.load_file('config.yml') DataSource.named(config.fetch('data_source')) # => FilesystemDataSource
To get all plugins of a given type, call
.all on the plugin type:
Filter.all # => [ERBFilter, HamlFilter] DataSource.all # => [FilesystemDataSource, PostgresDataSource]
To get the identifier of a plugin, call
.identifier, which returns a symbol:
Filter.named(:erb).identifier # => :erb Filter.named('haml').identifier # => :haml PostgresDataSource.identifier # => :postgres
Pull requests and issues are greatly appreciated.
When you submit a pull request, make sure that your change is covered by tests, and that the
README and YARD source code documentation are still up-to-date.
To run the tests:
% bundle install % bundle exec rake