Quill
Quill helps you write cleaner, clearer ruby code, by disentangling the business of specifying a classes dependencies from the business of constructing and supplying them.
Installation
Add this line to your application's Gemfile:
gem 'quill'
And then execute:
$ bundle
Or install it yourself as:
$ gem install quill
Usage
Extend your classes with the Quill DSL in order to specify their dependencies. Each class must specify the name of the feature it implements, and can optionally specify a list of features on which it depends:
require 'quill/dsl'
class UIController
extend Quill::DSL
#The name of the feature implemented
provides :ui_controller
#The names of the features we depend on. These will be passed in order as
#arguments to the constructor.
depends :logger, :display
def initialize(logger, display)
@logger = logger
@display = display
end
def run!
#...do things with the logger and display
end
end
You can then construct a Quill Container, and register all your Quill classes with them:
require 'quill/container'
container = Quill::Container.new
container.register_class(UIController)
#register implementation for every feature, so that the container can resolve
#the dependencies:
container.register_class(Logger)
#You can also register single instances as named features:
container.register_singleton(:display, STDOUT)
Finally, ask the container for the implementation of a feature, this will automatically resolve all the dependencies and construct the entire object graph!
controller = container[:ui_controller]
controller.run!
You can also lazily construct objects with a mixture of static dependencies and other arguments, using the 'curried' option:
require 'quill/dsl'
require 'quill/container'
class InventoryDisplay
extend Quill::DSL
provides :inventory_display
depends :display
curried
#the display dependency is injected, items is not.
def initialize(display, items)
@display = display
@items = items
end
end
container = Quill::Container.new
container.register_class(InventoryDisplay)
display_builder_proc = container[:inventory_display]
display_builder_proc.call(inventory) #=> Constructs and returns an instance
Why?
Dependency Injection is a fundamental pattern in object oriented programming, and is invaluable for making sure your code is testable and minimally coupled. However, it's often difficult to work out where the responsiblity for satisfying dependencies should happen. Quill takes care of this for you, with a simple, minimal framework for configuring your application's dependencies.
Compatibility
Tested with Ruby 1.9.3
Still to come
- Support for argument hashes
- Support for Ruby 2.0 named arguments
- Configurable instance memoization
- Better documentation and examples (including YARD, and an example of rails integration)
- Benchmarks
- Improved API to use factories directly, making use of the DSL optional
- Maybe some more experimental / advanced features:
- structural (duck-typed) dependency specifications
- inheritable dependency specifications
Contributing
- Fork it
- 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