Project

quill

0.0
Repository is archived
No commit activity in last 3 years
No release in over 3 years
Quill helps you organize your code more easily by separating the business of specifying a class's dependencies from the business of actually providing them, using a simple, declerative syntax.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.3
>= 0
 Project Readme

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

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request