diftw 0.4.0 → 1.0.0.pre.rc1
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.
- 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:
|