needle 0.5.0 → 0.6.0
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/benchmarks/instantiability.rb +26 -0
- data/benchmarks/instantiation.rb +33 -0
- data/benchmarks/interceptors.rb +42 -0
- data/benchmarks/interceptors2.rb +70 -0
- data/doc/README +3 -1
- data/doc/di-in-ruby.rdoc +201 -0
- data/doc/images/di_classdiagram.jpg +0 -0
- data/doc/manual/manual.yml +4 -0
- data/doc/manual/parts/01_alternatives.txt +11 -0
- data/doc/manual/parts/02_creating.txt +20 -0
- data/doc/manual/parts/02_namespaces.txt +1 -1
- data/doc/manual/parts/02_services.txt +15 -3
- data/doc/manual-html/chapter-1.html +34 -7
- data/doc/manual-html/chapter-2.html +43 -9
- data/doc/manual-html/chapter-3.html +6 -4
- data/doc/manual-html/chapter-4.html +6 -4
- data/doc/manual-html/chapter-5.html +6 -4
- data/doc/manual-html/chapter-6.html +6 -4
- data/doc/manual-html/chapter-7.html +6 -4
- data/doc/manual-html/index.html +19 -4
- data/lib/needle/container.rb +104 -66
- data/{test/tc_models.rb → lib/needle/lifecycle/deferred.rb} +14 -20
- data/lib/needle/lifecycle/initialize.rb +49 -0
- data/lib/needle/{models → lifecycle}/proxy.rb +16 -8
- data/lib/needle/lifecycle/singleton.rb +63 -0
- data/lib/needle/lifecycle/threaded.rb +58 -0
- data/lib/needle/pipeline/collection.rb +133 -0
- data/lib/needle/pipeline/element.rb +85 -0
- data/lib/needle/pipeline/interceptor.rb +46 -0
- data/lib/needle/registry.rb +48 -8
- data/lib/needle/service-point.rb +36 -39
- data/lib/needle/thread.rb +87 -0
- data/lib/needle/version.rb +1 -1
- data/{lib/needle/models/prototype.rb → test/lifecycle/tc_deferred.rb} +15 -17
- data/test/lifecycle/tc_initialize.rb +62 -0
- data/test/{models → lifecycle}/tc_proxy.rb +5 -5
- data/test/lifecycle/tc_singleton.rb +32 -0
- data/{lib/needle/models/prototype-deferred.rb → test/lifecycle/tc_threaded.rb} +24 -18
- data/test/models/model_test.rb +131 -0
- data/test/models/tc_prototype.rb +9 -30
- data/test/models/tc_prototype_deferred.rb +9 -31
- data/test/models/tc_prototype_deferred_initialize.rb +32 -0
- data/test/models/tc_prototype_initialize.rb +32 -0
- data/test/models/tc_singleton.rb +8 -29
- data/test/models/tc_singleton_deferred.rb +8 -30
- data/test/models/tc_singleton_deferred_initialize.rb +32 -0
- data/test/models/tc_singleton_initialize.rb +32 -0
- data/test/models/tc_threaded.rb +32 -0
- data/test/models/tc_threaded_deferred.rb +32 -0
- data/test/models/tc_threaded_deferred_initialize.rb +32 -0
- data/test/models/tc_threaded_initialize.rb +32 -0
- data/test/pipeline/tc_collection.rb +116 -0
- data/test/pipeline/tc_element.rb +72 -0
- data/test/tc_container.rb +77 -36
- data/test/tc_logger.rb +5 -0
- data/test/tc_registry.rb +39 -1
- data/test/tc_service_point.rb +43 -7
- metadata +39 -12
- data/lib/needle/models/singleton-deferred.rb +0 -57
- data/lib/needle/models/singleton.rb +0 -56
- data/lib/needle/models.rb +0 -44
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -177,7 +179,27 @@
|
|
177
179
|
registry = Needle::Registry.new
|
178
180
|
</pre>
|
179
181
|
|
180
|
-
<p>Once you have the reference to the registry, you can register services with it, create new namespaces in it, and so forth
|
182
|
+
<p>Once you have the reference to the registry, you can register services with it, create new namespaces in it, and so forth.</p>
|
183
|
+
|
184
|
+
<p>Alternatively, you can pass a block to <code>#new</code>:</p>
|
185
|
+
|
186
|
+
<pre>
|
187
|
+
registry = Needle::Registry.new do |r|
|
188
|
+
...
|
189
|
+
end
|
190
|
+
</pre>
|
191
|
+
|
192
|
+
<p>The parameter to the block will be a reference to the registry. This allows you to register services with the registry as soon as it is created.</p>
|
193
|
+
|
194
|
+
<p>One other convenience method is <code>#new!</code>:</p>
|
195
|
+
|
196
|
+
<pre>
|
197
|
+
registry = Needle::Registry.new! do
|
198
|
+
...
|
199
|
+
end
|
200
|
+
</pre>
|
201
|
+
|
202
|
+
<p>This block accepts no parameters, and evaluates the block as if it were passed to <code>Registry#define!</code> (see below).<br />
|
181
203
|
</p>
|
182
204
|
</div>
|
183
205
|
|
@@ -211,17 +233,29 @@
|
|
211
233
|
|
212
234
|
<h3>Convenience Methods</h3>
|
213
235
|
|
214
|
-
<p>Because you will often need to register many services with a registry at once,
|
236
|
+
<p>Because you will often need to register many services with a registry at once, two convenience methods have been provided to make this use case lean and mean.</p>
|
237
|
+
|
238
|
+
<p>The first is <code>define</code>. Just pass a block to define that accepts one parameter. This parameter will be a “builder” object that allows you to define services just by sending them as messages to the builder:</p>
|
239
|
+
|
240
|
+
<pre>
|
241
|
+
registry.define do |b|
|
242
|
+
b.foo { Bar.new }
|
243
|
+
b.bar { Foo.new }
|
244
|
+
...
|
245
|
+
end
|
246
|
+
</pre>
|
247
|
+
|
248
|
+
<p>Alternative, you can call <code>define!</code>, passing a block that accepts no parameters. This block will be evaluated in the “builder” object’s context, with any unrecognized method call being interpreted as a new service registration of that name:</p>
|
215
249
|
|
216
250
|
<pre>
|
217
|
-
registry.
|
251
|
+
registry.define! do
|
218
252
|
foo { Bar.new }
|
219
253
|
bar { Foo.new }
|
220
254
|
...
|
221
255
|
end
|
222
256
|
</pre>
|
223
257
|
|
224
|
-
<p>
|
258
|
+
<p>Both of the above will register two new services with the registry, <code>:foo</code> and <code>:bar</code>.</p>
|
225
259
|
|
226
260
|
<h3>Default Lifecycle</h3>
|
227
261
|
|
@@ -287,7 +321,7 @@
|
|
287
321
|
end
|
288
322
|
</pre>
|
289
323
|
|
290
|
-
<p>And, to mirror the <code>
|
324
|
+
<p>And, to mirror the <code>namespace</code> method, there is also a <code>namespace!</code> method. This method creates a new namespace and then does a <code>define!</code> call on that namespace.</p>
|
291
325
|
|
292
326
|
<pre>
|
293
327
|
registry.namespace! :stuff do
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
data/doc/manual-html/index.html
CHANGED
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>0.
|
18
|
-
Manual Last Updated: <strong>2004-10-
|
17
|
+
Needle Version: <strong>0.6.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-10-21 16:17 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -41,9 +41,11 @@
|
|
41
41
|
|
42
42
|
<li><a href="chapter-1.html#s2">How Can It Help Me?</a></li>
|
43
43
|
|
44
|
-
<li><a href="chapter-1.html#s3">
|
44
|
+
<li><a href="chapter-1.html#s3">Alternatives</a></li>
|
45
45
|
|
46
|
-
<li><a href="chapter-1.html#s4">
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
47
49
|
|
48
50
|
</ol>
|
49
51
|
</li>
|
@@ -161,6 +163,19 @@
|
|
161
163
|
</p>
|
162
164
|
|
163
165
|
|
166
|
+
<p align="center"><strong>Recent Updates to This Manual</strong></p>
|
167
|
+
<table border='0' cellpadding='0' cellspacing='0' align='center'><tr><td>
|
168
|
+
<ul>
|
169
|
+
|
170
|
+
<li>added Container#define</li>
|
171
|
+
|
172
|
+
<li>renamed Container#register! to Container#define!</li>
|
173
|
+
|
174
|
+
<li>added documentation of Container#new!</li>
|
175
|
+
|
176
|
+
</ul>
|
177
|
+
</table>
|
178
|
+
|
164
179
|
|
165
180
|
<p class="copyright">
|
166
181
|
Copyright © 2004
|
data/lib/needle/container.rb
CHANGED
@@ -30,13 +30,13 @@ module Needle
|
|
30
30
|
# Container#namespace method to create new containers.
|
31
31
|
class Container
|
32
32
|
|
33
|
-
# This class is used by the #
|
33
|
+
# This class is used by the #define! and #namespace! methods to allow
|
34
34
|
# an +instance_eval+'d block to create new service points simply by
|
35
35
|
# invoking imaginary methods. It is basically an empty shell, with almost
|
36
36
|
# all of the builtin methods removed from it. (This allows services like
|
37
37
|
# "hash" and "print" to be defined, where they would normally conflict
|
38
38
|
# with the Kernel methods of the same name.)
|
39
|
-
class
|
39
|
+
class DefinitionContext
|
40
40
|
( private_instance_methods +
|
41
41
|
protected_instance_methods +
|
42
42
|
public_instance_methods -
|
@@ -45,24 +45,33 @@ module Needle
|
|
45
45
|
).
|
46
46
|
each { |m| undef_method m }
|
47
47
|
|
48
|
-
# Create a new
|
48
|
+
# Create a new DefinitionContext that wraps the given container. All
|
49
49
|
# operations performed on this context will be delegated to the
|
50
50
|
# container.
|
51
51
|
def initialize( container )
|
52
52
|
@container = container
|
53
53
|
end
|
54
54
|
|
55
|
+
# A way to access the container reference being operated on from within
|
56
|
+
# the context.
|
57
|
+
def this_container
|
58
|
+
@container
|
59
|
+
end
|
60
|
+
|
55
61
|
# Delegate to Container#intercept.
|
56
62
|
def intercept( name )
|
57
63
|
@container.intercept( name )
|
58
64
|
end
|
59
65
|
|
60
|
-
# Delegate to Container#namespace
|
61
|
-
#
|
62
|
-
#
|
63
|
-
# within the context of a bang method (like Container#register!), it felt
|
64
|
-
# redundant to have the bang here as well. Disagree? Let me know.
|
66
|
+
# Delegate to Container#namespace. Instead of passing the container to
|
67
|
+
# the new namespace, however, pass the definition context for the new
|
68
|
+
# container.
|
65
69
|
def namespace( *parms, &block )
|
70
|
+
@container.namespace( *parms ) { |ns| block.call( ns.builder ) }
|
71
|
+
end
|
72
|
+
|
73
|
+
# Delegate to Container#namespace!.
|
74
|
+
def namespace!( *parms, &block )
|
66
75
|
@container.namespace!( *parms, &block )
|
67
76
|
end
|
68
77
|
|
@@ -96,6 +105,7 @@ module Needle
|
|
96
105
|
# Create a new empty container with the given parent and name.
|
97
106
|
def initialize( parent=nil, name=nil )
|
98
107
|
@root = nil
|
108
|
+
@builder = nil
|
99
109
|
|
100
110
|
@name = name
|
101
111
|
@parent = parent
|
@@ -119,49 +129,66 @@ module Needle
|
|
119
129
|
"#{@parent.fullname}.#{@name}"
|
120
130
|
end
|
121
131
|
|
122
|
-
#
|
123
|
-
#
|
124
|
-
|
132
|
+
# Returns the DefinitionContext instance that can be used to "build"
|
133
|
+
# this container.
|
134
|
+
def builder
|
135
|
+
@builder ||= DefinitionContext.new( self )
|
136
|
+
end
|
137
|
+
|
138
|
+
# If a block is given, yields the container's builder instance to the
|
139
|
+
# block. Otherwise, simply returns the builder instance.
|
125
140
|
#
|
126
141
|
# Usage:
|
127
142
|
#
|
128
|
-
# container.
|
129
|
-
#
|
143
|
+
# container.define do |b|
|
144
|
+
# b.foo { Bar.new }
|
145
|
+
# b.baz { Baz.new }
|
146
|
+
# ...
|
130
147
|
# end
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
148
|
+
#
|
149
|
+
# Or:
|
150
|
+
#
|
151
|
+
# container.define.foo { Bar.new }
|
152
|
+
# container.define.baz { Baz.new }
|
153
|
+
def define
|
154
|
+
yield builder if block_given?
|
155
|
+
builder
|
136
156
|
end
|
137
157
|
|
138
|
-
# Create a new
|
158
|
+
# Create a new DefinitionContext around the container, and then evaluate
|
139
159
|
# the block within the new context instance (via +instance_eval+).
|
140
160
|
#
|
141
161
|
# Usage:
|
142
162
|
#
|
143
|
-
# container.
|
163
|
+
# container.define! do
|
144
164
|
# calc( :model => :prototype ) { Calc.new( operations ) }
|
145
165
|
# end
|
146
|
-
def
|
166
|
+
def define!( &block )
|
147
167
|
raise ArgumentError, "block expected" unless block
|
148
|
-
|
149
|
-
ctx.instance_eval( &block )
|
168
|
+
builder.instance_eval( &block )
|
150
169
|
self
|
151
170
|
end
|
152
171
|
|
153
|
-
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
# the last-created namespace, unless that namespace already exists.
|
157
|
-
# This makes it work analogously to FileUtils#mkdir_p (creating new
|
158
|
-
# namespaces along a path of namespaces, as needed).
|
172
|
+
# Register the named service with the container. When the service is
|
173
|
+
# requested (with Container#[]), the associated callback will be used
|
174
|
+
# to construct it.
|
159
175
|
#
|
160
|
-
#
|
161
|
-
# block.
|
176
|
+
# Usage:
|
162
177
|
#
|
163
|
-
#
|
164
|
-
#
|
178
|
+
# container.register( :calc, :model=>:prototype ) do |c|
|
179
|
+
# Calc.new( c.operations )
|
180
|
+
# end
|
181
|
+
def register( name, opts={}, &callback )
|
182
|
+
raise ArgumentError, "expect block" unless callback
|
183
|
+
|
184
|
+
name = name.to_s.intern unless name.is_a?( Symbol )
|
185
|
+
@service_points[ name ] =
|
186
|
+
ServicePoint.new( self, name, opts, &callback )
|
187
|
+
end
|
188
|
+
|
189
|
+
# Create a new namespace within the container, with the given name. If a
|
190
|
+
# block is provided, it will be invoked when the namespace is created,
|
191
|
+
# with the new namespace passed to it.
|
165
192
|
#
|
166
193
|
# For the curious, namespaces are simply services that are implemented
|
167
194
|
# by Container. The two statements are really identical:
|
@@ -169,46 +196,30 @@ module Needle
|
|
169
196
|
# container.namespace( :calc )
|
170
197
|
# container.register( :calc ) { |c| Needle::Container.new( c, :calc ) }
|
171
198
|
#
|
199
|
+
# Note that this means that namespaces may be singletons or prototypes, or
|
200
|
+
# have immediate or deferred instantiation, and so forth. (The default of
|
201
|
+
# immediately, singleton instantiation is sufficient for 99% of the things
|
202
|
+
# you'll use namespaces for.)
|
203
|
+
#
|
172
204
|
# Usage:
|
173
205
|
#
|
174
|
-
# container.namespace( :
|
206
|
+
# container.namespace( :operations ) do |op|
|
175
207
|
# op.register( :add ) { Adder.new }
|
176
208
|
# ...
|
177
209
|
# end
|
178
210
|
#
|
179
211
|
# adder = container.calc.operations.add
|
180
|
-
def namespace(
|
181
|
-
opts
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
raise ArgumentError, "you must specify at least one name"
|
212
|
+
def namespace( name, opts={}, &block )
|
213
|
+
register( name, opts ) do |c,p|
|
214
|
+
ns = Container.new( c, name )
|
215
|
+
block.call ns if block
|
216
|
+
ns
|
186
217
|
end
|
187
|
-
|
188
|
-
container = self
|
189
|
-
parms.each do |parm|
|
190
|
-
unless container.has_key?( parm )
|
191
|
-
container.register( parm, opts ) { |c| Container.new( c, parm ) }
|
192
|
-
end
|
193
|
-
|
194
|
-
container = container[parm]
|
195
|
-
end
|
196
|
-
|
197
|
-
yield container if block_given?
|
198
218
|
end
|
199
219
|
|
200
|
-
# Create a new namespace within the container
|
201
|
-
#
|
202
|
-
#
|
203
|
-
# the last-created namespace, unless that namespace already exists.
|
204
|
-
# This makes it work analogously to FileUtils#mkdir_p (creating new
|
205
|
-
# namespaces along a path of namespaces, as needed).
|
206
|
-
#
|
207
|
-
# The last parameter may be a Hash, in which case it is used to specify
|
208
|
-
# options describing how the namespace should be created.
|
209
|
-
#
|
210
|
-
# The block is passed to the Container#register! method of the last
|
211
|
-
# namespace created.
|
220
|
+
# Create a new namespace within the container, with the given name.
|
221
|
+
# The block (which is required) will be passed to Container#define! on
|
222
|
+
# the new namespace.
|
212
223
|
#
|
213
224
|
# For the curious, namespaces are simply services that are implemented
|
214
225
|
# by Container. The two statements are really identical:
|
@@ -216,17 +227,22 @@ module Needle
|
|
216
227
|
# container.namespace( :calc )
|
217
228
|
# container.register( :calc ) { |c| Needle::Container.new( c, :calc ) }
|
218
229
|
#
|
230
|
+
# Note that this means that namespaces may be singletons or prototypes, or
|
231
|
+
# have immediate or deferred instantiation, and so forth. (The default of
|
232
|
+
# immediately, singleton instantiation is sufficient for 99% of the things
|
233
|
+
# you'll use namespaces for.)
|
234
|
+
#
|
219
235
|
# Usage:
|
220
236
|
#
|
221
|
-
# container.namespace!( :
|
237
|
+
# container.namespace!( :operations ) do
|
222
238
|
# add { Adder.new }
|
223
239
|
# ...
|
224
240
|
# end
|
225
241
|
#
|
226
242
|
# adder = container.calc.operations.add
|
227
|
-
def namespace!(
|
243
|
+
def namespace!( name, opts={}, &block )
|
228
244
|
raise ArgumentError, "block expected" unless block
|
229
|
-
namespace(
|
245
|
+
namespace( name, opts ) { |ns| ns.define!( &block ) }
|
230
246
|
end
|
231
247
|
|
232
248
|
# Describe a new interceptor to use that will intercept method calls
|
@@ -246,6 +262,21 @@ module Needle
|
|
246
262
|
interceptor
|
247
263
|
end
|
248
264
|
|
265
|
+
# Returns the pipeline object for the named service, which allows clients
|
266
|
+
# to explicitly manipulate the service's instantiation pipeline.
|
267
|
+
#
|
268
|
+
# Usage:
|
269
|
+
#
|
270
|
+
# container.pipeline( :calc ).
|
271
|
+
# add( :initialize ).
|
272
|
+
# add( :custom ) { |me,*args| me.succ.call( *args ) }
|
273
|
+
def pipeline( name )
|
274
|
+
point = find_definition( name )
|
275
|
+
raise ServiceNotFound, "#{fullname}.#{name}" unless point
|
276
|
+
|
277
|
+
point.pipeline
|
278
|
+
end
|
279
|
+
|
249
280
|
# Searches the current container and its ancestors for the named service.
|
250
281
|
# If found, the service point (the definition of that service) is returned,
|
251
282
|
# otherwise +nil+ is returned.
|
@@ -297,6 +328,13 @@ module Needle
|
|
297
328
|
# container.register( :add ) { Adder.new }
|
298
329
|
# p container.add == container[:add] # => true
|
299
330
|
#
|
331
|
+
# This also allows you to register new services in the container by
|
332
|
+
# sending the container a message with an attached block.
|
333
|
+
#
|
334
|
+
# Usage:
|
335
|
+
#
|
336
|
+
# container.foo { Bar.new }
|
337
|
+
# p container.foo
|
300
338
|
def method_missing( sym, *args, &block )
|
301
339
|
if block.nil? && args.empty? && knows_key?( sym )
|
302
340
|
self[sym]
|
@@ -14,31 +14,25 @@
|
|
14
14
|
# =============================================================================
|
15
15
|
#++
|
16
16
|
|
17
|
-
|
17
|
+
require 'needle/pipeline/element'
|
18
|
+
require 'needle/lifecycle/proxy'
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
module Needle
|
21
|
+
module Lifecycle
|
21
22
|
|
22
|
-
|
23
|
+
# The instantiation pipeline element that implements deferred
|
24
|
+
# instantiation.
|
25
|
+
class Deferred < Needle::Pipeline::Element
|
23
26
|
|
24
|
-
|
25
|
-
def register( name, opts={}, &callback )
|
26
|
-
self[name] = callback.call( self )
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_register
|
31
|
-
registry = Registry.new
|
27
|
+
set_default_priority 50
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
# Returns a new proxy instance that wraps the next element of the
|
30
|
+
# instantiation pipeline.
|
31
|
+
def call( *args )
|
32
|
+
Proxy.new( succ, *args )
|
33
|
+
end
|
36
34
|
|
37
|
-
|
35
|
+
end
|
38
36
|
|
39
|
-
assert_equal 4, models.length
|
40
|
-
assert_equal [:prototype, :prototype_deferred, :singleton, :singleton_deferred],
|
41
|
-
models.keys.sort {|a,b| a.to_s <=> b.to_s}
|
42
37
|
end
|
43
|
-
|
44
38
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# This source file is distributed as part of the Needle dependency injection
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Needle
|
10
|
+
# distribution for the texts of these licenses.
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
# needle website : http://needle.rubyforge.org
|
13
|
+
# project website: http://rubyforge.org/projects/needle
|
14
|
+
# =============================================================================
|
15
|
+
#++
|
16
|
+
|
17
|
+
require 'needle/pipeline/element'
|
18
|
+
|
19
|
+
module Needle
|
20
|
+
module Lifecycle
|
21
|
+
|
22
|
+
# The instantiation pipeline element that implements calling a separate
|
23
|
+
# initialization method on the instantiated service. This should always be
|
24
|
+
# placed in the pipeline as close to the service implementation as possible
|
25
|
+
# (hence, the low default priority).
|
26
|
+
class Initialize < Needle::Pipeline::Element
|
27
|
+
|
28
|
+
set_default_priority -100
|
29
|
+
|
30
|
+
# Initialize the element. Looks at the options hash to determine the
|
31
|
+
# name of the initialization method to call, defaulting to
|
32
|
+
# <tt>:initialize_service</tt>.
|
33
|
+
def initialize_element
|
34
|
+
@init_method = options[:init_method] || :initialize_service
|
35
|
+
end
|
36
|
+
|
37
|
+
# Invokes the next element of the chain. If the result responds to the
|
38
|
+
# requested initialization method, that method is invoked on the
|
39
|
+
# result, and the result is returned.
|
40
|
+
def call( *args )
|
41
|
+
service = succ.call( *args )
|
42
|
+
service.send @init_method if service.respond_to?( @init_method )
|
43
|
+
service
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|