needle 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.
|
18
|
-
Manual Last Updated: <strong>2004-11-
|
17
|
+
Needle Version: <strong>1.2.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -221,11 +221,10 @@
|
|
221
221
|
|
222
222
|
<div class="section">
|
223
223
|
<p>The service locator works well when there are few dependencies, and the dependency graph is not very deep. However, it has a few drawbacks:</p>
|
224
|
-
|
225
224
|
<ol>
|
226
|
-
<li>It requires each object to accept the locator as a parameter, and to know how to use it. This is problematic if you want to use existing classes that were created without knowledge of a locator. (I.e., <code>Logger</code>, in the Ruby library)
|
225
|
+
<li>It requires each object to accept the locator as a parameter, and to know how to use it. This is problematic if you want to use existing classes that were created without knowledge of a locator. (I.e., <code>Logger</code>, in the Ruby library).
|
227
226
|
</li>
|
228
|
-
<li>It requires each object to know what the services are named, in the locator. If you ever decide to change the name of a service in the locator, you may have to change lots of code to comply with the change
|
227
|
+
<li>It requires each object to know what the services are named, in the locator. If you ever decide to change the name of a service in the locator, you may have to change lots of code to comply with the change.
|
229
228
|
</li>
|
230
229
|
<li>For deep dependency graphs, it can become cumbersome to have to pass the locator to each constructor.</li>
|
231
230
|
</ol>
|
@@ -245,6 +244,7 @@
|
|
245
244
|
<div class="section">
|
246
245
|
<p>Setting up for DI is very similar to the setup for a service locator, but instead of passing the locator (we’ll call it a <em>registry</em> now), we only pass (or set) the dependencies that the service itself needs.</p>
|
247
246
|
|
247
|
+
|
248
248
|
<pre>
|
249
249
|
require 'needle'
|
250
250
|
|
@@ -283,11 +283,9 @@
|
|
283
283
|
|
284
284
|
...
|
285
285
|
</pre>
|
286
|
-
|
287
286
|
<p>The <code>create_application</code> method is now (necessarily) a little more complex, since it now contains all of the initialization logic for each service in the application. However, look how much simpler this made the other classes, especially the <code>Application</code> class.</p>
|
288
287
|
|
289
|
-
<p>Now, each class no longer even needs to care that it is being initialized via another container. All it knows is that when it is created, it will be given each of its dependencies (either as constructor parameters or as property accessors)
|
290
|
-
</p>
|
288
|
+
<p>Now, each class no longer even needs to care that it is being initialized via another container. All it knows is that when it is created, it will be given each of its dependencies (either as constructor parameters or as property accessors).</p>
|
291
289
|
</div>
|
292
290
|
|
293
291
|
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.
|
18
|
-
Manual Last Updated: <strong>2004-11-
|
17
|
+
Needle Version: <strong>1.2.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -224,8 +224,7 @@
|
|
224
224
|
|
225
225
|
<p>Needle comes with one interceptor, the LoggingInterceptor. This allows you to easily trace the execution of your services by logging method entry and exit, as well as any exceptions that are raised.</p>
|
226
226
|
|
227
|
-
<p>You can, of course, implement your own interceptors as well
|
228
|
-
</p>
|
227
|
+
<p>You can, of course, implement your own interceptors as well.</p>
|
229
228
|
</div>
|
230
229
|
|
231
230
|
|
@@ -242,8 +241,7 @@
|
|
242
241
|
|
243
242
|
<p>The interceptors themselves are attached to the service during the execution of its instantiation pipeline (see Service Models). Thus, any action in the pipeline that is situated closer to the service than the interceptor pipeline action will bypass the interceptors altogether. This allows you to attach hooks to your service that can be called without invoking the interceptors on the service.</p>
|
244
243
|
|
245
|
-
<p>Another thing to keep in mind is that the interceptors are one-to-one for each service instance. Thus, if your service is a prototype (see the Service Models chapter), you’ll have one instance of each interceptor for each instance of your service
|
246
|
-
</p>
|
244
|
+
<p>Another thing to keep in mind is that the interceptors are one-to-one for each service instance. Thus, if your service is a prototype (see the Service Models chapter), you’ll have one instance of each interceptor for each instance of your service.</p>
|
247
245
|
</div>
|
248
246
|
|
249
247
|
|
@@ -266,60 +264,59 @@
|
|
266
264
|
|
267
265
|
<p>You can attach interceptor factories to your service using the <code>#interceptor(...).with {...}</code> syntax:</p>
|
268
266
|
|
267
|
+
|
269
268
|
<pre>
|
270
269
|
reg.register( :foo ) {...}
|
271
270
|
reg.intercept( :foo ).with { MyInterceptorFactory }
|
272
271
|
</pre>
|
273
|
-
|
274
272
|
<p>Note that you could also make the interceptor factory a service:</p>
|
275
273
|
|
274
|
+
|
276
275
|
<pre>
|
277
276
|
reg.register( :foo ) {...}
|
278
277
|
reg.register( :my_interceptor ) { MyInterceptorFactory }
|
279
278
|
reg.intercept( :foo ).with { |c| c.my_interceptor }
|
280
279
|
</pre>
|
281
|
-
|
282
280
|
<p>And, to make accessing interceptor services even more convenient, you can use the <code>#with!</code> method (which executes its block within the context of the calling container):</p>
|
283
281
|
|
282
|
+
|
284
283
|
<pre>
|
285
284
|
reg.register( :foo ) {...}
|
286
285
|
reg.register( :my_interceptor ) { MyInterceptorFactory }
|
287
286
|
reg.intercept( :foo ).with! { my_interceptor }
|
288
287
|
</pre>
|
289
|
-
|
290
288
|
<h3>Blocks</h3>
|
291
289
|
|
292
|
-
<p>Sometimes creating an entire class to implement an interceptor is overkill. This is particularly the case during debugging or testing, when you might want to attach an interceptor to class to verify that a parameter passed is correct, or a return value is what you expect. To satisfy these conditions, you can using the
|
290
|
+
<p>Sometimes creating an entire class to implement an interceptor is overkill. This is particularly the case during debugging or testing, when you might want to attach an interceptor to class to verify that a parameter passed is correct, or a return value is what you expect. To satisfy these conditions, you can using the
|
293
291
|
<code>#doing</code> method. Just give it a block that accepts two parameters (the chain, and context) and you’re good to go!</p>
|
294
292
|
|
293
|
+
|
295
294
|
<pre>
|
296
295
|
reg.register( :foo ) {...}
|
297
296
|
reg.intercept( :foo ).doing { |chain,ctx| ...; chain.process_next( ctx ) }
|
298
297
|
</pre>
|
299
|
-
|
300
298
|
<p>Note that this approach is about 40% slower than using an interceptor factory, so it should not be used if performance is an issue.</p>
|
301
299
|
|
302
300
|
<h3>Options</h3>
|
303
301
|
|
304
302
|
<p>Some interceptors can accept configuration options. For example, the LoggingInterceptor allows clients to specify methods that should and shouldn’t be intercepted. Options are specified via the <code>#with_options</code> method.</p>
|
305
303
|
|
304
|
+
|
306
305
|
<pre>
|
307
306
|
reg.register( :foo ) {...}
|
308
307
|
reg.intercept( :foo ).
|
309
308
|
with { |c| c.logging_interceptor }.
|
310
309
|
with_options( :exclude => [ "method1", "method2" ] )
|
311
310
|
</pre>
|
312
|
-
|
313
311
|
<p>Options can apply to the blocks given to the <code>#doing</code> method, too. The block may access the options via the <code>#data[:options]</code> member of the context:</p>
|
314
312
|
|
313
|
+
|
315
314
|
<pre>
|
316
315
|
reg.intercept( :foo ).
|
317
316
|
doing { |ch,ctx| ...; p ctx.data[:options][:value]; ... }.
|
318
317
|
with_options( :value => "hello" )
|
319
318
|
</pre>
|
320
|
-
|
321
|
-
<p>With blocks, of course, the value of such an approach is limited.<br />
|
322
|
-
</p>
|
319
|
+
<p>With blocks, of course, the value of such an approach is limited.</p>
|
323
320
|
</div>
|
324
321
|
|
325
322
|
|
@@ -338,14 +335,13 @@
|
|
338
335
|
|
339
336
|
<p>You can specify the priority as an option when attaching an interceptor:</p>
|
340
337
|
|
338
|
+
|
341
339
|
<pre>
|
342
340
|
reg.register( :foo ) { ... }
|
343
341
|
reg.intercept( :foo ).with { Something }.with_options( :priority => 100 )
|
344
342
|
reg.intercept( :foo ).with { SomethingElse }.with_options( :priority => 50 )
|
345
343
|
</pre>
|
346
|
-
|
347
|
-
<p>Without the priorities, when a method of <code>:foo</code> was invoked, Something would be called first, and then SomethingElse. <em>With</em> the priorities (as specified), SomethingElse would be called before Something (since SomethingElse has a lower priority).<br />
|
348
|
-
</p>
|
344
|
+
<p>Without the priorities, when a method of <code>:foo</code> was invoked, Something would be called first, and then SomethingElse. <em>With</em> the priorities (as specified), SomethingElse would be called before Something (since SomethingElse has a lower priority).</p>
|
349
345
|
</div>
|
350
346
|
|
351
347
|
|
@@ -362,6 +358,7 @@
|
|
362
358
|
|
363
359
|
<p>An interceptor factory can be any object, as long as it implements the method <code>#new</code> with two parameters, the <em>service point</em> (service “definition”) of the service that the interceptor will be bound to, and a hash of the options that were passed to the interceptor when it was attached to the service. This method should then return a new interceptor instance, which must implement the <code>#process</code> method. The <code>#process</code> method should accept two parameters: an object representing the <em>chain</em> of interceptors, and the invocation <em>context</em>.</p>
|
364
360
|
|
361
|
+
|
365
362
|
<pre>
|
366
363
|
class MyInterceptorFactory
|
367
364
|
def initialize( point, options )
|
@@ -377,9 +374,9 @@
|
|
377
374
|
end
|
378
375
|
end
|
379
376
|
</pre>
|
380
|
-
|
381
377
|
<p>Once you’ve created your factory, you can attach it to a service:</p>
|
382
378
|
|
379
|
+
|
383
380
|
<pre>
|
384
381
|
reg.intercept( :foo ).with { MyInterceptorFactory }
|
385
382
|
</pre>
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.
|
18
|
-
Manual Last Updated: <strong>2004-11-
|
17
|
+
Needle Version: <strong>1.2.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -222,8 +222,7 @@
|
|
222
222
|
<div class="section">
|
223
223
|
<p>Service models are the mechanism by which a client can specify how the lifecycle of a particular service should be managed. By default, all services are managed as <em>singletons</em>, but it is a simple matter to choose a different behavior when a service is registered.</p>
|
224
224
|
|
225
|
-
<p>Underneath, service models are implemented using an <em>instantiation pipeline</em
|
226
|
-
</p>
|
225
|
+
<p>Underneath, service models are implemented using an <em>instantiation pipeline</em>.</p>
|
227
226
|
</div>
|
228
227
|
|
229
228
|
|
@@ -243,11 +242,11 @@
|
|
243
242
|
<h3>Standard Pipeline Elements</h3>
|
244
243
|
|
245
244
|
<p>There are five standard pipeline elements available in Needle (although you may certainly create your own):</p>
|
246
|
-
|
247
245
|
<ul>
|
248
246
|
<li><code>deferred</code>: this will always return a proxy that wraps subsequent pipeline elements, causing the subsequent elements to be executed only when a method is invoked on the proxy (at which point the method is then delegated to the resulting service).</li>
|
249
247
|
<li><code>initialize</code>: this will invoke a method on the resulting service (defaults to <code>initialize_service</code>, though it can be changed). It is used for doing final initialization of services (for services that need it).</li>
|
250
248
|
<li><code>interceptor</code>: this element is used to implement the proxy that wraps the interceptors around the service. It is only attached to the pipeline when an interceptor is attached to a service.</li>
|
249
|
+
<li><code>multiton</code>: this element enforces a multiton guard on the service. This means that the service will only be instantiated once for each unique set of parameters given to the service.</li>
|
251
250
|
<li><code>singleton</code>: this is a multiplicity guard that ensures a service is instantiated only once per process.</li>
|
252
251
|
<li><code>threaded</code>: this is like the <code>singleton</code> element, but it ensures that a service is instantiated no more than once <em>per thread</em>.</li>
|
253
252
|
</ul>
|
@@ -262,6 +261,7 @@
|
|
262
261
|
|
263
262
|
<p>Creating new pipeline elements simple. Just create a new class that extends <code>Needle::Pipeline::Element</code>. Set the default pipeline priority (using the <code>#set_default_priority</code> class method), and then implement the <code>#call</code> method (accepting at least two parameters: the container and the service point).</p>
|
264
263
|
|
264
|
+
|
265
265
|
<pre>
|
266
266
|
require 'needle/pipeline/element'
|
267
267
|
|
@@ -276,7 +276,6 @@
|
|
276
276
|
end
|
277
277
|
end
|
278
278
|
</pre>
|
279
|
-
|
280
279
|
<p>To invoke the next element of the pipeline, just invoke <code>#succ.call(...)</code>.</p>
|
281
280
|
|
282
281
|
<p>If needed, you can also implement <code>#initialize_element</code> (with no arguments), which you may invoke to perform initialization of the element. From there, you can access the options that were given to the element via the <code>#options</code> accessor.</p>
|
@@ -287,16 +286,17 @@
|
|
287
286
|
|
288
287
|
<p>You can specify the pipeline elements to use for a service via the <code>:pipeline</code> option. This must refer to an array, each element of which must be either a symbol (in which case it references an element of the <code>:pipeline_elements</code> service), or a class (in which case it must implement the interface required by @Needle::Pipeline::Element).</p>
|
289
288
|
|
289
|
+
|
290
290
|
<pre>
|
291
291
|
reg.register( :foo, :pipeline => [ :singleton, MyPipelineElement ] ) { ... }
|
292
292
|
</pre>
|
293
|
-
|
294
293
|
<p>The elements will be sorted based on their priorities, with lower priorities sorting closer to the instantiation block, and higher priorities sorting closer to the client.</p>
|
295
294
|
|
296
295
|
<h3>Making Custom Pipeline Elements Available</h3>
|
297
296
|
|
298
297
|
<p>You can make your custom pipeline elements available (so they can be referenced by symbol, instead of class name) by adding them to the <code>:pipeline_elements</code> service:</p>
|
299
298
|
|
299
|
+
|
300
300
|
<pre>
|
301
301
|
reg.pipeline_elements[ :my_pipeline_element ] = MyPipelineElement
|
302
302
|
reg.register( :foo, :pipeline => [ :singleton, :my_pipeline_element ] ) { ... }
|
@@ -323,6 +323,26 @@
|
|
323
323
|
<th style="text-align:left;">Pipeline</th>
|
324
324
|
<th style="text-align:left;">Effect</th>
|
325
325
|
</tr>
|
326
|
+
<tr>
|
327
|
+
<td style="vertical-align:top;"><code>:multiton</code></td>
|
328
|
+
<td style="vertical-align:top;"><code>:multiton</code></td>
|
329
|
+
<td>The returned value will be unique for each unique parameter set given to the service.</td>
|
330
|
+
</tr>
|
331
|
+
<tr>
|
332
|
+
<td style="vertical-align:top;"><code>:multiton_deferred</code></td>
|
333
|
+
<td style="vertical-align:top;"><code>:multiton</code>, <code>:deferred</code></td>
|
334
|
+
<td>As <code>:multiton</code>, but a proxy is returned, deferring the instantiation of the service itself until a method is invoked on it.</td>
|
335
|
+
</tr>
|
336
|
+
<tr>
|
337
|
+
<td style="vertical-align:top;"><code>:multiton_initialize</code></td>
|
338
|
+
<td style="vertical-align:top;"><code>:multiton</code>, <code>:initialize</code></td>
|
339
|
+
<td>As <code>:multiton</code>, but invoke an initialization method on every service instance as soon as they are created.</td>
|
340
|
+
</tr>
|
341
|
+
<tr>
|
342
|
+
<td style="vertical-align:top;"><code>:multiton_deferred_initialize</code></td>
|
343
|
+
<td style="vertical-align:top;"><code>:multiton</code>, <code>:deferred</code>, <code>:initialize</code></td>
|
344
|
+
<td>As <code>:multiton</code>, but a proxy is returned, deferring the instantiation of the service itself until a method is invoked on it. When the service is instantiated, an initialization method will be invoked on it.</td>
|
345
|
+
</tr>
|
326
346
|
<tr>
|
327
347
|
<td style="vertical-align:top;"><code>:prototype</code></td>
|
328
348
|
<td style="vertical-align:top;">(empty)</td>
|
@@ -385,18 +405,21 @@
|
|
385
405
|
</tr>
|
386
406
|
</table>
|
387
407
|
|
408
|
+
|
409
|
+
|
388
410
|
<h3>Specifying a Service Model</h3>
|
389
411
|
|
390
412
|
<p>You specify the service model by passing the <code>:model</code> option when you register a service. (You must only specify <em>either</em> the model, <em>or</em> the pipeline, but not both.)</p>
|
391
413
|
|
414
|
+
|
392
415
|
<pre>
|
393
416
|
reg.register( :foo, :model => :singleton_deferred ) {...}
|
394
417
|
</pre>
|
395
|
-
|
396
418
|
<h3>Defining New Models</h3>
|
397
419
|
|
398
420
|
<p>You can create your own service models by adding the corresponding pipelines to the <code>:service_models</code> service:</p>
|
399
421
|
|
422
|
+
|
400
423
|
<pre>
|
401
424
|
reg.service_models[ :my_service_model ] = [ :singleton, :my_pipeline_element ]
|
402
425
|
reg.register( :foo, :model => :my_service_model ) {...}
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.
|
18
|
-
Manual Last Updated: <strong>2004-11-
|
17
|
+
Needle Version: <strong>1.2.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -224,8 +224,7 @@
|
|
224
224
|
|
225
225
|
<p>Needle’s logging framework is built on top of the standard Ruby <code>Logger</code> library. However, it extends that library to add additional functionality, including customizable message formats and a centralized location for obtaining logger instances.</p>
|
226
226
|
|
227
|
-
<p>This centralized location is the LogFactory
|
228
|
-
</p>
|
227
|
+
<p>This centralized location is the LogFactory.</p>
|
229
228
|
</div>
|
230
229
|
|
231
230
|
|
@@ -240,34 +239,43 @@
|
|
240
239
|
<div class="section">
|
241
240
|
<p>The LogFactory is available as a service, so that any component that needs a logger instance can gain easy access to one. The factory’s service name is <code>:logs</code>.</p>
|
242
241
|
|
242
|
+
|
243
243
|
<pre>
|
244
244
|
factory = reg.logs
|
245
245
|
</pre>
|
246
|
-
|
247
246
|
<p>You obtain logger instances from the factory by passing a logger name to <code>#get</code>:</p>
|
248
247
|
|
248
|
+
|
249
249
|
<pre>
|
250
250
|
logger = reg.logs.get "a logger name"
|
251
251
|
</pre>
|
252
|
-
|
253
252
|
<p>Subsequent calls to <code>#get</code> will return the same logger instance for the given logger name.</p>
|
254
253
|
|
255
254
|
<h3>Loggers for Services</h3>
|
256
255
|
|
257
256
|
<p>Typically, you’ll use this to assign a logger instance to a service when it is constructed. In that case, the name of the logger is the fully-qualified name of the service:</p>
|
258
257
|
|
258
|
+
|
259
259
|
<pre>
|
260
260
|
reg.register( :foo ) do |c,p|
|
261
261
|
Foo.new( c.logs.get( p.fullname ) )
|
262
262
|
end
|
263
263
|
</pre>
|
264
|
-
|
265
264
|
<p>As a convenience, if the value passed to <code>#get</code> responds to either <code>fullname</code> or <code>name</code>, the return value of that message will be used as the name. Thus, you can do the following:</p>
|
266
265
|
|
266
|
+
|
267
267
|
<pre>
|
268
268
|
reg.register( :foo ) do |c,p|
|
269
269
|
Foo.new( c.logs.get( p ) )
|
270
270
|
end
|
271
|
+
</pre>
|
272
|
+
<p>As a further convenience, there is a <code>:log_for</code> service that is parameterized. Just pass the name of the log to retreive (or the service point instance) and it will return the log handle directly:</p>
|
273
|
+
|
274
|
+
|
275
|
+
<pre>
|
276
|
+
reg.register( :foo ) do |c,p|
|
277
|
+
Foo.new( c.log_for( p ) )
|
278
|
+
end
|
271
279
|
</pre>
|
272
280
|
</div>
|
273
281
|
|
@@ -322,8 +330,11 @@
|
|
322
330
|
</tr>
|
323
331
|
</table>
|
324
332
|
|
333
|
+
|
334
|
+
|
325
335
|
<p>By default, the filename is ”./needle.log”, and the roll_size is one megabyte. The default level is <code>:debug</code>. If you wanted to specify a different filename and default level of <code>:warn</code>, you could do:</p>
|
326
336
|
|
337
|
+
|
327
338
|
<pre>
|
328
339
|
reg = Needle::Registry.new(
|
329
340
|
:logs => {
|
@@ -331,9 +342,9 @@
|
|
331
342
|
:default_level => :warn }
|
332
343
|
)
|
333
344
|
</pre>
|
334
|
-
|
335
345
|
<p>Alternatively, you can easily put the logging configuration in a <span class="caps">YAML</span> file and read it in, like so:</p>
|
336
346
|
|
347
|
+
|
337
348
|
<pre>
|
338
349
|
require 'yaml'
|
339
350
|
reg = Needle::Registry.new(
|
@@ -14,8 +14,8 @@
|
|
14
14
|
</div>
|
15
15
|
</td><td valign='middle' align='right'>
|
16
16
|
<div class="info">
|
17
|
-
Needle Version: <strong>1.
|
18
|
-
Manual Last Updated: <strong>2004-11-
|
17
|
+
Needle Version: <strong>1.2.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
|
19
19
|
</div>
|
20
20
|
</td></tr>
|
21
21
|
</table>
|
@@ -222,8 +222,7 @@
|
|
222
222
|
<div class="section">
|
223
223
|
<p>Using Needle as it has been presented so far works fine when you are dealing with a single application, all self-encapsulated. When you start dealing with combining multiple libraries, each potentially written by a different author, into a single registry, things get a little more complicated.</p>
|
224
224
|
|
225
|
-
<p>Needle provides a way for service authors to share their services. All it requires is that authors centralize their service configuration
|
226
|
-
</p>
|
225
|
+
<p>Needle provides a way for service authors to share their services. All it requires is that authors centralize their service configuration.</p>
|
227
226
|
</div>
|
228
227
|
|
229
228
|
|
@@ -240,6 +239,7 @@
|
|
240
239
|
|
241
240
|
<p>For example, if I had a library of cryptographic routines and I wanted to make them accessible as Needle services, I would create a module to contain the service definitions. Typically, this module will be defined in a file called “services.rb”, although you can certainly name it whatever you like.</p>
|
242
241
|
|
242
|
+
|
243
243
|
<pre>
|
244
244
|
module Crypto
|
245
245
|
|
@@ -262,11 +262,9 @@
|
|
262
262
|
|
263
263
|
end
|
264
264
|
</pre>
|
265
|
-
|
266
265
|
<p>Notice that there are no explicit dependencies on Needle, only on the interfaces Needle publishes. Thus, third-parties can add service configuration modules to their libraries without introducing dependencies on Needle.</p>
|
267
266
|
|
268
|
-
<p>Once a service library has been created, it can then be accessed from another library or application that wishes to import those services
|
269
|
-
</p>
|
267
|
+
<p>Once a service library has been created, it can then be accessed from another library or application that wishes to import those services.</p>
|
270
268
|
</div>
|
271
269
|
|
272
270
|
|
@@ -281,6 +279,7 @@
|
|
281
279
|
<div class="section">
|
282
280
|
<p>Using the libraries is as simple as requiring the file that has the service definitions, and then invoking the <code>#register_services</code> module function:</p>
|
283
281
|
|
282
|
+
|
284
283
|
<pre>
|
285
284
|
require 'needle'
|
286
285
|
|
@@ -294,9 +293,9 @@
|
|
294
293
|
|
295
294
|
prng = reg.crypto.prng
|
296
295
|
</pre>
|
297
|
-
|
298
296
|
<p>To make this easier, the Container class has a convenience method named <code>#require</code>:</p>
|
299
297
|
|
298
|
+
|
300
299
|
<pre>
|
301
300
|
require 'needle'
|
302
301
|
|
@@ -308,9 +307,7 @@
|
|
308
307
|
|
309
308
|
prng = reg.crypto.prng
|
310
309
|
</pre>
|
311
|
-
|
312
|
-
<p>The <code>Container#require</code> method will require the file, and then look for a <code>#register_services</code> method of the named module. It will execute that method, passing the container as an argument.<br />
|
313
|
-
</p>
|
310
|
+
<p>The <code>Container#require</code> method will require the file, and then look for a <code>#register_services</code> method of the named module. It will execute that method, passing the container as an argument.</p>
|
314
311
|
</div>
|
315
312
|
|
316
313
|
|