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.
Files changed (38) hide show
  1. data/benchmarks/instantiation.rb +39 -0
  2. data/doc/faq/faq.yml +137 -102
  3. data/doc/manual-html/chapter-1.html +15 -19
  4. data/doc/manual-html/chapter-2.html +52 -23
  5. data/doc/manual-html/chapter-3.html +7 -9
  6. data/doc/manual-html/chapter-4.html +6 -8
  7. data/doc/manual-html/chapter-5.html +16 -19
  8. data/doc/manual-html/chapter-6.html +31 -8
  9. data/doc/manual-html/chapter-7.html +19 -8
  10. data/doc/manual-html/chapter-8.html +8 -11
  11. data/doc/manual-html/chapter-9.html +7 -6
  12. data/doc/manual-html/index.html +5 -3
  13. data/doc/manual/manual.yml +2 -1
  14. data/doc/manual/parts/01_alternatives.txt +2 -1
  15. data/doc/manual/parts/02_services.txt +33 -0
  16. data/doc/manual/parts/logging_logfactory.txt +9 -0
  17. data/doc/manual/parts/models_models.txt +4 -0
  18. data/doc/manual/parts/models_pipelines.txt +1 -0
  19. data/lib/needle/container.rb +64 -19
  20. data/lib/needle/definition-context.rb +34 -6
  21. data/lib/needle/lifecycle/multiton.rb +64 -0
  22. data/lib/needle/lifecycle/singleton.rb +2 -2
  23. data/lib/needle/lifecycle/threaded.rb +4 -3
  24. data/lib/needle/pipeline/collection.rb +10 -1
  25. data/lib/needle/pipeline/element.rb +6 -0
  26. data/lib/needle/registry.rb +18 -5
  27. data/lib/needle/service-point.rb +21 -10
  28. data/lib/needle/version.rb +1 -1
  29. data/test/lifecycle/tc_multiton.rb +43 -0
  30. data/test/lifecycle/tc_singleton.rb +18 -2
  31. data/test/lifecycle/tc_threaded.rb +12 -6
  32. data/test/pipeline/tc_collection.rb +26 -2
  33. data/test/services.rb +8 -0
  34. data/test/tc_container.rb +82 -0
  35. data/test/tc_definition_context.rb +63 -7
  36. data/test/tc_registry.rb +13 -1
  37. data/test/tc_service_point.rb +49 -0
  38. metadata +4 -2
@@ -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 registry
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 block
112
- should return the implementation of the service. If needed, the block can
113
- accept two parameters--the container that the service is being registered
114
- with, and an object that represents the service being defined (called a "service
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 services.
126
- These approaches are friendlier if you are needing to register several services
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 sent to the
144
- builder are interpreted as service names, and if a block is sent with the message,
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 context
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, so you
153
- could do something like the following if you only need to define one or two
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 readable
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 treat the
177
- container (i.e., registry) as a hash, passing the name of the service as an argument
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 the name of
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 does not
197
- conflict with the name of an existing method on the container. For example, if
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 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 of that service
212
- will return the same object instance. This is the _singleton_ service model.
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 register the service:
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 packages. You can create
230
- namespaces in a few ways. The first (and simplest) is to just call Container#namespace:
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 block as well,
239
- the block will be invoked (with the new namespace yielded to it) the first time the
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 namespace, there
255
- are some convenience methods to make this more...convenient.
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!. The second
274
- creates the namespace and calls Container#define. In both cases, _the namespace is
275
- created immediately_, unlike Container#namespace which only creates the 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 pass options
280
- to the namespace methods just as you can with Container#register and friends.
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@ service. Once you have a
284
- logger instance, you can invoke the #debug, #info, #warn, #error, and #fatal methods
285
- on the instance to log messages of the corresponding severity.
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
- Log messages are written, by default, to a file called "needle.log", in the same
297
- directory that the application was invoked from.
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 method
301
- invocations on a service. This includes method entry and exit, as well as any
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 logging
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 you here.
319
- Fortunately, the LoggingInterceptor is one of them. (If you write your own interceptor
320
- and would like similar functionality, see the IncludeExclude module.)
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 (matching
324
- method names and/or arities) as the "exclude" option, when declaring the interceptor:
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 invocation
336
- of 'bar' with more than 4 arguments, or any method invocation with fewer than two
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 to be
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 matches
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 expects
361
- to be "included" by other libraries/applications. For example, Needle encourages
362
- the use of a method called @register_services@, which accepts a container as a
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 require of
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 Container#require,
383
- passing the file to require and a string (or symbol) identifying the name of the
384
- module that contains the registration method. You can also pass a symbol as the third
385
- parameter naming the registration method, but it defaults to @:register_services@.
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 require method,
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 prototype,
422
- because you will likely have many buttons in an application, with each button
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 to explicitly
427
- specify it as a model. It is appropriate for services that:
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 the service
436
- _per thread_. Thus, it is appropriate to the same situations as singleton, but
437
- specific to a thread, instead of an application. This is useful for web applications
438
- that are run in a single virtual machine, and which share a single registry.
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 service. A service
442
- using a deferred service model (ie, @:prototype_deferred@, @:singleton_deferred@, or
443
- @:threaded_deferred@) will not be instantiated until the first time a method is invoked
444
- on the service.
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 instantiate, since
448
- you can wait to do the expensive initialization until it is really needed. Applications
449
- will start up faster when their dependences use deferred instantiation.
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 automatically after
453
- a service has been instantiated. Consider the case where a service is initialized
454
- primarily using setters, but requires some logic to be executed to complete the
455
- initialization phase. In this case, you could always explicitly invoke the initialization
456
- method(s) in the constructor block, but if many services use the same initialization
457
- method, it can be more convenient to use an "initialize" service model.
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.