needle 1.1.0 → 1.2.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/instantiation.rb +39 -0
- data/doc/faq/faq.yml +137 -102
- data/doc/manual-html/chapter-1.html +15 -19
- data/doc/manual-html/chapter-2.html +52 -23
- data/doc/manual-html/chapter-3.html +7 -9
- data/doc/manual-html/chapter-4.html +6 -8
- data/doc/manual-html/chapter-5.html +16 -19
- data/doc/manual-html/chapter-6.html +31 -8
- data/doc/manual-html/chapter-7.html +19 -8
- data/doc/manual-html/chapter-8.html +8 -11
- data/doc/manual-html/chapter-9.html +7 -6
- data/doc/manual-html/index.html +5 -3
- data/doc/manual/manual.yml +2 -1
- data/doc/manual/parts/01_alternatives.txt +2 -1
- data/doc/manual/parts/02_services.txt +33 -0
- data/doc/manual/parts/logging_logfactory.txt +9 -0
- data/doc/manual/parts/models_models.txt +4 -0
- data/doc/manual/parts/models_pipelines.txt +1 -0
- data/lib/needle/container.rb +64 -19
- data/lib/needle/definition-context.rb +34 -6
- data/lib/needle/lifecycle/multiton.rb +64 -0
- data/lib/needle/lifecycle/singleton.rb +2 -2
- data/lib/needle/lifecycle/threaded.rb +4 -3
- data/lib/needle/pipeline/collection.rb +10 -1
- data/lib/needle/pipeline/element.rb +6 -0
- data/lib/needle/registry.rb +18 -5
- data/lib/needle/service-point.rb +21 -10
- data/lib/needle/version.rb +1 -1
- data/test/lifecycle/tc_multiton.rb +43 -0
- data/test/lifecycle/tc_singleton.rb +18 -2
- data/test/lifecycle/tc_threaded.rb +12 -6
- data/test/pipeline/tc_collection.rb +26 -2
- data/test/services.rb +8 -0
- data/test/tc_container.rb +82 -0
- data/test/tc_definition_context.rb +63 -7
- data/test/tc_registry.rb +13 -1
- data/test/tc_service_point.rb +49 -0
- metadata +4 -2
data/benchmarks/instantiation.rb
CHANGED
@@ -31,3 +31,42 @@ end
|
|
31
31
|
|
32
32
|
puts "* this benchmark forced the proxy to instantiate its wrapped service"
|
33
33
|
puts
|
34
|
+
|
35
|
+
class S2
|
36
|
+
def initialize
|
37
|
+
@h = Hash.new
|
38
|
+
@h[:one] = :two
|
39
|
+
@h[:two] = :three
|
40
|
+
@h[:three] = :four
|
41
|
+
10.times { @h[:one] }
|
42
|
+
end
|
43
|
+
|
44
|
+
def value
|
45
|
+
@h
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
registry = Needle::Registry.new
|
50
|
+
registry.register( :immediate, :model=>:prototype ) { S2.new }
|
51
|
+
registry.register( :deferred, :model=>:prototype_deferred ) { S2.new }
|
52
|
+
|
53
|
+
puts
|
54
|
+
puts "--------------------------------------------------------------------"
|
55
|
+
puts "Direct vs. Immediate vs. Deferred instantiation (non-trivial)"
|
56
|
+
puts "#{ITERATIONS} iterations"
|
57
|
+
puts
|
58
|
+
|
59
|
+
Benchmark.bm(10) do |x|
|
60
|
+
GC.disable
|
61
|
+
x.report( "direct:" ) { ITERATIONS.times { S2.new } }
|
62
|
+
GC.start
|
63
|
+
x.report( "immediate:" ) { ITERATIONS.times { registry.immediate } }
|
64
|
+
GC.start
|
65
|
+
x.report( "deferred:" ) { ITERATIONS.times { registry.deferred } }
|
66
|
+
GC.start
|
67
|
+
x.report( "deferred*:" ) { ITERATIONS.times { registry.deferred.value } }
|
68
|
+
GC.enable
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "* this benchmark forced the proxy to instantiate its wrapped service"
|
72
|
+
puts
|
data/doc/faq/faq.yml
CHANGED
@@ -19,6 +19,14 @@
|
|
19
19
|
- "service?": >-
|
20
20
|
A _service_ is the instantiation of a service point.
|
21
21
|
|
22
|
+
- "parameterized service?": >-
|
23
|
+
A _parameterized_ service is a service that allows contextual parameters
|
24
|
+
to be passed to the service when it is created. Such services are
|
25
|
+
typically used in conjunction with the @multiton@ service model, but
|
26
|
+
the only real requirement is that they _not_ be used with a service model
|
27
|
+
that does not support multiple parameters (like @singleton@ or
|
28
|
+
@threaded@).
|
29
|
+
|
22
30
|
- "service model?": >-
|
23
31
|
A _service model_ is a description of the lifecycle of a service. By
|
24
32
|
default, all services are _singletons_, meaning that every time you ask
|
@@ -99,8 +107,8 @@
|
|
99
107
|
thing, but evaluates the block within the context of the builder.
|
100
108
|
|
101
109
|
- "register a service?": >-
|
102
|
-
The first way to register a service is by calling #register on the
|
103
|
-
(or a namespace):
|
110
|
+
The first way to register a service is by calling #register on the
|
111
|
+
registry (or a namespace):
|
104
112
|
|
105
113
|
|
106
114
|
<pre>
|
@@ -108,11 +116,11 @@
|
|
108
116
|
</pre>
|
109
117
|
|
110
118
|
|
111
|
-
The (first) parameter to #register is the name of the service, and the
|
112
|
-
should return the implementation of the service. If needed, the
|
113
|
-
accept two parameters--the container that the service is being
|
114
|
-
with, and an object that represents the service being defined
|
115
|
-
point"):
|
119
|
+
The (first) parameter to #register is the name of the service, and the
|
120
|
+
block should return the implementation of the service. If needed, the
|
121
|
+
block can accept two parameters--the container that the service is being
|
122
|
+
registered with, and an object that represents the service being defined
|
123
|
+
(called a "service point"):
|
116
124
|
|
117
125
|
|
118
126
|
<pre>
|
@@ -122,9 +130,9 @@
|
|
122
130
|
</pre>
|
123
131
|
|
124
132
|
|
125
|
-
You can also use Container#define and Container#define! to register
|
126
|
-
These approaches are friendlier if you are needing to register
|
127
|
-
at once.
|
133
|
+
You can also use Container#define and Container#define! to register
|
134
|
+
services. These approaches are friendlier if you are needing to register
|
135
|
+
several services at once.
|
128
136
|
|
129
137
|
|
130
138
|
<pre>
|
@@ -140,18 +148,18 @@
|
|
140
148
|
</pre>
|
141
149
|
|
142
150
|
|
143
|
-
Container#define yields a new "builder" object to the block. Messages
|
144
|
-
builder are interpreted as service names, and if a block is
|
145
|
-
a new service is registered under that name.
|
151
|
+
Container#define yields a new "builder" object to the block. Messages
|
152
|
+
sent to the builder are interpreted as service names, and if a block is
|
153
|
+
sent with the message, a new service is registered under that name.
|
146
154
|
|
147
155
|
|
148
|
-
Container#define! does likewise, except it evaluates the block within the
|
149
|
-
of the builder object.
|
156
|
+
Container#define! does likewise, except it evaluates the block within the
|
157
|
+
context of the builder object.
|
150
158
|
|
151
159
|
|
152
|
-
If you do not pass a block to #define, it will return the builder object,
|
153
|
-
could do something like the following if you only need to define
|
154
|
-
services:
|
160
|
+
If you do not pass a block to #define, it will return the builder object,
|
161
|
+
so you could do something like the following if you only need to define
|
162
|
+
one or two services:
|
155
163
|
|
156
164
|
|
157
165
|
<pre>
|
@@ -169,13 +177,13 @@
|
|
169
177
|
</pre>
|
170
178
|
|
171
179
|
|
172
|
-
(This last is the same as calling #define without arguments, but is more
|
173
|
-
if you intend to use the builder object multiple times.)
|
180
|
+
(This last is the same as calling #define without arguments, but is more
|
181
|
+
readable if you intend to use the builder object multiple times.)
|
174
182
|
|
175
183
|
- "reference a service?": >-
|
176
|
-
Referencing a service can be done in either of two ways. The first is to
|
177
|
-
container (i.e., registry) as a hash, passing the name of the
|
178
|
-
to Container#[]:
|
184
|
+
Referencing a service can be done in either of two ways. The first is to
|
185
|
+
treat the container (i.e., registry) as a hash, passing the name of the
|
186
|
+
service as an argument to Container#[]:
|
179
187
|
|
180
188
|
|
181
189
|
<pre>
|
@@ -184,8 +192,8 @@
|
|
184
192
|
</pre>
|
185
193
|
|
186
194
|
|
187
|
-
A more convenient (but slightly more peril-fraught) approach is to send
|
188
|
-
the method to the registry as a message:
|
195
|
+
A more convenient (but slightly more peril-fraught) approach is to send
|
196
|
+
the name of the method to the registry as a message:
|
189
197
|
|
190
198
|
|
191
199
|
<pre>
|
@@ -193,9 +201,9 @@
|
|
193
201
|
</pre>
|
194
202
|
|
195
203
|
|
196
|
-
Be aware that this latter approach will only work when the service name
|
197
|
-
conflict with the name of an existing method on the container.
|
198
|
-
you were to do:
|
204
|
+
Be aware that this latter approach will only work when the service name
|
205
|
+
does not conflict with the name of an existing method on the container.
|
206
|
+
For example, if you were to do:
|
199
207
|
|
200
208
|
|
201
209
|
<pre>
|
@@ -204,15 +212,17 @@
|
|
204
212
|
</pre>
|
205
213
|
|
206
214
|
|
207
|
-
You would get the hash value of the registry object, instead of the value
|
208
|
-
of the service (which would be "hello, world").
|
215
|
+
You would get the hash value of the registry object, instead of the value
|
216
|
+
value of the service (which would be "hello, world").
|
209
217
|
|
210
218
|
- "select a service model for a service (i.e., change the default model of lifecycle management)?": >-
|
211
|
-
By default, a service will be managed as a singleton, i.e., every request
|
212
|
-
will return the same object instance. This is the
|
219
|
+
By default, a service will be managed as a singleton, i.e., every request
|
220
|
+
of that service will return the same object instance. This is the
|
221
|
+
_singleton_ service model.
|
213
222
|
|
214
223
|
|
215
|
-
To select a different service model, pass it as an option when you
|
224
|
+
To select a different service model, pass it as an option when you
|
225
|
+
register the service:
|
216
226
|
|
217
227
|
|
218
228
|
<pre>
|
@@ -226,8 +236,9 @@
|
|
226
236
|
</pre>
|
227
237
|
|
228
238
|
- "create a namespace?": >-
|
229
|
-
Namespaces allow you to organize your services into hierarchical
|
230
|
-
namespaces in a few ways. The first (and
|
239
|
+
Namespaces allow you to organize your services into hierarchical
|
240
|
+
packages. You can create namespaces in a few ways. The first (and
|
241
|
+
simplest) is to just call Container#namespace:
|
231
242
|
|
232
243
|
|
233
244
|
<pre>
|
@@ -235,9 +246,9 @@
|
|
235
246
|
</pre>
|
236
247
|
|
237
248
|
|
238
|
-
This will create a namespace in the registry, called stuff. If you send a
|
239
|
-
the block will be invoked (with the new namespace yielded
|
240
|
-
namespace is requested:
|
249
|
+
This will create a namespace in the registry, called stuff. If you send a
|
250
|
+
block as well, the block will be invoked (with the new namespace yielded
|
251
|
+
to it) the first time the namespace is requested:
|
241
252
|
|
242
253
|
|
243
254
|
<pre>
|
@@ -251,8 +262,9 @@
|
|
251
262
|
end
|
252
263
|
</pre>
|
253
264
|
|
254
|
-
Because it is so common to immediately define services on the new
|
255
|
-
are some convenience methods to make this more...
|
265
|
+
Because it is so common to immediately define services on the new
|
266
|
+
namespace, there are some convenience methods to make this more...
|
267
|
+
convenient.
|
256
268
|
|
257
269
|
|
258
270
|
<pre>
|
@@ -270,19 +282,21 @@
|
|
270
282
|
</pre>
|
271
283
|
|
272
284
|
|
273
|
-
The first one, above, creates the namespace and calls Container#define!.
|
274
|
-
creates the namespace and calls Container#define. In both
|
275
|
-
created immediately_, unlike Container#namespace
|
276
|
-
when it is first requested.
|
285
|
+
The first one, above, creates the namespace and calls Container#define!.
|
286
|
+
The second creates the namespace and calls Container#define. In both
|
287
|
+
cases, _the namespace is created immediately_, unlike Container#namespace
|
288
|
+
which only creates the namespace when it is first requested.
|
277
289
|
|
278
290
|
|
279
|
-
Lastly, note that namespace's are just special services. Thus, you can
|
280
|
-
to the namespace methods just as you can with
|
291
|
+
Lastly, note that namespace's are just special services. Thus, you can
|
292
|
+
pass options to the namespace methods just as you can with
|
293
|
+
Container#register and friends.
|
281
294
|
|
282
295
|
- "write log messages?": >-
|
283
|
-
You can obtain a new logger instance from the @:logs@
|
284
|
-
logger instance, you can invoke the #debug,
|
285
|
-
on the instance to log messages
|
296
|
+
You can obtain a new logger instance from the @:logs@ and @:log_for@
|
297
|
+
services. Once you have a logger instance, you can invoke the #debug,
|
298
|
+
#info, #warn, #error, and #fatal methods on the instance to log messages
|
299
|
+
of the corresponding severity.
|
286
300
|
|
287
301
|
|
288
302
|
<pre>
|
@@ -290,16 +304,22 @@
|
|
290
304
|
logger.debug "This is a debug message"
|
291
305
|
logger.info "This is an informational message"
|
292
306
|
...
|
307
|
+
logger2 = registry.log_for( "another logger name" )
|
308
|
+
...
|
293
309
|
</pre>
|
294
310
|
|
295
311
|
|
296
|
-
|
297
|
-
|
312
|
+
The two approaches shown above are identical--the second approach (using
|
313
|
+
the @log_for@ service) is just a convenience for @logs.get@.
|
314
|
+
|
315
|
+
|
316
|
+
Log messages are written, by default, to a file called "needle.log", in
|
317
|
+
the same directory that the application was invoked from.
|
298
318
|
|
299
319
|
|
300
|
-
You can also use a logging interceptor to automatically log all external
|
301
|
-
invocations on a service. This includes method entry and exit, as
|
302
|
-
exceptions that are raised inside the method.
|
320
|
+
You can also use a logging interceptor to automatically log all external
|
321
|
+
method invocations on a service. This includes method entry and exit, as
|
322
|
+
well as any exceptions that are raised inside the method.
|
303
323
|
|
304
324
|
|
305
325
|
<pre>
|
@@ -311,17 +331,19 @@
|
|
311
331
|
</pre>
|
312
332
|
|
313
333
|
|
314
|
-
See the chapter in the "User's Manual":http://needle.rubyforge.org about
|
315
|
-
for more information on how to use and configure loggers.
|
334
|
+
See the chapter in the "User's Manual":http://needle.rubyforge.org about
|
335
|
+
logging for more information on how to use and configure loggers.
|
316
336
|
|
317
337
|
- "exclude methods from being intercepted?": >-
|
318
|
-
Only interceptors that explicitly support exclusion of methods can help
|
319
|
-
Fortunately, the LoggingInterceptor is one of them. (If you
|
320
|
-
and would like similar functionality, see the
|
338
|
+
Only interceptors that explicitly support exclusion of methods can help
|
339
|
+
you here. Fortunately, the LoggingInterceptor is one of them. (If you
|
340
|
+
write your own interceptor and would like similar functionality, see the
|
341
|
+
IncludeExclude module.)
|
321
342
|
|
322
343
|
|
323
|
-
In the case of the LoggingInterceptor, just pass an array of patterns
|
324
|
-
method names and/or arities) as the "exclude" option, when
|
344
|
+
In the case of the LoggingInterceptor, just pass an array of patterns
|
345
|
+
(matching method names and/or arities) as the "exclude" option, when
|
346
|
+
declaring the interceptor:
|
325
347
|
|
326
348
|
|
327
349
|
<pre>
|
@@ -332,13 +354,13 @@
|
|
332
354
|
</pre>
|
333
355
|
|
334
356
|
|
335
|
-
The above will exclude from interception any method named 'foo', or any
|
336
|
-
of 'bar' with more than 4 arguments, or any method invocation
|
337
|
-
arguments.
|
357
|
+
The above will exclude from interception any method named 'foo', or any
|
358
|
+
invocation of 'bar' with more than 4 arguments, or any method invocation
|
359
|
+
with fewer than two arguments.
|
338
360
|
|
339
361
|
|
340
|
-
You can also give an array of patterns to _include_. These cause methods
|
341
|
-
explicitly intercepted even if they match an exclude pattern:
|
362
|
+
You can also give an array of patterns to _include_. These cause methods
|
363
|
+
to be explicitly intercepted even if they match an exclude pattern:
|
342
364
|
|
343
365
|
|
344
366
|
<pre>
|
@@ -353,14 +375,14 @@
|
|
353
375
|
</pre>
|
354
376
|
|
355
377
|
|
356
|
-
This would result in the call to #baz being intercepted, even though it
|
357
|
-
an exclude pattern (@*(<2)@).
|
378
|
+
This would result in the call to #baz being intercepted, even though it
|
379
|
+
matches an exclude pattern (@*(<2)@).
|
358
380
|
|
359
381
|
- "include services defined in another library?": >-
|
360
|
-
This requires that the other library be implemented in such a way that it
|
361
|
-
to be "included" by other libraries/applications. For example,
|
362
|
-
the use of a method called @register_services@, which
|
363
|
-
parameter:
|
382
|
+
This requires that the other library be implemented in such a way that it
|
383
|
+
expects to be "included" by other libraries/applications. For example,
|
384
|
+
Needle encourages the use of a method called @register_services@, which
|
385
|
+
accepts a container as a parameter:
|
364
386
|
|
365
387
|
|
366
388
|
<pre>
|
@@ -375,14 +397,15 @@
|
|
375
397
|
</pre>
|
376
398
|
|
377
399
|
|
378
|
-
If the library has been implemented in this way, you can simply do a
|
379
|
-
the library and then invoke the @register_services@ method.
|
400
|
+
If the library has been implemented in this way, you can simply do a
|
401
|
+
require of the library and then invoke the @register_services@ method.
|
380
402
|
|
381
403
|
|
382
|
-
There is a convenience method in Container for doing this. Just call
|
383
|
-
passing the file to require and a string (or symbol)
|
384
|
-
module that contains the registration method.
|
385
|
-
|
404
|
+
There is a convenience method in Container for doing this. Just call
|
405
|
+
Container#require, passing the file to require and a string (or symbol)
|
406
|
+
identifying the name of the module that contains the registration method.
|
407
|
+
You can also pass a symbol as the third parameter naming the registration
|
408
|
+
method, but it defaults to @:register_services@.
|
386
409
|
|
387
410
|
|
388
411
|
<pre>
|
@@ -395,8 +418,8 @@
|
|
395
418
|
</pre>
|
396
419
|
|
397
420
|
|
398
|
-
The definition context (i.e., the "builder" object) also supports the
|
399
|
-
so you can do:
|
421
|
+
The definition context (i.e., the "builder" object) also supports the
|
422
|
+
require method, so you can do:
|
400
423
|
|
401
424
|
|
402
425
|
<pre>
|
@@ -418,13 +441,14 @@
|
|
418
441
|
* will be used multiple times for different situations
|
419
442
|
|
420
443
|
|
421
|
-
For example, if you have a GUI library, a "button" service could be a
|
422
|
-
because you will likely have many buttons in an application,
|
423
|
-
being an independent instance.
|
444
|
+
For example, if you have a GUI library, a "button" service could be a
|
445
|
+
prototype, because you will likely have many buttons in an application,
|
446
|
+
with each button being an independent instance.
|
424
447
|
|
425
448
|
- "Like, :singleton?": >-
|
426
|
-
The singleton service model is the default, so you should rarely need
|
427
|
-
specify it as a model. It is appropriate for services
|
449
|
+
The singleton service model is the default, so you should rarely need
|
450
|
+
to explicitly specify it as a model. It is appropriate for services
|
451
|
+
that:
|
428
452
|
|
429
453
|
|
430
454
|
* guard some specific functionality
|
@@ -432,26 +456,37 @@
|
|
432
456
|
* represent state that is global across an application
|
433
457
|
|
434
458
|
- "Like, :threaded?": >-
|
435
|
-
Threaded is similar to singleton, but it allows one unique instance of
|
436
|
-
_per thread_. Thus, it is appropriate to the same
|
437
|
-
specific to a thread, instead of an
|
438
|
-
|
459
|
+
Threaded is similar to singleton, but it allows one unique instance of
|
460
|
+
the service _per thread_. Thus, it is appropriate to the same
|
461
|
+
situations as singleton, but specific to a thread, instead of an
|
462
|
+
application. This is useful for web applications that are run in a
|
463
|
+
single virtual machine, and which share a single registry.
|
439
464
|
|
440
465
|
- "Like, deferred?": >-
|
441
|
-
Deferred models use a proxy to enforce lazy initialization of the
|
442
|
-
using a deferred service model (ie,
|
443
|
-
@:
|
444
|
-
|
466
|
+
Deferred models use a proxy to enforce lazy initialization of the
|
467
|
+
service. A service using a deferred service model (ie,
|
468
|
+
@:prototype_deferred@, @:multiton_deferred@, @:singleton_deferred@, or
|
469
|
+
@:threaded_deferred@) will not be instantiated until the first time a
|
470
|
+
method is invoked on the service.
|
445
471
|
|
446
472
|
|
447
|
-
This makes a deferred model appropriate when a service is expensive to
|
448
|
-
you can wait to do the expensive initialization
|
449
|
-
will start up faster when their
|
473
|
+
This makes a deferred model appropriate when a service is expensive to
|
474
|
+
instantiate, since you can wait to do the expensive initialization
|
475
|
+
until it is really needed. Applications will start up faster when their
|
476
|
+
dependences use deferred instantiation.
|
450
477
|
|
451
478
|
- "Like, initialize?": >-
|
452
|
-
This is useful when you have a method that you want to be invoked
|
453
|
-
a service has been instantiated. Consider the case
|
454
|
-
primarily using setters, but requires
|
455
|
-
|
456
|
-
|
457
|
-
|
479
|
+
This is useful when you have a method that you want to be invoked
|
480
|
+
automatically after a service has been instantiated. Consider the case
|
481
|
+
where a service is initialized primarily using setters, but requires
|
482
|
+
some logic to be executed to complete the initialization phase. In this
|
483
|
+
case, you could always explicitly invoke the initialization method(s)
|
484
|
+
in the constructor block, but if many services use the same
|
485
|
+
initialization method, it can be more convenient to use an "initialize"
|
486
|
+
service model.
|
487
|
+
|
488
|
+
- "Like, multiton?": >-
|
489
|
+
Multitons are useful for factories, where you have a class that
|
490
|
+
differentiates its instances based on some construction parameters that
|
491
|
+
need to be determined at runtime. Thus, multitons are always used with
|
492
|
+
parameterized services.
|