needle 1.1.0 → 1.2.0

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