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
@@ -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.1.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-11 17:31 GMT</strong>
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).<br />
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.<br />
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&#8217;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).<br />
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.1.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-11 17:31 GMT</strong>
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.<br />
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&#8217;ll have one instance of each interceptor for each instance of your service.<br />
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&#8217;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<br />
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&#8217;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&#8217;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 =&gt; [ "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 =&gt; "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 =&gt; 100 )
344
342
  reg.intercept( :foo ).with { SomethingElse }.with_options( :priority =&gt; 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 &#8220;definition&#8221;) 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&#8217;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.1.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-11 17:31 GMT</strong>
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>.<br />
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 =&gt; [ :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 =&gt; [ :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 =&gt; :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 =&gt; :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.1.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-11 17:31 GMT</strong>
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&#8217;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.<br />
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&#8217;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&#8217;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 &#8221;./needle.log&#8221;, 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 =&gt; {
@@ -331,9 +342,9 @@
331
342
  :default_level =&gt; :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.1.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-11 17:31 GMT</strong>
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.<br />
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 &#8220;services.rb&#8221;, 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.<br />
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