dependor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +37 -0
- data/Guardfile +18 -0
- data/MIT-LICENSE +7 -0
- data/README.md +286 -0
- data/Rakefile +13 -0
- data/dependor.gemspec +28 -0
- data/lib/dependor.rb +13 -0
- data/lib/dependor/auto_inject.rb +35 -0
- data/lib/dependor/auto_injector.rb +37 -0
- data/lib/dependor/class_name_resolver.rb +30 -0
- data/lib/dependor/constructor.rb +13 -0
- data/lib/dependor/exceptions.rb +3 -0
- data/lib/dependor/injectable.rb +17 -0
- data/lib/dependor/instantiator.rb +14 -0
- data/lib/dependor/let.rb +7 -0
- data/lib/dependor/shorty.rb +13 -0
- data/lib/dependor/version.rb +3 -0
- data/spec/dependor/auto_inject_spec.rb +79 -0
- data/spec/dependor/class_name_resolver_spec.rb +43 -0
- data/spec/dependor/constructor_spec.rb +16 -0
- data/spec/dependor/injectable_spec.rb +63 -0
- data/spec/dependor/instantiator_spec.rb +37 -0
- data/spec/dependor/let_spec.rb +13 -0
- data/spec/dependor/shorty_spec.rb +33 -0
- data/spec/spec_helper.rb +10 -0
- metadata +136 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dependor (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
ffi (1.0.11)
|
11
|
+
growl (1.0.3)
|
12
|
+
guard (1.0.1)
|
13
|
+
ffi (>= 0.5.0)
|
14
|
+
thor (~> 0.14.6)
|
15
|
+
guard-rspec (0.6.0)
|
16
|
+
guard (>= 0.10.0)
|
17
|
+
libnotify (0.7.2)
|
18
|
+
rspec (2.5.0)
|
19
|
+
rspec-core (~> 2.5.0)
|
20
|
+
rspec-expectations (~> 2.5.0)
|
21
|
+
rspec-mocks (~> 2.5.0)
|
22
|
+
rspec-core (2.5.1)
|
23
|
+
rspec-expectations (2.5.0)
|
24
|
+
diff-lcs (~> 1.1.2)
|
25
|
+
rspec-mocks (2.5.0)
|
26
|
+
thor (0.14.6)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
dependor!
|
33
|
+
growl
|
34
|
+
guard
|
35
|
+
guard-rspec
|
36
|
+
libnotify
|
37
|
+
rspec
|
data/Guardfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
# Capybara request specs
|
17
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
18
|
+
end
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (C) 2012 Adam Pohorecki
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
# Dependor
|
2
|
+
|
3
|
+
[![build status](https://secure.travis-ci.org/psyho/dependor.png)](http://travis-ci.org/psyho/dependor)
|
4
|
+
|
5
|
+
## What is Dependor
|
6
|
+
|
7
|
+
Dependor is a set of helpers that make writing Ruby apps that use the dependency injection pattern easier.
|
8
|
+
It comes as a set of modules, which you can selectively add to your project.
|
9
|
+
It is designed do play nice with Rails and similar frameworks.
|
10
|
+
|
11
|
+
## Manual Dependency Injection
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class Foo
|
15
|
+
def do_foo
|
16
|
+
"foo"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Bar
|
21
|
+
def initialize(foo)
|
22
|
+
@foo = foo
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_bar
|
26
|
+
@foo.do_foo + "bar"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Injector
|
31
|
+
def foo
|
32
|
+
Foo.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def bar
|
36
|
+
Bar.new(foo)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class EntryPoint
|
41
|
+
def inject
|
42
|
+
@injector ||= Injector.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def bar
|
46
|
+
inject.bar
|
47
|
+
end
|
48
|
+
|
49
|
+
def run
|
50
|
+
bar.do_bar
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
EntryPoint.new.run
|
55
|
+
```
|
56
|
+
|
57
|
+
## The same thing with Dependor
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
require 'dependor'
|
61
|
+
require 'dependor/shorty'
|
62
|
+
|
63
|
+
class Foo
|
64
|
+
def do_foo
|
65
|
+
"foo"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Bar
|
70
|
+
takes :foo
|
71
|
+
|
72
|
+
def do_bar
|
73
|
+
@foo.do_foo + "bar"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Injector
|
78
|
+
include Dependor::AutoInject
|
79
|
+
end
|
80
|
+
|
81
|
+
class EntryPoint
|
82
|
+
include Dependor::Injectable
|
83
|
+
inject_from Injector
|
84
|
+
|
85
|
+
inject :bar
|
86
|
+
|
87
|
+
def run
|
88
|
+
bar.do_bar
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
EntryPoint.new.run
|
93
|
+
```
|
94
|
+
|
95
|
+
## Dependor::AutoInject
|
96
|
+
|
97
|
+
This is the core part of the library.
|
98
|
+
It looks at the constructor of a class to find out it's dependencies and instantiates it's instances with proper objects injected.
|
99
|
+
It looks up classes by name.
|
100
|
+
|
101
|
+
AutoInject can also use the methods declared on injector as injection sources, which is quite useful for things like configuration.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class Injector
|
105
|
+
include Dependor::AutoInject
|
106
|
+
|
107
|
+
attr_reader :session
|
108
|
+
|
109
|
+
def initialize(session)
|
110
|
+
@session = session
|
111
|
+
end
|
112
|
+
|
113
|
+
let(:current_user) { current_user_service.get }
|
114
|
+
let(:users_repository) { User }
|
115
|
+
let(:comments_repository) { Comment }
|
116
|
+
end
|
117
|
+
|
118
|
+
class CurrentUserService
|
119
|
+
takes :session, :users_repository
|
120
|
+
|
121
|
+
def get
|
122
|
+
@current_user ||= users_repository.find(session[:current_user_id])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class CreatesComments
|
127
|
+
takes :current_user, :comments_repository
|
128
|
+
|
129
|
+
def create
|
130
|
+
# ...
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class User < ActiveRecord::Base
|
135
|
+
end
|
136
|
+
|
137
|
+
class Comment < ActiveRecord::Base
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
## Dependor::Shorty
|
142
|
+
|
143
|
+
This makes the constructor definition less verbose and includes Dependor::Let for shorter method definition syntax.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
class Foo
|
147
|
+
takes :foo, :bar, :baz
|
148
|
+
let(:hello) { "world" }
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
is equivalent to:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class Foo
|
156
|
+
attr_reader :foo, :bar, :baz
|
157
|
+
|
158
|
+
def initialize(foo, bar, baz)
|
159
|
+
@foo = foo
|
160
|
+
@bar = bar
|
161
|
+
@baz = baz
|
162
|
+
end
|
163
|
+
|
164
|
+
def hello
|
165
|
+
"world"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
## Dependor::Constructor
|
171
|
+
|
172
|
+
Sometimes you don't want to pollute every class with a `takes` method.
|
173
|
+
You can then shorten the class declaration with Dependor::Constructor.
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
class Foo
|
177
|
+
include Dependor::Constructor(:foo, :bar, :baz)
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
is equivalent to:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class Foo
|
185
|
+
def initialize(foo, bar, baz)
|
186
|
+
@foo = foo
|
187
|
+
@bar = bar
|
188
|
+
@baz = baz
|
189
|
+
end
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
## Dependor::Let
|
194
|
+
|
195
|
+
It allows a simpler syntax to define getter methods.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
class Foo
|
199
|
+
def foo
|
200
|
+
do_something_or_other
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
becomes:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class Foo
|
209
|
+
extend Dependor::Let
|
210
|
+
let(:foo) { do_something_or_other }
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
## Dependor::Injectable
|
215
|
+
|
216
|
+
You can include this to make usage of the injector more convenient.
|
217
|
+
This is used in the entry point of your application, typically a Rails controller.
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
class MyInjector
|
221
|
+
def foo
|
222
|
+
"foo"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class ApplicationController
|
227
|
+
extend Dependor::Injectable
|
228
|
+
inject_from MyInjector
|
229
|
+
end
|
230
|
+
|
231
|
+
class PostsController < ApplicationController
|
232
|
+
inject :foo
|
233
|
+
|
234
|
+
def get
|
235
|
+
render text: foo
|
236
|
+
end
|
237
|
+
end
|
238
|
+
```
|
239
|
+
|
240
|
+
Sometimes you might want to pass request, params or session to your injector.
|
241
|
+
Here is an example, how to do it:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
require 'dependor/shorty'
|
245
|
+
|
246
|
+
class MyInjector
|
247
|
+
include Dependor::AutoInject
|
248
|
+
|
249
|
+
takes :params, :session, :request
|
250
|
+
|
251
|
+
def foo
|
252
|
+
session[:foo]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class ApplicationController
|
257
|
+
extend Dependor::Injectable
|
258
|
+
|
259
|
+
def injector
|
260
|
+
@injector ||= MyInjector.new(params, session, request)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class PostsController < ApplicationController
|
265
|
+
inject :foo
|
266
|
+
|
267
|
+
def get
|
268
|
+
render text: foo
|
269
|
+
end
|
270
|
+
end
|
271
|
+
```
|
272
|
+
|
273
|
+
## License
|
274
|
+
|
275
|
+
MIT. See the MIT-LICENSE file.
|
276
|
+
|
277
|
+
## Author
|
278
|
+
|
279
|
+
Adam Pohorecki
|
280
|
+
|
281
|
+
## Acknowledgements
|
282
|
+
|
283
|
+
Dependor::Shorty is inspired (or rather blatantly copied) from Gary Bernhardt's [Destroy All Software Screencast][das] ["Shorter Class Syntax"][shorter-syntax].
|
284
|
+
|
285
|
+
[das]: http://www.destroyallsoftware.com
|
286
|
+
[shorter-syntax]: https://www.destroyallsoftware.com/screencasts/catalog/shorter-class-syntax
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
desc "Run all specs"
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
9
|
+
t.pattern = "./spec/**/*_spec.rb"
|
10
|
+
t.rspec_opts = ["--profile --color --format=documentation"]
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
data/dependor.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "dependor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dependor"
|
7
|
+
s.version = Dependor::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Adam Pohorecki"]
|
10
|
+
s.email = ["adam@pohorecki.pl"]
|
11
|
+
s.homepage = "http://github.com/psyho/dependor"
|
12
|
+
s.summary = %q{A couple of classes and modules that simplify dependency injection in Ruby.}
|
13
|
+
s.description = %q{Dependor is not a framework for Dependency Injection, but something thatt reduces duplication a little bit when doing manual dependency injection in settings like Rails apps.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "dependor"
|
16
|
+
|
17
|
+
s.add_development_dependency 'rspec'
|
18
|
+
|
19
|
+
s.add_development_dependency 'guard'
|
20
|
+
s.add_development_dependency 'guard-rspec'
|
21
|
+
s.add_development_dependency 'growl'
|
22
|
+
s.add_development_dependency 'libnotify'
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
end
|
data/lib/dependor.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'dependor/constructor'
|
2
|
+
|
3
|
+
module Dependor
|
4
|
+
autoload :AutoInject, 'dependor/auto_inject'
|
5
|
+
autoload :AutoInjector, 'dependor/auto_injector'
|
6
|
+
autoload :ClassNameResolver, 'dependor/class_name_resolver'
|
7
|
+
autoload :Injectable, 'dependor/injectable'
|
8
|
+
autoload :Instantiator, 'dependor/instantiator'
|
9
|
+
autoload :Let, 'dependor/let'
|
10
|
+
autoload :Shorty, 'dependor/shorty'
|
11
|
+
autoload :UnknownObject, 'dependor/exceptions'
|
12
|
+
autoload :VERSION, 'dependor/version'
|
13
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Dependor
|
2
|
+
module AutoInject
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
def look_in_modules(*modules)
|
6
|
+
search_modules.concat(modules)
|
7
|
+
end
|
8
|
+
|
9
|
+
def search_modules
|
10
|
+
@search_modules ||= []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(klass)
|
15
|
+
klass.extend ClassMethods
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
auto_injector.get(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to?(name)
|
23
|
+
auto_injector.resolvable?(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def auto_injector
|
29
|
+
@auto_injector ||= Dependor::AutoInjector.new(self, self.class.search_modules)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dependor
|
2
|
+
class AutoInjector
|
3
|
+
|
4
|
+
def initialize(injector, search_modules)
|
5
|
+
@injector = injector
|
6
|
+
@instantiator = Instantiator.new(self)
|
7
|
+
@class_name_resolver = ClassNameResolver.new(search_modules)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(name)
|
11
|
+
ensure_resolvable!(name)
|
12
|
+
|
13
|
+
return @injector.send(name) if method_exists?(name)
|
14
|
+
|
15
|
+
klass = @class_name_resolver.for_name(name)
|
16
|
+
@instantiator.instantiate(klass)
|
17
|
+
end
|
18
|
+
|
19
|
+
def resolvable?(name)
|
20
|
+
method_exists?(name) || !!@class_name_resolver.for_name(name)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def ensure_resolvable!(name)
|
26
|
+
unless resolvable?(name)
|
27
|
+
raise UnknownObject.new("Injector does not know how to create object: #{name}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_exists?(name)
|
32
|
+
@injector.methods.include?(name)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Dependor
|
2
|
+
class ClassNameResolver
|
3
|
+
attr_reader :search_modules
|
4
|
+
|
5
|
+
def initialize(search_modules)
|
6
|
+
@search_modules = search_modules
|
7
|
+
end
|
8
|
+
|
9
|
+
def for_name(name)
|
10
|
+
class_name = camelize(name)
|
11
|
+
modules = search_modules.concat([Object])
|
12
|
+
klass = nil
|
13
|
+
|
14
|
+
modules.each do |mod|
|
15
|
+
klass = mod.const_get(class_name) rescue nil
|
16
|
+
break if klass
|
17
|
+
end
|
18
|
+
|
19
|
+
klass
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def camelize(symbol)
|
25
|
+
string = symbol.to_s
|
26
|
+
string = string.gsub(/_\w/) { |match| match[1].upcase }
|
27
|
+
return string.gsub(/^\w/) { |match| match.upcase }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Dependor
|
2
|
+
module Injectable
|
3
|
+
def inject_from(klass)
|
4
|
+
define_method :injector do
|
5
|
+
@injector ||= klass.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def inject(*names)
|
10
|
+
names.each do |name|
|
11
|
+
define_method name do
|
12
|
+
injector.send(name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Dependor
|
2
|
+
class Instantiator
|
3
|
+
def initialize(injector)
|
4
|
+
@injector = injector
|
5
|
+
end
|
6
|
+
|
7
|
+
def instantiate(klass)
|
8
|
+
params = klass.instance_method(:initialize).parameters
|
9
|
+
dependency_names = params.select{|type, name| type == :req}.map{|type, name| name}
|
10
|
+
dependencies = dependency_names.map{|name| @injector.get(name)}
|
11
|
+
return klass.new(*dependencies)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/dependor/let.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
require 'dependor/shorty'
|
4
|
+
|
5
|
+
describe Dependor::AutoInject do
|
6
|
+
class SampleClassWithNoDependencies
|
7
|
+
end
|
8
|
+
|
9
|
+
class SampleClassWithDependency
|
10
|
+
takes :sample_class_with_no_dependencies
|
11
|
+
end
|
12
|
+
|
13
|
+
class SampleClassWithManualDependency
|
14
|
+
takes :manual_dep
|
15
|
+
end
|
16
|
+
|
17
|
+
module SomeModule
|
18
|
+
class SampleClassWithinSomeModule
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SampleInjector
|
23
|
+
include Dependor::AutoInject
|
24
|
+
look_in_modules SomeModule
|
25
|
+
|
26
|
+
def manual_dep
|
27
|
+
"manual dep"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:injector) { SampleInjector.new }
|
32
|
+
|
33
|
+
shared_examples_for 'dependency injector' do
|
34
|
+
it 'responds to the object name' do
|
35
|
+
injector.should respond_to(object_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'creates the object' do
|
39
|
+
injector.send(object_name).should be_an_instance_of(object_class)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'no dependencies' do
|
44
|
+
let(:object_name) { :sample_class_with_no_dependencies }
|
45
|
+
let(:object_class) { SampleClassWithNoDependencies }
|
46
|
+
|
47
|
+
it_behaves_like 'dependency injector'
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'dependencies on other objects' do
|
51
|
+
let(:object_name) { :sample_class_with_dependency }
|
52
|
+
let(:object_class) { SampleClassWithDependency }
|
53
|
+
|
54
|
+
it_behaves_like 'dependency injector'
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'dependencies on objects returned by methods on the injector' do
|
58
|
+
let(:object_name) { :sample_class_with_manual_dependency }
|
59
|
+
let(:object_class) { SampleClassWithManualDependency }
|
60
|
+
|
61
|
+
it_behaves_like 'dependency injector'
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'dependencies from another module' do
|
65
|
+
let(:object_name) { :sample_class_within_some_module }
|
66
|
+
let(:object_class) { SomeModule::SampleClassWithinSomeModule }
|
67
|
+
|
68
|
+
it_behaves_like 'dependency injector'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "raises an error if the object is not found" do
|
72
|
+
proc{ injector.unknown_object }.should raise_exception(Dependor::UnknownObject)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'responds to regular methods on injector' do
|
76
|
+
injector.should respond_to(:manual_dep)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Dependor::ClassNameResolver do
|
4
|
+
class FooBarBaz
|
5
|
+
end
|
6
|
+
|
7
|
+
class FooBarBaz2
|
8
|
+
end
|
9
|
+
|
10
|
+
module Foo
|
11
|
+
class FooBarBaz
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Bar
|
16
|
+
class FooBarBaz
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns nil when the class could not be found" do
|
21
|
+
resolver = Dependor::ClassNameResolver.new([])
|
22
|
+
|
23
|
+
resolver.for_name(:something).should be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "uses global scope with no search_modules" do
|
27
|
+
resolver = Dependor::ClassNameResolver.new([])
|
28
|
+
|
29
|
+
resolver.for_name(:foo_bar_baz).should == FooBarBaz
|
30
|
+
end
|
31
|
+
|
32
|
+
it "searches modules in order specified" do
|
33
|
+
resolver = Dependor::ClassNameResolver.new([Foo, Bar])
|
34
|
+
|
35
|
+
resolver.for_name(:foo_bar_baz).should == Foo::FooBarBaz
|
36
|
+
end
|
37
|
+
|
38
|
+
it "searches in order specified, with the global scope last" do
|
39
|
+
resolver = Dependor::ClassNameResolver.new([Foo, Bar])
|
40
|
+
|
41
|
+
resolver.for_name(:foo_bar_baz_2).should == FooBarBaz2
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe 'Dependor::Constructor' do
|
4
|
+
class SampleClassUsingConstructor
|
5
|
+
include Dependor::Constructor(:foo, :bar, :baz)
|
6
|
+
|
7
|
+
def as_instance_variables
|
8
|
+
{foo: @foo, bar: @bar, baz: @baz}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'defines a constructor with given parameters' do
|
13
|
+
sample = SampleClassUsingConstructor.new('aaa', 'bbb', 'ccc')
|
14
|
+
sample.as_instance_variables.should == {foo: 'aaa', bar: 'bbb', baz: 'ccc'}
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Dependor::Injectable do
|
4
|
+
class SampleInjector
|
5
|
+
def foo
|
6
|
+
"foo"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class SampleInjectable
|
11
|
+
extend Dependor::Injectable
|
12
|
+
inject_from(SampleInjector)
|
13
|
+
|
14
|
+
inject :foo
|
15
|
+
|
16
|
+
def hello_foo
|
17
|
+
"hello #{foo}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class SampleInjectableWithoutAnInjector
|
22
|
+
extend Dependor::Injectable
|
23
|
+
|
24
|
+
inject :foo
|
25
|
+
|
26
|
+
def hello_foo
|
27
|
+
"hello #{foo}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "requires the class to provide injector method" do
|
32
|
+
injectable = SampleInjectableWithoutAnInjector.new
|
33
|
+
|
34
|
+
expect do
|
35
|
+
injectable.hello_foo
|
36
|
+
end.to raise_exception
|
37
|
+
end
|
38
|
+
|
39
|
+
it "uses the provided injector" do
|
40
|
+
injectable = SampleInjectable.new
|
41
|
+
|
42
|
+
injectable.hello_foo.should == 'hello foo'
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "typical Rails usage" do
|
46
|
+
class ApplicationController
|
47
|
+
extend Dependor::Injectable
|
48
|
+
inject_from SampleInjector
|
49
|
+
end
|
50
|
+
|
51
|
+
class PostsController < ApplicationController
|
52
|
+
inject :foo
|
53
|
+
|
54
|
+
def get
|
55
|
+
"render #{foo}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return foo value in child controller" do
|
60
|
+
PostsController.new.get.should == "render foo"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Dependor::Instantiator do
|
4
|
+
let(:injector) { stub(:injector) }
|
5
|
+
let(:instantiator) { Dependor::Instantiator.new(injector) }
|
6
|
+
|
7
|
+
it "instantiates objects with no-arg constructors" do
|
8
|
+
klass = Class.new do
|
9
|
+
def foo
|
10
|
+
"foo"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
instance = instantiator.instantiate(klass)
|
15
|
+
instance.foo.should == "foo"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "instantiates objects with constructors" do
|
19
|
+
klass = Class.new do
|
20
|
+
def initialize(foo, bar, baz)
|
21
|
+
@foo = [foo, bar, baz].join('-')
|
22
|
+
end
|
23
|
+
|
24
|
+
def foo
|
25
|
+
@foo
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
injector.should_receive(:get).with(:foo).and_return("foo")
|
30
|
+
injector.should_receive(:get).with(:bar).and_return("bar")
|
31
|
+
injector.should_receive(:get).with(:baz).and_return("baz")
|
32
|
+
|
33
|
+
instance = instantiator.instantiate(klass)
|
34
|
+
|
35
|
+
instance.foo.should == 'foo-bar-baz'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
require 'dependor/shorty'
|
4
|
+
|
5
|
+
describe Dependor::Shorty do
|
6
|
+
class SampleClassThatUsesTakes
|
7
|
+
takes :foo, :bar, :baz
|
8
|
+
|
9
|
+
def as_instance_variables
|
10
|
+
{foo: @foo, bar: @bar, baz: @baz}
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_attributes
|
14
|
+
{foo: foo, bar: bar, baz: baz}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
subject{ SampleClassThatUsesTakes.new('foo value', 'bar value', 'baz value') }
|
19
|
+
|
20
|
+
it 'defines a constructor with given names' do
|
21
|
+
subject.as_instance_variables.should == { foo: 'foo value',
|
22
|
+
bar: 'bar value',
|
23
|
+
baz: 'baz value'
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'defines attr_reader for the given names' do
|
28
|
+
subject.as_attributes.should == { foo: 'foo value',
|
29
|
+
bar: 'bar value',
|
30
|
+
baz: 'baz value'
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dependor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Adam Pohorecki
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &71879150 !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: *71879150
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard
|
27
|
+
requirement: &71878830 !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: *71878830
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: guard-rspec
|
38
|
+
requirement: &71878470 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *71878470
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: growl
|
49
|
+
requirement: &71878150 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *71878150
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: libnotify
|
60
|
+
requirement: &71877780 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *71877780
|
69
|
+
description: Dependor is not a framework for Dependency Injection, but something thatt
|
70
|
+
reduces duplication a little bit when doing manual dependency injection in settings
|
71
|
+
like Rails apps.
|
72
|
+
email:
|
73
|
+
- adam@pohorecki.pl
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- .travis.yml
|
80
|
+
- Gemfile
|
81
|
+
- Gemfile.lock
|
82
|
+
- Guardfile
|
83
|
+
- MIT-LICENSE
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- dependor.gemspec
|
87
|
+
- lib/dependor.rb
|
88
|
+
- lib/dependor/auto_inject.rb
|
89
|
+
- lib/dependor/auto_injector.rb
|
90
|
+
- lib/dependor/class_name_resolver.rb
|
91
|
+
- lib/dependor/constructor.rb
|
92
|
+
- lib/dependor/exceptions.rb
|
93
|
+
- lib/dependor/injectable.rb
|
94
|
+
- lib/dependor/instantiator.rb
|
95
|
+
- lib/dependor/let.rb
|
96
|
+
- lib/dependor/shorty.rb
|
97
|
+
- lib/dependor/version.rb
|
98
|
+
- spec/dependor/auto_inject_spec.rb
|
99
|
+
- spec/dependor/class_name_resolver_spec.rb
|
100
|
+
- spec/dependor/constructor_spec.rb
|
101
|
+
- spec/dependor/injectable_spec.rb
|
102
|
+
- spec/dependor/instantiator_spec.rb
|
103
|
+
- spec/dependor/let_spec.rb
|
104
|
+
- spec/dependor/shorty_spec.rb
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
homepage: http://github.com/psyho/dependor
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
segments:
|
119
|
+
- 0
|
120
|
+
hash: 637782349
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
hash: 637782349
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project: dependor
|
132
|
+
rubygems_version: 1.8.10
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: A couple of classes and modules that simplify dependency injection in Ruby.
|
136
|
+
test_files: []
|