quill 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NWRmOGQ2ZDY1ZjU1ODFjY2UzMjU0MmZhZGMwZTFmOGFkZGFlODhjOQ==
5
+ data.tar.gz: !binary |-
6
+ ZDgzM2YyZmViNjI5NzQ5NTQ5MWY0YmRlMWM4M2JiNTZlNjA4YjQ3ZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZWY1MWRkMmJkMTc4YzM0OGQ1M2M3ZTcwNjlkMjExZmI5ZGVlYmY5MzhlZGJh
10
+ ZDUxNTAyMDE4Njg3ODNmMGRiOTkxZjNkMzM3NDRhNGMxODE0MzE3NzM1ZmFh
11
+ MjkxODViNzUxOGRhODg1YTZiMTY1ZmRjMjEyNWU5ZjZlZmE4ZWY=
12
+ data.tar.gz: !binary |-
13
+ ZTZlYjgxYzU0MjgxZGFjOGYyZTk1NmM5NjZlOGNhMTRiMGZkYzBkYjU2ZGMz
14
+ OGRkNjQ5MWY0OWI1MDIxODdjYmRjY2Y2ODc3NjA4MDE1NTNkOTNlMWY0MDdh
15
+ OTBhZjQyZWYxNjg0NDNhZGI4YzNmMWQzYmFlMDUzNWRlNzU5MDQ=
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1 @@
1
+ quill
@@ -0,0 +1 @@
1
+ 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in quill.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Tim Cowlishaw
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,124 @@
1
+ # Quill
2
+
3
+ Quill helps you write cleaner, clearer ruby code, by disentangling the business
4
+ of specifying a classes dependencies from the business of constructing and
5
+ supplying them.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'quill'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install quill
20
+
21
+ ## Usage
22
+
23
+ Extend your classes with the Quill DSL in order to specify their dependencies.
24
+ Each class must specify the name of the feature it implements, and can
25
+ optionally specify a list of features on which it depends:
26
+
27
+ ```ruby
28
+ require 'quill/dsl'
29
+ class UIController
30
+ extend Quill::DSL
31
+
32
+ #The name of the feature implemented
33
+ provides :ui_controller
34
+
35
+ #The names of the features we depend on. These will be passed in order as
36
+ arguments to the constructor.
37
+ depends [:logger, :display]
38
+
39
+ def initialize(logger, display)
40
+ @logger = logger
41
+ @display = display
42
+ end
43
+
44
+ def run!
45
+ #...do things with the logger and display
46
+ end
47
+ end
48
+ ```
49
+
50
+ You can then construct a Quill Container, and register all your Quill classes
51
+ with them:
52
+
53
+ ```ruby
54
+ require 'quill/container'
55
+ container = Quill::Container.new
56
+ container.register_class(UIController)
57
+
58
+ #register implementation for every feature, so that the container can resolve
59
+ the dependencies:
60
+ container.register_class(Logger)
61
+
62
+ #You can also register single instances as named features:
63
+ container.register_singleton(:display, STDOUT)
64
+
65
+ ```
66
+
67
+ Finally, ask the container for the implementation of a feature, this will
68
+ automatically resolve all the dependencies and construct the entire object
69
+ graph!
70
+
71
+ ```ruby
72
+ controller = container[:ui_controller]
73
+ controller.run!
74
+ ```
75
+
76
+ You can also lazily construct objects with a mixture of static dependencies and
77
+ other arguments, using the 'curried' option:
78
+
79
+ ```ruby
80
+ require 'quill/dsl'
81
+ require 'quill/container'
82
+
83
+ class InventoryDisplay
84
+ extend Quill::DSL
85
+
86
+ provides :inventory_display
87
+ depends [:display]
88
+ curried
89
+
90
+ #the display dependency is injected, items is not.
91
+ def initialize(display, items)
92
+ @display = display
93
+ @items = items
94
+ end
95
+
96
+ container = Quill::Container.new
97
+ container.register_class(InventoryDisplay)
98
+
99
+ display_builder_proc = container[:inventory_display]
100
+
101
+ display_builder_proc.call(inventory) #=> Constructs and returns an instance
102
+ ```
103
+
104
+ ## Why?
105
+ [Dependency
106
+ Injection](https://speakerdeck.com/bestie/improve-your-ruby-code-with-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.
107
+
108
+ ## Compatibiliyu
109
+ Tested with Ruby 1.9.3
110
+
111
+ ## Still to come
112
+
113
+ - Support for argument hashes
114
+ - Support for Ruby 2.0 named arguments
115
+ - Configurable instance memoization
116
+
117
+
118
+ ## Contributing
119
+
120
+ 1. Fork it
121
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
122
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
123
+ 4. Push to the branch (`git push origin my-new-feature`)
124
+ 5. Create new Pull Request
@@ -0,0 +1,38 @@
1
+ Feature: Declaring and Satisfying Dependencies
2
+
3
+ Scenario: Satisfying a dependency with a singleton
4
+ Given I have a factory with a named dependency
5
+ When I satisfy the named dependency with a singleton
6
+ And I call the factory
7
+ Then the factory should receive the singleton instance of its dependency
8
+
9
+ Scenario: Satisfying a dependency with a factory
10
+ Given I have a factory with a named dependency
11
+ When I satisfy the named dependency with another factory that has no dependencies
12
+ And I call the factory
13
+ Then the factory should receive an instance created by the dependency factory
14
+
15
+ Scenario: Transitively satisfying dependencies
16
+ Given I have a factory with a named dependency
17
+ When I satisfy the named dependency with another factory that has a dependency
18
+ And I satisfy that dependency with a singleton
19
+ And I call the factory
20
+ Then the dependency factory should receive the singleton instance of its dependency
21
+ And the factory should receive an instance created by the dependency factory
22
+
23
+ Scenario: Raising an error when dependencies are not satisfied
24
+ Given I have a factory with a named dependency
25
+ When I satisfy the named dependency with another factory that has a dependency
26
+ And I call the factory
27
+ Then an unmet dependency error should be raised for the transitive depenency
28
+
29
+ Scenario: Satisfying dependencies for curried factories
30
+ Given I have a curried factory with a named dependency
31
+ When I satisfy the named dependency with a singleton
32
+ And I call the factory
33
+ And I call the returned proc with additional arguments
34
+ Then the factory should receive the singleton dependency and the additional arguments
35
+
36
+ Scenario: Satisfying dependencies for factories that take an arguments hash
37
+
38
+ Scenario: Satisfying dependencies for curried factories that take an arguments hash
@@ -0,0 +1,82 @@
1
+ Given(/^I have a factory with a named dependency$/) do
2
+ @container = Quill::Container.new
3
+ @feature_class = Struct.new(:dependency) do
4
+ extend Quill::DSL
5
+ provides :feature
6
+ depends :dependency
7
+ end
8
+ @container.register_class(@feature_class)
9
+ end
10
+
11
+ Given(/^I have a curried factory with a named dependency$/) do
12
+ @container = Quill::Container.new
13
+ @feature_class = Struct.new(:dependency, :argument) do
14
+ extend Quill::DSL
15
+ provides :feature
16
+ depends :dependency
17
+ curried
18
+ end
19
+ @container.register_class(@feature_class)
20
+ end
21
+
22
+ When(/^I satisfy the named dependency with a singleton$/) do
23
+ @dependency = Object.new
24
+ @container.register_singleton(:dependency, @dependency)
25
+ end
26
+
27
+ When(/^I call the factory$/) do
28
+ begin
29
+ @feature = @container[:feature]
30
+ rescue Exception => e
31
+ @error = e
32
+ end
33
+ end
34
+
35
+ When(/^I satisfy the named dependency with another factory that has no dependencies$/) do
36
+ @dependency_class = Class.new do
37
+ extend Quill::DSL
38
+ provides :dependency
39
+ end
40
+ @container.register_class(@dependency_class)
41
+ end
42
+
43
+ When(/^I satisfy the named dependency with another factory that has a dependency$/) do
44
+ @dependency_class = Struct.new(:transitive_dependency) do
45
+ extend Quill::DSL
46
+ provides :dependency
47
+ depends :transitive_dependency
48
+ end
49
+ @container.register_class(@dependency_class)
50
+ end
51
+
52
+ When(/^I satisfy that dependency with a singleton$/) do
53
+ @transitive_dependency = Object.new
54
+ @container.register_singleton(:transitive_dependency, @transitive_dependency)
55
+ end
56
+
57
+ When(/^I call the returned proc with additional arguments$/) do
58
+ @argument = Object.new
59
+ @feature = @container[:feature][@argument]
60
+ end
61
+
62
+ Then(/^the factory should receive the singleton instance of its dependency$/) do
63
+ expect(@feature.dependency).to be == @dependency
64
+ end
65
+
66
+ Then(/^the factory should receive an instance created by the dependency factory$/) do
67
+ expect(@feature.dependency).to be_instance_of(@dependency_class)
68
+ end
69
+
70
+ Then(/^the dependency factory should receive the singleton instance of its dependency$/) do
71
+ expect(@feature.dependency.transitive_dependency).to be == @transitive_dependency
72
+ end
73
+
74
+ Then(/^the factory should receive the singleton dependency and the additional arguments$/) do
75
+ expect(@feature.dependency).to be == @dependency
76
+ expect(@feature.argument).to be == @argument
77
+ end
78
+
79
+ Then(/^an unmet dependency error should be raised for the transitive depenency$/) do
80
+ @error.should be_instance_of(Quill::UnsatisfiedDependencyError)
81
+ @error.dependency.should be == :transitive_dependency
82
+ end
@@ -0,0 +1 @@
1
+ require 'quill'
@@ -0,0 +1,5 @@
1
+ module Quill
2
+ end
3
+ require "quill/version"
4
+ require "quill/container"
5
+ require "quill/dsl"
@@ -0,0 +1,36 @@
1
+ require 'quill/unsatisfied_dependency_error'
2
+ require 'quill/no_factory_error'
3
+ module Quill
4
+ class Container
5
+ def initialize
6
+ @singletons = {}
7
+ @factories = {}
8
+ end
9
+
10
+ def register_singleton(feature, instance)
11
+ @singletons[feature] = instance
12
+ end
13
+
14
+ def register_class(klass)
15
+ raise NoFactoryError.new(klass) unless klass.respond_to?(:factory)
16
+ factory = klass.factory
17
+ @factories[factory.feature] = factory
18
+ end
19
+
20
+ def [](name)
21
+ instance = named_singleton(name) || instance_from_named_factory(name)
22
+ instance or raise UnsatisfiedDependencyError.new(name)
23
+ end
24
+
25
+ private
26
+
27
+ def named_singleton(name)
28
+ @singletons[name]
29
+ end
30
+
31
+ def instance_from_named_factory(name)
32
+ factory = @factories[name]
33
+ factory && factory.call(self)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ require 'quill/factory'
2
+ module Quill
3
+ module DSL
4
+
5
+ def factory
6
+ raise "You must specify a feature provided by the class" unless provided_feature
7
+ @factory ||= Quill::Factory.new(self, {
8
+ :feature => provided_feature,
9
+ :dependencies => @dependencies || [],
10
+ :curried => curried?
11
+ })
12
+ end
13
+
14
+ def provides(feature_name)
15
+ @provided_feature = feature_name
16
+ end
17
+
18
+ def depends(*dependency_names)
19
+ @dependencies = dependency_names
20
+ end
21
+
22
+ def curried(value = true)
23
+ @curried = value
24
+ end
25
+
26
+ private
27
+ attr_reader :provided_feature
28
+
29
+ def curried?
30
+ !!@curried
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ module Quill
2
+ class Factory
3
+ attr_reader :feature
4
+
5
+ def initialize(klass, arguments={})
6
+ @feature = arguments.fetch(:feature)
7
+ @dependencies = arguments[:dependencies] || []
8
+ @curried = arguments[:curried]
9
+ @klass = klass
10
+ end
11
+
12
+ def call(container)
13
+ curried? ? construct_curried_proc(container) : construct_instance(container)
14
+ end
15
+
16
+ private
17
+ attr_reader :klass, :dependencies
18
+
19
+ def curried?
20
+ !!@curried
21
+ end
22
+
23
+
24
+ def construct_instance(container, args=[])
25
+ arguments = fulfilled_dependencies(container) + args
26
+ @instance ||= klass.new(*arguments)
27
+ end
28
+
29
+ def construct_curried_proc(container)
30
+ ->(*args) { construct_instance(container, args) }
31
+ end
32
+
33
+ def fulfilled_dependencies(container)
34
+ dependencies.map { |dep| container[dep] }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ module Quill
2
+ class NoFactoryError < RuntimeError
3
+ def initialize(klass)
4
+ @klass = klass
5
+ end
6
+
7
+ def message
8
+ "The class #{klass.name} cannot be registered with the container, as it does not extend Quill::DSL."
9
+ end
10
+
11
+ private
12
+ attr_reader :klass
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Quill
2
+ class UnsatisfiedDependencyError < RuntimeError
3
+ def initialize(dependency)
4
+ @dependency = dependency
5
+ super
6
+ end
7
+
8
+ def message
9
+ "No implementation for the feature #{dependency} is registered with the container."
10
+ end
11
+
12
+ attr_reader :dependency
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Quill
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'quill/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "quill"
8
+ spec.version = Quill::VERSION
9
+ spec.authors = ["Tim Cowlishaw"]
10
+ spec.email = ["tim@timcowlishaw.co.uk"]
11
+ spec.description = %q{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.}
12
+ spec.summary = %q{Quill - Simple DI for your rupy applications}
13
+ spec.homepage = "http://github.com/timcowlishaw/quill"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "cucumber"
24
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'quill/container'
3
+ require 'quill/unsatisfied_dependency_error'
4
+
5
+ describe Quill::Container do
6
+ subject(:container) { Quill::Container.new }
7
+ let(:instance) { double(:instance) }
8
+ let(:name) { double(:factory) }
9
+
10
+ describe "requesting features which don't exist" do
11
+ it "raises an unment dependecy error for the feature" do
12
+ expect {
13
+ container[:non_existant_feature]
14
+ }.to raise_error { |error|
15
+ expect(error).to be_instance_of(Quill::UnsatisfiedDependencyError)
16
+ expect(error.dependency).to be == :non_existant_feature
17
+ }
18
+ end
19
+ end
20
+
21
+ describe "registering and returning singletons" do
22
+ it "returns the registed instance" do
23
+ container.register_singleton(name, instance)
24
+ expect(container[name]).to be(instance)
25
+ end
26
+ end
27
+
28
+ describe "registering and constructing classes" do
29
+ context "registering a class with a factory" do
30
+ it "calls the factory with itself when the named feature is requested" do
31
+ klass = double(:class)
32
+ instance = double(:instance)
33
+ factory = double(:factory, :feature => :feature_name)
34
+ expect(klass).to receive(:factory).and_return(factory)
35
+ container.register_class(klass)
36
+ expect(factory).to receive(:call).with(container).and_return(instance)
37
+ expect(container[:feature_name]).to be == instance
38
+ end
39
+ end
40
+
41
+ context "registering a class without a factory" do
42
+ it "raises an error" do
43
+ klass = double(:class)
44
+ expect {
45
+ container.register_class(klass)
46
+ }.to raise_error(Quill::NoFactoryError)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'quill/dsl'
3
+ describe "Quill::DSL" do
4
+
5
+ let(:factory) { double(:factory) }
6
+
7
+ subject(:extending_class) {
8
+ Class.new do
9
+ extend Quill::DSL
10
+ end
11
+ }
12
+
13
+ before(:each) do
14
+ allow(Quill::Factory).to receive(:new).and_return(factory)
15
+ end
16
+
17
+ context "when a provided feature name is not supplied" do
18
+ it "raises an error when the factory is accessed" do
19
+ expect {
20
+ extending_class.factory
21
+ }.to raise_error
22
+ end
23
+ end
24
+
25
+ context "when a provided feature name is supplied" do
26
+ context "when no dependencies are supplied" do
27
+ it "exposes a Quill factory wrapping the extended class with the specified feature name and no dependencies" do
28
+ expect(Quill::Factory).to receive(:new).with(extending_class, {
29
+ :feature => :feature_name, :dependencies => [], :curried => false
30
+ }).and_return(factory)
31
+
32
+ extending_class.instance_eval do
33
+ extend Quill::DSL
34
+ provides :feature_name
35
+ end
36
+
37
+ expect(extending_class.factory).to be == factory
38
+ end
39
+ end
40
+
41
+ context "when dependencies are supplied" do
42
+ it "exposes a Quill factory wrapping the extended class with the specified feature name and the_specified dependencies" do
43
+ expect(Quill::Factory).to receive(:new).with(extending_class, {
44
+ :feature => :feature_name,
45
+ :dependencies => [:dependency_1, :dependency_2],
46
+ :curried => false
47
+ }).and_return(factory)
48
+
49
+ extending_class.instance_eval do
50
+ extend Quill::DSL
51
+ provides :feature_name
52
+ depends :dependency_1, :dependency_2
53
+ end
54
+
55
+ expect(extending_class.factory).to be == factory
56
+ end
57
+ end
58
+
59
+ context "when the factory is specified as curried" do
60
+ it "exposes a curried Quill factory wrapping the extended class with the specified feature name" do
61
+ expect(Quill::Factory).to receive(:new).with(extending_class, {
62
+ :feature => :feature_name, :dependencies => [], :curried => true
63
+ })
64
+ extending_class.instance_eval do
65
+ extend Quill::DSL
66
+ provides :feature_name
67
+ curried
68
+ end
69
+ expect(extending_class.factory).to be == factory
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'quill/factory'
3
+ describe Quill::Factory do
4
+ let(:feature_name) { double(:feature_name) }
5
+ let(:klass) { double(:klass) }
6
+
7
+ subject(:factory) { Quill::Factory.new(klass, :feature => feature_name )}
8
+
9
+ describe "feature" do
10
+ it "returns the feature name" do
11
+ expect(factory.feature).to be == feature_name
12
+ end
13
+ end
14
+
15
+ describe "call" do
16
+ let(:container) { double(:container) }
17
+ let(:instance) { double(:instance) }
18
+
19
+ context "when the factory is not curried" do
20
+ context "when the factory has no dependencies" do
21
+ it "calls the class constructor with no arguments" do
22
+ expect(klass).to receive(:new).and_return(instance)
23
+ expect(factory.call(container)).to be == instance
24
+ end
25
+ end
26
+
27
+ context "when the factory has dependencies" do
28
+ let(:dependency_1) { double(:dependency_1) }
29
+ let(:dependency_2) { double(:dependency_2) }
30
+
31
+ subject(:factory) {
32
+ Quill::Factory.new(klass, {
33
+ :feature => feature_name,
34
+ :dependencies => [:dependency_1, :dependency_2],
35
+ })
36
+ }
37
+
38
+ it "calls the class constructor with the dependencies from the factory" do
39
+ expect(container).to receive(:[]).with(:dependency_1).and_return(dependency_1)
40
+ expect(container).to receive(:[]).with(:dependency_2).and_return(dependency_2)
41
+ expect(klass).to receive(:new).with(dependency_1, dependency_2).and_return(instance)
42
+ expect(factory.call(container)).to be == instance
43
+ end
44
+ end
45
+
46
+ it "memoizes the constructed instance of the class" do
47
+ allow(klass).to receive(:new) { Object.new }
48
+ first = factory.call(container)
49
+ second = factory.call(container)
50
+ expect(first).to eq(second)
51
+ end
52
+ end
53
+
54
+ context "when the factory is curried" do
55
+ context "when the factory has no dependencies" do
56
+ subject(:factory) {
57
+ Quill::Factory.new(klass, {
58
+ :feature => feature_name,
59
+ :curried => true,
60
+ })
61
+ }
62
+
63
+ it "returns a proc which calls the class constructor with no arguments" do
64
+ the_proc = factory.call(container)
65
+ expect(klass).to receive(:new).and_return(instance)
66
+ expect(the_proc.call).to be == instance
67
+ end
68
+ end
69
+
70
+ context "when the factory has dependencies" do
71
+ let(:dependency_1) { double(:dependency_1) }
72
+ let(:dependency_2) { double(:dependency_2) }
73
+ let(:additional_arg_1) { double(:additional_arg_1) }
74
+ let(:additional_arg_2) { double(:additional_arg_2) }
75
+
76
+ subject(:factory) {
77
+ Quill::Factory.new(klass, {
78
+ :feature => feature_name,
79
+ :dependencies => [:dependency_1, :dependency_2],
80
+ :curried => true
81
+ })
82
+ }
83
+
84
+ it "calls the class constructor with the dependencies from the factory" do
85
+ expect(container).to receive(:[]).with(:dependency_1).and_return(dependency_1)
86
+ expect(container).to receive(:[]).with(:dependency_2).and_return(dependency_2)
87
+ the_proc = factory.call(container)
88
+ expect(klass).to receive(:new).
89
+ with(dependency_1, dependency_2, additional_arg_1, additional_arg_2).
90
+ and_return(instance)
91
+ result = the_proc.call(additional_arg_1, additional_arg_2)
92
+ expect(result).to be == instance
93
+ end
94
+ end
95
+
96
+ it "memoizes the constructed instance of the class" do
97
+ allow(klass).to receive(:new) { Object.new }
98
+ first = factory.call(container)
99
+ second = factory.call(container)
100
+ expect(first).to eq(second)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.configure do |c|
2
+ c.expect_with :rspec do |conf|
3
+ conf.syntax = :expect
4
+ end
5
+
6
+ c.mock_with :rspec do |conf|
7
+ conf.syntax = :expect
8
+ end
9
+
10
+ c.order = :random
11
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quill
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tim Cowlishaw
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cucumber
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Quill helps you organize your code more easily by separating the business
56
+ of specifying a class's dependencies from the business of actually providing them,
57
+ using a simple, declerative syntax.
58
+ email:
59
+ - tim@timcowlishaw.co.uk
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - .ruby-gemset
66
+ - .ruby-version
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - features/declaring_dependencies.feature
71
+ - features/step_definitions/declaring_dependencies_steps.rb
72
+ - features/support/env.rb
73
+ - lib/quill.rb
74
+ - lib/quill/container.rb
75
+ - lib/quill/dsl.rb
76
+ - lib/quill/factory.rb
77
+ - lib/quill/no_factory_error.rb
78
+ - lib/quill/unsatisfied_dependency_error.rb
79
+ - lib/quill/version.rb
80
+ - quill.gemspec
81
+ - spec/quill/container_spec.rb
82
+ - spec/quill/dsl_spec.rb
83
+ - spec/quill/factory_spec.rb
84
+ - spec/spec_helper.rb
85
+ homepage: http://github.com/timcowlishaw/quill
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.0.4
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Quill - Simple DI for your rupy applications
109
+ test_files:
110
+ - features/declaring_dependencies.feature
111
+ - features/step_definitions/declaring_dependencies_steps.rb
112
+ - features/support/env.rb
113
+ - spec/quill/container_spec.rb
114
+ - spec/quill/dsl_spec.rb
115
+ - spec/quill/factory_spec.rb
116
+ - spec/spec_helper.rb