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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 003ba4d7dfddcf1130c2dcc1a82b398265af7c5e
4
- data.tar.gz: 290586529ebe1c70de998696f182c06cd6251a07
3
+ metadata.gz: 2cdc890fe9de411546dd8cdee3cbf7c7e3002475
4
+ data.tar.gz: 2eb8aeebfdc305b91a06f260e4eef43fb917c2e4
5
5
  SHA512:
6
- metadata.gz: 34f2a2827ee113f6e847318c2b5315d25109901727c0a743fff22b07953aae7fdf4efb1e0300658b5dd3a784101e008469cd90d88d50e79747101df09284b09e
7
- data.tar.gz: 6ddc67b51453af2ccc8b29ae2712c06b27c704716af93f2435e5bfc12ea476792b0b1a6acfd194995f36c54e15c7e3aa3668a1938f320d0cd254bef9e9007f6b
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
- * Dead-simple registration API
11
+ * DI container w/dead-simple registration
14
12
  * Lazy injection (by default)
15
- * Inject into all instances, a single instance, a class, or a module
16
- * Injects singletons (by default)
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
- ## Injects singletons (by default)
89
+ ## Optionally injects singletons
92
90
 
93
- Widget.new.bar.object_id == Widget.new.bar.object_id
94
- => true
95
-
96
- If you *don't* want your injector to return singletons (i.e. get a new copy each time you inject something), initialize your injector like this:
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
- => false
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 your child injector, and *it* will be injected instead of whatever is registered above it in the chain. Objects using sibling or parent injectors will remain unchanged, as they won't know about this registration override. Perhaps some examples are best.
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
@@ -1,3 +1,4 @@
1
1
  require 'diftw/injector'
2
+ require 'diftw/dependency'
2
3
  require 'diftw/builder'
3
4
  require 'diftw/version'
@@ -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
@@ -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, :mutexes
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
- # @param singleton [Boolean] If true, each dependency will only be initialized once. When false, it will be initialized each time it's injected.
47
- #
48
- def initialize(singleton: true, parent: nil, &registrator)
42
+ def initialize(parent: nil, &registrator)
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 &registrator 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 by passing a Proc or a block.
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[:foo] = -> { Foo }
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
- def []=(name, y)
88
- register name, y
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). If this is a Singleton injector,
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 [](name)
100
- if singleton
101
- var = "@_singleton_#{name}"
102
- instance_variable_get(var) || mutex(name).synchronize {
103
- instance_variable_get(var) || instance_variable_set(var, resolve!(name))
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
- resolve! name
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
@@ -1,4 +1,4 @@
1
1
  module DiFtw
2
2
  # Library version
3
- VERSION = '0.4.0'.freeze
3
+ VERSION = '1.0.0-rc1'.freeze
4
4
  end
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.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: 2016-07-25 00:00:00.000000000 Z
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: '0'
43
+ version: 1.3.1
43
44
  requirements: []
44
45
  rubyforge_project:
45
- rubygems_version: 2.4.5.1
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: