deject 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in deject.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/Readme.md ADDED
@@ -0,0 +1,212 @@
1
+ About
2
+ =====
3
+
4
+ Simple dependency injection
5
+
6
+ Install
7
+ =======
8
+
9
+ On most systems:
10
+
11
+ $ gem install deject # coming soon
12
+
13
+ On some systems:
14
+
15
+ $ sudo gem install deject
16
+
17
+ If you have to use sudo and you don't know why, it's because you need to set your GEM_HOME environment variable.
18
+
19
+ Example
20
+ =======
21
+
22
+ require 'deject'
23
+
24
+ # Represents some client like https://github.com/voloko/twitter-stream
25
+ # Some client that will be used by our service
26
+ class Client
27
+ def initialize(credentials)
28
+ @credentials = credentials
29
+ end
30
+
31
+ def login(name)
32
+ @login = name
33
+ end
34
+
35
+ def has_logged_in?(name) # !> `&' interpreted as argument prefix
36
+ @login == name
37
+ end
38
+
39
+ def initialized_with?(credentials)
40
+ @credentials == credentials
41
+ end
42
+ end
43
+
44
+
45
+ class Service
46
+ Deject self # <-- we'll talk more about this later
47
+
48
+ # you can basically think of the block as a factory that
49
+ # returns a client. It is evaluated in the context of the instance
50
+ # ...though I'm not sure that's a good strategy to employ
51
+ # (I suspect it would be better that these return constants as much as possible)
52
+ dependency(:client) { Client.new credentials }
53
+
54
+ attr_accessor :name
55
+
56
+ def initialize(name)
57
+ self.name = name
58
+ end
59
+
60
+ def login
61
+ client.login name
62
+ end
63
+
64
+ def credentials
65
+ # a login key or something, would probably be dejected as well
66
+ # to retrieve the result from some config file or service
67
+ 'skj123@#KLFNV9ajv'
68
+ end
69
+ end
70
+
71
+ # using the default
72
+ service = Service.new('josh')
73
+ service.login
74
+ service.client # => #<Client:0x007ff97a92d9b8 @credentials="skj123@#KLFNV9ajv", @login="josh">
75
+ service.client.has_logged_in? 'josh' # => true
76
+ service.client.initialized_with? service.credentials # => true
77
+
78
+ # overriding the default at instance level
79
+ client_mock = Struct.new :recordings do
80
+ def method_missing(*args)
81
+ self.recordings ||= []
82
+ recordings << args
83
+ end
84
+ end
85
+ client = client_mock.new
86
+ sally = Service.new('sally').with_client client # <-- you can also override with a block
87
+
88
+ sally.login
89
+ client.recordings # => [[:login, "sally"]]
90
+
91
+ sally.login
92
+ client.recordings # => [[:login, "sally"], [:login, "sally"]]
93
+
94
+ Reasons
95
+ =======
96
+
97
+ Why write this?
98
+ ---------------
99
+
100
+ Hard dependencies kick ass. They make your code clear and easy to understand.
101
+ But, of course, they're hard, you can't change them (or can't reasonably change them).
102
+ So when you go to test, it sucks. When you want to reuse, it sucks. How to get around this?
103
+ Inject your dependencies.
104
+
105
+ And while it's not the worst thing in the world to do custom dependency injection in Ruby,
106
+ it can still get obnoxious. What do you do? There's basically two options:
107
+
108
+ 1. Add it as an argument when initializing (or _possibly_ when invoking your method). This works
109
+ fine if you aren't already doing anything complicated with your arguments. If you can just throw
110
+ an optional arg in there for the dependency, giving it a default of the hard dependency, then
111
+ it's not too big of a deal. But what if you have two dependencies? Then you can't use optional
112
+ arguments, because how will you know which is which? What if you're already taking optional args?
113
+ Then again, you can't pass this in optionally. So you have to set it to an ordinal argument, which
114
+ means that everywhere you use the thing, you have to deal with the dependency. It's cumbersome and ugly.
115
+ Or you can pass it in with an options hash, but what if you're already taking a hash (as I was when
116
+ I decided I wanted this) and it's not for this object? Then you have to namespace the common options
117
+ such that you can tell them apart, it's gross (e.g. passing html options to a form in Rails), and you
118
+ only need to do it for something that users shouldn't need to care about unless they really want to.
119
+
120
+ 2. Defining methods to return the dependency that can be overridden by setting the value. This is a heavier
121
+ choice than the above, but it can become necessary. Define an `attr_writer :whatever` and a getter
122
+ whose body looks like `@whatever ||= HardDependency.new`. Not the worst thing in the world, but it takes
123
+ about four lines and clutters things up. What's more, it must be set with a setter, and setters always
124
+ return the RHS of the assignment. So to override it, you have to have three lines where you probably only want one.
125
+ And of course, having a real method in there is a statement. It says "this is the implementation", people
126
+ don't override methods all willy nilly, I'd give dirty looks to colleagues if they overrode it as was convenient.
127
+ For instance, say you _always_ want to override the default (e.g. a FakeUser in the test environment and User in
128
+ development/production environments). Then you have to open the class and redefine it in an initialization file.
129
+ Not cool.
130
+
131
+ Deject handles these shortcomings with the default ways to inject dependencies. Declaring something a dependency
132
+ inherently identifies it as overridable. Overriding it by environment is not shocking or unexpected, and only requires one line,
133
+ and has the advantage of closures during overriding -- as opposed to having to metaprogramming to set that default.
134
+
135
+ It makes it very easy to declare and to override dependencies, by adding an inline call to the override.
136
+ You don't have to deal with arguments, you don't have to define methods, it defines the methods for you
137
+ and gives you an easy way to inject a new value. In the end, it's simpler and easier to understand.
138
+
139
+
140
+ Statements I am trying to make by writing this
141
+ ----------------------------------------------
142
+
143
+ Dependencies should be soft by default, dependency injection can have a place in Ruby
144
+ (even though I'll probably get made fun of for it). I acknowledge that I really enjoyed
145
+ the post [Why I love everything you hate about Java](http://magicscalingsprinkles.wordpress.com/2010/02/08/why-i-love-everything-you-hate-about-java/).
146
+ Though I agreed with a lot of the rebuttals in the comments as well.
147
+
148
+ I intentionally didn't do this with module inclusion. Module inclusion has become a cancer
149
+ (I'll probably write a blog about that later). _Especially_ the way people abuse the `self.included` hook.
150
+ I wanted to show people that you don't _HAVE_ to do that. There's no reason your module can't have
151
+ a method that is truthful about its purpose, something like `MyModule.apply_to MyClass`, it can include and extend
152
+ in there all it wants. That's fine, that's obvious, it isn't lying. But when people `include MyModule`
153
+ just so they can get into the included hook (where they almost never need to) and then **EXTEND** the class... grrrrr.
154
+
155
+ And of course, after I decided I wasn't going to directly include / extend the module, I began
156
+ thinking about how to get Deject onto the class. `Deject.dejectify SomeClass`? Couldn't think of
157
+ a good verb. But wait, do I _really_ need a verb? I went and read
158
+ [Execution in the Kingdom of Nouns](http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html)
159
+ and decided I was okay with having a method that applies it, hence `Deject SomeClass`. Not a usual practice
160
+ but not everything needs to be OO. Which led to the next realization that I didn't need a module at all.
161
+
162
+ So, there's two implementations. You can set which one you want to use with an environment variable (not that you care).
163
+ The first is "functional" which is to say that I was trying to channel functional ideas when writing it. It's really just one
164
+ big function that defines and redefines methods. Initially I hated this, I found it very difficult to read (might have been
165
+ better if Ruby had macros), I had to add comments in to keep track of what was happening.
166
+ But then I wrote the object oriented implementation, and it was pretty opaque as well.
167
+ Plus there were a lot of things I wanted to do that were very difficult to accomplish, and it was much longer.
168
+
169
+ So in the end, I'm hoping someone takes the time to look at both implementations and gives me feedback on their thoughts
170
+ Is one better? Are they each better in certain ways? Can this code be made simpler? Any feedback is welcome.
171
+
172
+ Oh, I also intentionally used closures over local variables rather than instance variables, because I
173
+ wanted to make people realize it's better to use setters and getters than to directly access instance variables
174
+ (to be fair, there are some big names that [disagree with](http://www.ruby-forum.com/topic/211544#919648) me on this).
175
+ I think most people directly access ivars because they haven't found themselves in a situation where it mattered.
176
+ But what if `attr_accessor` wound up changing implementations such that it didn't use ivars? "Ridiculous" I can hear
177
+ people saying, but it's not so ridiculous when you realize that you can remove 4 redundant lines by inheriting from
178
+ a Struct. If you use indirect access, everything still works just fine. And structs aren't the only place this occurs,
179
+ think about ActiveRecord::Base, it doesn't use ivars, so if you use attr_accessor in your model somewhere, you need to
180
+ know how a given attribute was defined so that you can know if you should use ivars or not... terrible. Deject's functional
181
+ implementation does not use ivars, you **must** use the getter and the overrider (there isn't currently a setter).
182
+ That is intentional (though I used ivars in the OO implementation).
183
+
184
+
185
+ Todo
186
+ ====
187
+
188
+ Maybe raise an error if you call `with_whatever` and pass no args.
189
+ Maybe add a setter rather than only provide the overrider.
190
+
191
+ License
192
+ =======
193
+
194
+ Copyright (c) 2012 Joshua Cheek
195
+
196
+ Permission is hereby granted, free of charge, to any person obtaining a copy
197
+ of this software and associated documentation files (the "Software"), to deal
198
+ in the Software without restriction, including without limitation the rights
199
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
200
+ copies of the Software, and to permit persons to whom the Software is
201
+ furnished to do so, subject to the following conditions:
202
+
203
+ The above copyright notice and this permission notice shall be included in
204
+ all copies or substantial portions of the Software.
205
+
206
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
207
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
208
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
209
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
210
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
212
+ THE SOFTWARE.
data/deject.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "deject/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "deject"
7
+ s.version = Deject::VERSION
8
+ s.authors = ["Josh Cheek"]
9
+ s.email = ["josh.cheek@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Simple dependency injection}
12
+ s.description = %q{Provides a super simple API for dependency injection}
13
+
14
+ s.rubyforge_project = "deject"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "pry"
24
+ # s.add_runtime_dependency "rest-client"
25
+ end
data/lib/deject.rb ADDED
@@ -0,0 +1,8 @@
1
+ case ENV['deject_implementation']
2
+ when 'object_oriented'
3
+ require 'deject/object_oriented'
4
+ else
5
+ require 'deject/functional'
6
+ end
7
+
8
+ require "deject/version"
@@ -0,0 +1,48 @@
1
+ module Deject
2
+ UninitializedDependency = Class.new StandardError
3
+ end
4
+
5
+ def Deject(klass)
6
+ uninitialized_error = lambda do |meth|
7
+ raise Deject::UninitializedDependency, "#{meth} invoked before being defined"
8
+ end
9
+
10
+ # define klass.dependency
11
+ klass.define_singleton_method :dependency do |meth, &default_block|
12
+
13
+ # define the getter
14
+ define_method meth do
15
+ uninitialized_error[meth] unless default_block
16
+ value = instance_eval &default_block
17
+ define_singleton_method(meth) { value }
18
+ send meth
19
+ end
20
+
21
+ # define the override
22
+ define_method :"with_#{meth}" do |value=nil, &block|
23
+
24
+ # redefine getter if given a block
25
+ if block
26
+ define_singleton_method meth do
27
+ value = instance_eval &block
28
+ define_singleton_method(meth) { value }
29
+ send meth
30
+ end
31
+
32
+ # always return value if given a value
33
+ else
34
+ define_singleton_method(meth) { value }
35
+ end
36
+
37
+ self
38
+ end
39
+ end
40
+
41
+ # override multiple dependencies
42
+ klass.send :define_method, :with_dependencies do |overrides|
43
+ overrides.each { |meth, value| send "with_#{meth}", value }
44
+ self
45
+ end
46
+
47
+ klass
48
+ end
@@ -0,0 +1,82 @@
1
+ def Deject(klass)
2
+ klass.extend Deject
3
+ end
4
+
5
+ module Deject
6
+ UninitializedDependency = Class.new StandardError
7
+
8
+ def dependency(meth, &block)
9
+ InstanceMethods.for self, meth, block
10
+ end
11
+
12
+
13
+ class InstanceMethods
14
+ attr_accessor :klass, :meth, :initializer, :ivar
15
+
16
+ def self.for(klass, meth, initializer)
17
+ instance = new klass, meth, initializer
18
+ instance.define_getter
19
+ instance.define_override
20
+ instance.define_multi_override
21
+ end
22
+
23
+ def initialize(klass, meth, initializer)
24
+ self.klass, self.meth, self.initializer, self.ivar = klass, meth, initializer, "@#{meth}"
25
+ end
26
+
27
+ def define_getter
28
+ ivar, meth, initializer = self.ivar, self.meth, self.initializer
29
+ klass.send :define_method, meth do
30
+ unless instance_variable_defined? ivar
31
+ instance_variable_set ivar, Deject::Dependency.new(self, meth, initializer)
32
+ end
33
+ instance_variable_get(ivar).invoke
34
+ end
35
+ end
36
+
37
+ def define_override
38
+ ivar, meth = self.ivar, self.meth
39
+ klass.send :define_method, "with_#{meth}" do |value=nil, &initializer|
40
+ initializer ||= Proc.new { value }
41
+ instance_variable_set ivar, Deject::Dependency.new(self, meth, initializer)
42
+ self
43
+ end
44
+ end
45
+
46
+ def define_multi_override
47
+ klass.send :define_method, :with_dependencies do |overrides|
48
+ overrides.each { |meth, value| send "with_#{meth}", value }
49
+ self
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ class Dependency < Struct.new(:instance, :dependency, :initializer)
56
+ attr_accessor :result
57
+
58
+ def invoke
59
+ validate_initializer!
60
+ memoized_result
61
+ end
62
+
63
+ def validate_initializer!
64
+ return if initializer
65
+ raise UninitializedDependency, "#{dependency} invoked before being defined"
66
+ end
67
+
68
+ def memoized_result
69
+ memoize! unless memoized?
70
+ result
71
+ end
72
+
73
+ def memoized?
74
+ @memoized
75
+ end
76
+
77
+ def memoize!
78
+ @memoized = true
79
+ self.result = instance.instance_eval &initializer
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,3 @@
1
+ module Deject
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,78 @@
1
+ require 'deject'
2
+
3
+ describe Deject, 'acceptance tests' do
4
+ example 'setting and overriding' do
5
+ class Client
6
+ def initialize(credentials)
7
+ @credentials = credentials
8
+ end
9
+
10
+ def login(name)
11
+ @login = name
12
+ end
13
+
14
+ def has_logged_in?(name)
15
+ @login == name
16
+ end
17
+
18
+ def initialized_with?(credentials)
19
+ @credentials == credentials
20
+ end
21
+ end
22
+
23
+ class Service
24
+ Deject self
25
+ dependency(:client) { Client.new credentials }
26
+
27
+ attr_accessor :name
28
+
29
+ def initialize(name)
30
+ self.name = name
31
+ end
32
+
33
+ def login
34
+ client.login name
35
+ end
36
+
37
+ def credentials
38
+ 'skj123@#KLFNV9ajv' # a login key or something, would probably be dejected as well
39
+ end
40
+ end
41
+
42
+ # using the default
43
+ service = Service.new('josh')
44
+ service.login
45
+ service.client.should have_logged_in 'josh'
46
+ service.client.should be_initialized_with service.credentials
47
+
48
+ # overriding the default at instance level
49
+ client = double('Mock Client 1')
50
+ client.should_receive(:login).with('sally')
51
+ Service.new('sally').with_client(client).login
52
+
53
+ client_class, client = double, double
54
+ george = Service.new('george').with_client { client_class.new credentials }
55
+ client_class.should_receive(:new).with(george.credentials).and_return(client)
56
+ client.should_receive(:login).with('george')
57
+ george.login
58
+
59
+ # class default remains the same
60
+ Service.new('josh').client.should be_a_kind_of Client
61
+
62
+ # overriding the default at class level
63
+ client = double('Mock Client 2')
64
+ client.should_receive(:login).with('mei')
65
+ Service.dependency(:client) { client }
66
+ Service.new('mei').login
67
+ end
68
+
69
+ example 'avoid all dependencies by omitting the default' do
70
+ klass = Class.new do
71
+ Deject self
72
+ dependency :client
73
+ end
74
+ expect { klass.new.client }.to raise_error Deject::UninitializedDependency
75
+ client = double
76
+ klass.new.with_client(client).client.should be client
77
+ end
78
+ end
@@ -0,0 +1,41 @@
1
+ require 'deject'
2
+
3
+
4
+ describe 'Klass.dependency' do
5
+ let(:klass) { Deject Class.new }
6
+
7
+ before { klass.new.should_not respond_to :dependency }
8
+
9
+ context 'with a block' do
10
+ meth = 'meth'.freeze
11
+ result = 100
12
+ before { klass.dependency(meth) { result } }
13
+
14
+ it 'adds the instance method' do
15
+ klass.new.should respond_to meth
16
+ end
17
+
18
+ specify 'the instance method defaults to the result of the init block' do
19
+ klass.new.send(meth).should == result
20
+ end
21
+
22
+ specify 'the instance method is evaluated within the context of the instance' do
23
+ klass.dependency(:a) { b }
24
+ instance = klass.new
25
+ def instance.b() 10 end
26
+ instance.a.should == instance.b
27
+ end
28
+ end
29
+
30
+ context 'without a block' do
31
+ it 'adds the instance method' do
32
+ klass.dependency :abc
33
+ klass.new.should respond_to :abc
34
+ end
35
+
36
+ it 'raises an error if called before setting it' do
37
+ klass.dependency :jjjjj
38
+ expect { klass.new.jjjjj }.to raise_error(Deject::UninitializedDependency, /jjjjj/)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ require 'deject'
2
+
3
+ describe 'Deject()' do
4
+ let(:klass) { Class.new }
5
+
6
+ it 'adds the dependency method to the class' do
7
+ klass.should_not respond_to :dependency
8
+ Deject klass
9
+ klass.should respond_to :dependency
10
+ end
11
+
12
+ it 'returns the class' do
13
+ Deject(klass).should be klass
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ require 'deject'
2
+
3
+ describe 'after initializing a dependency' do
4
+ let(:klass) { Deject Class.new }
5
+
6
+ specify '#<dependency> returns the result, initialized for each instance' do
7
+ i = 0
8
+ klass.dependency(:number) { i += 1 }
9
+ klass.new.number.should == 1
10
+ klass.new.number.should == 2
11
+ end
12
+
13
+ it 'memoizes the result' do
14
+ i = 0
15
+ klass.dependency(:number) { i += 1 }
16
+ instance = klass.new
17
+ instance.number.should == 1
18
+ instance.number.should == 1
19
+ end
20
+
21
+ specify '#with_<dependency> overrides the result' do
22
+ klass.dependency(:number) { 5 }
23
+ klass.new.with_number(6).number.should == 6
24
+ end
25
+
26
+ specify '#with_<dependency> can take a value or an init block' do
27
+ klass.dependency(:number1) { 1 }
28
+ klass.dependency(:number2) { 2 }
29
+ i = 0
30
+ instance = klass.new.with_number2 { i += number1 }
31
+ instance.number2.should == instance.number1
32
+ instance.number2.should == instance.number1
33
+ i.should == instance.number1
34
+ end
35
+
36
+ example 'you can override multiple defaults from the instance level by using with_dependencies' do
37
+ klass = Class.new do
38
+ Deject self
39
+ dependency(:a) { 1 }
40
+ dependency(:b) { 2 }
41
+ end
42
+ instance = klass.new.with_dependencies(a: 10, b: 20)
43
+ instance.a.should == 10
44
+ instance.b.should == 20
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deject
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Cheek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70320438529780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70320438529780
25
+ - !ruby/object:Gem::Dependency
26
+ name: pry
27
+ requirement: &70320438528180 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70320438528180
36
+ description: Provides a super simple API for dependency injection
37
+ email:
38
+ - josh.cheek@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - Rakefile
46
+ - Readme.md
47
+ - deject.gemspec
48
+ - lib/deject.rb
49
+ - lib/deject/functional.rb
50
+ - lib/deject/object_oriented.rb
51
+ - lib/deject/version.rb
52
+ - spec/acceptance_spec.rb
53
+ - spec/class_methods_spec.rb
54
+ - spec/deject_function_spec.rb
55
+ - spec/instance_methods_spec.rb
56
+ homepage: ''
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: deject
76
+ rubygems_version: 1.8.10
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Simple dependency injection
80
+ test_files:
81
+ - spec/acceptance_spec.rb
82
+ - spec/class_methods_spec.rb
83
+ - spec/deject_function_spec.rb
84
+ - spec/instance_methods_spec.rb