needle 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|