ddplugin¶ ↑
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.
Use case¶ ↑
Many projects can make use of plugins. Here are a few examples:
-
a text processing library with filters such as
colorize-syntax
,markdown
andsmartify-quotes
. -
an image processing library with filters such as
resize
,desaturate
androtate
. -
a database driver abstraction with connectors such as
postgres
,sqlite3
andmysql
. -
a document management system with data sources such as
filesystem
anddatabase
.
In ddplugin, the filters, connectors and data sources would be plugin types, while the actual plugins, such as markdown
, rotate
, postgres
and 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.
Requirements¶ ↑
ddplugin requires Ruby 2.3 or higher.
Versioning¶ ↑
ddplugin adheres to Semantic Versioning 2.0.0.
Installation¶ ↑
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 Gemfile
:
gem 'ddplugin', '~> 1.0'
Usage¶ ↑
Plugin type are classes that extend DDPlugin::Plugin
:
class Filter extend DDPlugin::Plugin end class DataSource extend DDPlugin::Plugin 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
Development¶ ↑
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