diftw 0.4.0 → 1.0.0.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -21
- data/lib/diftw.rb +1 -0
- data/lib/diftw/dependency.rb +38 -0
- data/lib/diftw/injector.rb +26 -64
- data/lib/diftw/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cdc890fe9de411546dd8cdee3cbf7c7e3002475
|
4
|
+
data.tar.gz: 2eb8aeebfdc305b91a06f260e4eef43fb917c2e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d9f306c34f9870f76f8ebcba3d3fef1602fee927ca819499730cd8edddc0bd19c455abca01e46808965f3c46c94d3e9fe85b76c5f972ff44fc799d153cd5e6d
|
7
|
+
data.tar.gz: 677d79d8e34c7e9388a0757616666430be7fc5be9a5452bf9d35c81cd9bbba45f8166373f7bea268f9827599a9c0637d9f7315eeb9c3d0396c6241067b050d32
|
data/README.md
CHANGED
@@ -2,24 +2,22 @@
|
|
2
2
|
|
3
3
|
Dependency Injection For The Win! A small, yet surprisingly powerful, dependency injection library for Ruby.
|
4
4
|
|
5
|
-
**NOTE** This library is pre-1.0 and under active development. It's perfectly usable, but expect breaking API or behavior changes until 1.0.
|
6
|
-
|
7
5
|
### Why DI in Ruby?
|
8
6
|
|
9
7
|
If your only concern is testing, mocks/stubs and `webmock` might be all you need. But if you're working on a large project that hooks into all kinds of enterprisey services, and those services aren't always available in dev/testing/staging, a dash of DI might be just the thing.
|
10
8
|
|
11
9
|
### Features
|
12
10
|
|
13
|
-
*
|
11
|
+
* DI container w/dead-simple registration
|
14
12
|
* Lazy injection (by default)
|
15
|
-
* Inject into
|
16
|
-
*
|
13
|
+
* Inject into each of a class's instances, a single instance, a class itself, or a module
|
14
|
+
* Optionally injects singletons
|
17
15
|
* Uses parent-child injectors for max flexibility
|
18
16
|
* Threadsafe, except for registration
|
19
17
|
|
20
18
|
## Dead-simple registration API
|
21
19
|
|
22
|
-
# Create your root injector
|
20
|
+
# Create your root injector/container
|
23
21
|
DI = DiFtw::Injector.new do
|
24
22
|
# Register some dependencies in here
|
25
23
|
register :foo do
|
@@ -88,18 +86,16 @@ Lazy injection is usually fine. But if it isn't, use `inject!`:
|
|
88
86
|
puts SomeModule.baz.message
|
89
87
|
=> 'Baz'
|
90
88
|
|
91
|
-
##
|
89
|
+
## Optionally injects singletons
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
91
|
+
DI = DiFtw::Injector.new do
|
92
|
+
singleton :bar do
|
93
|
+
OpenStruct.new(message: 'Bar')
|
94
|
+
end
|
95
|
+
end
|
97
96
|
|
98
|
-
DI = DiFtw::Injector.new(singleton: false)
|
99
|
-
DI[:bar] = -> { OpenStruct.new(message: 'Bar') }
|
100
|
-
...
|
101
97
|
Widget.new.bar.object_id == Widget.new.bar.object_id
|
102
|
-
=>
|
98
|
+
=> true
|
103
99
|
|
104
100
|
Accessing injected singletons **is thread safe**. However, registering them is not.
|
105
101
|
|
@@ -107,7 +103,7 @@ Accessing injected singletons **is thread safe**. However, registering them is n
|
|
107
103
|
|
108
104
|
This is **maybe the coolest part**. Each time you call `inject` (or `inject_instance`) you're creating a fresh, empty child `DiFtw::Injector`. It will recursively look up dependencies through the parent chain until it finds the nearest registration of that dependency.
|
109
105
|
|
110
|
-
This means you can re-register a dependency on
|
106
|
+
This means you can re-register a dependency on a child injector, and *it* will be injected instead of whatever is registered above it in the chain.
|
111
107
|
|
112
108
|
# Create your root injector and register :foo
|
113
109
|
DI = DiFtw::Injector.new
|
@@ -173,11 +169,7 @@ To inject different dependencies in these environments, you have several options
|
|
173
169
|
|
174
170
|
DI[:foo] = -> { OpenStruct.new(message: 'Test Foo') }
|
175
171
|
|
176
|
-
And you can use the parent-child injector features described above
|
177
|
-
|
178
|
-
### Injecting in before(:each)
|
179
|
-
|
180
|
-
If you want to re-inject something into a class's injector in something like rspec's `before(:each)`:
|
172
|
+
And/Or you can use the parent-child injector features described above to great effect:
|
181
173
|
|
182
174
|
before :each do
|
183
175
|
# Give all MyService instances 'Test foo' as #foo
|
data/lib/diftw.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
module DiFtw
|
2
|
+
#
|
3
|
+
# Class representing an injected dependency.
|
4
|
+
#
|
5
|
+
class Dependency
|
6
|
+
# @return [Proc] proc that returns the dependency
|
7
|
+
attr_reader :y
|
8
|
+
# @return [Boolean] whether or not this depdency is a singleton
|
9
|
+
attr_reader :singleton
|
10
|
+
# @return [Mutex] the mutex for accessing the Singleton
|
11
|
+
attr_reader :mutex
|
12
|
+
|
13
|
+
#
|
14
|
+
# A new dependency.
|
15
|
+
#
|
16
|
+
# @param y [Proc] returns the dependency
|
17
|
+
# @param singleton [Boolean] if true, the Proc will only be called the first time the dep is injected.
|
18
|
+
#
|
19
|
+
def initialize(y, singleton:)
|
20
|
+
@y = y
|
21
|
+
@singleton = singleton
|
22
|
+
@mutex = Mutex.new if singleton
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Return the value for the dependency. If this is a singleton, the value will
|
27
|
+
# only be initialized on the first call (thread safe). Otherwise, the proc will
|
28
|
+
# called each time.
|
29
|
+
#
|
30
|
+
def resolve
|
31
|
+
if singleton
|
32
|
+
@val || mutex.synchronize { @val ||= y.() }
|
33
|
+
else
|
34
|
+
y.()
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/diftw/injector.rb
CHANGED
@@ -28,14 +28,10 @@ module DiFtw
|
|
28
28
|
class Injector
|
29
29
|
# @return [DiFtw::Injector] The parent injector, if any
|
30
30
|
attr_reader :parent
|
31
|
-
# @return [Boolean] If true, the Injector injects singleton objects
|
32
|
-
attr_reader :singleton
|
33
31
|
# @return [Hash] A Hash containing all registered depencies (as procs) keyed by Symbols
|
34
32
|
attr_reader :registry
|
35
|
-
# @return [Hash] A Hash containing a Mutex for each dependency (only if singleton == true)
|
36
|
-
attr_reader :mutexes
|
37
33
|
|
38
|
-
protected :registry
|
34
|
+
protected :registry
|
39
35
|
private :parent
|
40
36
|
|
41
37
|
#
|
@@ -43,14 +39,8 @@ module DiFtw
|
|
43
39
|
#
|
44
40
|
# DI = DiFtw::Injector.new
|
45
41
|
#
|
46
|
-
|
47
|
-
#
|
48
|
-
def initialize(singleton: true, parent: nil, ®istrator)
|
42
|
+
def initialize(parent: nil, ®istrator)
|
49
43
|
@registry, @parent = {}, parent
|
50
|
-
@singleton = parent ? parent.singleton : singleton
|
51
|
-
@mutexes = (parent ? parent.mutexes.keys : []).
|
52
|
-
inject({}) { |a, name| a[name] = Mutex.new; a }
|
53
|
-
@metamutex = Mutex.new
|
54
44
|
instance_eval ®istrator if registrator
|
55
45
|
end
|
56
46
|
|
@@ -68,45 +58,47 @@ module DiFtw
|
|
68
58
|
# @return [DiFtw::Injector] returns the Injector object
|
69
59
|
#
|
70
60
|
def register(name, y = nil, &block)
|
71
|
-
registry[name] = y || block
|
72
|
-
if singleton
|
73
|
-
instance_variable_set "@_singleton_#{name}", nil
|
74
|
-
mutexes[name] ||= Mutex.new
|
75
|
-
end
|
61
|
+
registry[name] = Dependency.new(y || block, singleton: false)
|
76
62
|
self
|
77
63
|
end
|
78
64
|
|
79
65
|
#
|
80
|
-
# Register a new dependency
|
66
|
+
# Register a new dependency as a singleton. The proc will only be called
|
67
|
+
# the first time, then the returned value will be stored and returned for
|
68
|
+
# subsequent injections. Threadsafe.
|
69
|
+
#
|
70
|
+
# DI.singleton :foo do
|
71
|
+
# Foo
|
72
|
+
# end
|
81
73
|
#
|
82
|
-
# DI
|
74
|
+
# DI.singleton :bar, -> { Bar }
|
83
75
|
#
|
84
76
|
# @param name [Symbol] name of the dependency
|
85
|
-
# @param y [Proc] the dependency wrapped in a Proc
|
86
|
-
#
|
87
|
-
|
88
|
-
|
77
|
+
# @param y [Proc] the dependency wrapped in a Proc or block
|
78
|
+
# @return [DiFtw::Injector] returns the Injector object
|
79
|
+
#
|
80
|
+
def singleton(name, y = nil, &block)
|
81
|
+
registry[name] = Dependency.new(y || block, singleton: true)
|
82
|
+
self
|
89
83
|
end
|
90
84
|
|
91
85
|
#
|
92
|
-
# Fetches a dependency by name (calls the Proc/block).
|
93
|
-
# the same object will be returned each time. Otherwise a new one will be returned each time.
|
94
|
-
#
|
95
|
-
# An application will probably never want to call this directly.
|
86
|
+
# Fetches a dependency by name (calls the Proc/block).
|
96
87
|
#
|
97
88
|
# @return whatever the Proc/block returns
|
98
89
|
#
|
99
|
-
def
|
100
|
-
if
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
}
|
90
|
+
def fetch(name)
|
91
|
+
if parent.nil?
|
92
|
+
registry.fetch(name).resolve
|
93
|
+
elsif registry.has_key? name
|
94
|
+
registry[name].resolve
|
105
95
|
else
|
106
|
-
|
96
|
+
parent[name]
|
107
97
|
end
|
108
98
|
end
|
109
99
|
|
100
|
+
alias_method :[], :fetch
|
101
|
+
|
110
102
|
#
|
111
103
|
# Unregisters the dependency from this injector instance. This means requests for this dependency
|
112
104
|
# will continue on up the chain.
|
@@ -116,9 +108,6 @@ module DiFtw
|
|
116
108
|
#
|
117
109
|
def delete(name)
|
118
110
|
registry.delete name
|
119
|
-
if singleton
|
120
|
-
instance_variable_set "@_singleton_#{name}", nil
|
121
|
-
end
|
122
111
|
self
|
123
112
|
end
|
124
113
|
|
@@ -155,32 +144,5 @@ module DiFtw
|
|
155
144
|
mod = DiFtw::Builder.injector_module self, dependencies
|
156
145
|
instance.singleton_class.send :include, mod
|
157
146
|
end
|
158
|
-
|
159
|
-
protected
|
160
|
-
|
161
|
-
#
|
162
|
-
# Recursively look up a dependency
|
163
|
-
#
|
164
|
-
# @param dependency [Symbol] name of dependency
|
165
|
-
# @return [Proc]
|
166
|
-
#
|
167
|
-
def resolve!(dependency)
|
168
|
-
if parent.nil?
|
169
|
-
registry.fetch(dependency).call
|
170
|
-
elsif registry.has_key? dependency
|
171
|
-
registry[dependency].call
|
172
|
-
else
|
173
|
-
parent[dependency]
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def mutex(name)
|
180
|
-
return mutexes[name] unless mutexes[name].nil?
|
181
|
-
@metamutex.synchronize {
|
182
|
-
mutexes[name] = Mutex.new
|
183
|
-
}
|
184
|
-
end
|
185
147
|
end
|
186
148
|
end
|
data/lib/diftw/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: diftw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Hollinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A small dependency injection library for Ruby
|
14
14
|
email: jordan.hollinger@gmail.com
|
@@ -20,6 +20,7 @@ files:
|
|
20
20
|
- README.md
|
21
21
|
- lib/diftw.rb
|
22
22
|
- lib/diftw/builder.rb
|
23
|
+
- lib/diftw/dependency.rb
|
23
24
|
- lib/diftw/injector.rb
|
24
25
|
- lib/diftw/version.rb
|
25
26
|
homepage: https://github.com/jhollinger/ruby-diftw
|
@@ -37,14 +38,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
37
38
|
version: 2.0.0
|
38
39
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
40
|
requirements:
|
40
|
-
- - "
|
41
|
+
- - ">"
|
41
42
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
43
|
+
version: 1.3.1
|
43
44
|
requirements: []
|
44
45
|
rubyforge_project:
|
45
|
-
rubygems_version: 2.
|
46
|
+
rubygems_version: 2.5.2
|
46
47
|
signing_key:
|
47
48
|
specification_version: 4
|
48
49
|
summary: Dependency Injection For The Win!
|
49
50
|
test_files: []
|
50
|
-
has_rdoc:
|