needle 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/doc/manual-html/chapter-1.html +138 -78
  2. data/doc/manual-html/chapter-2.html +180 -99
  3. data/doc/manual-html/chapter-3.html +111 -75
  4. data/doc/manual-html/chapter-4.html +80 -48
  5. data/doc/manual-html/chapter-5.html +106 -56
  6. data/doc/manual-html/chapter-6.html +82 -34
  7. data/doc/manual-html/chapter-7.html +74 -38
  8. data/doc/manual-html/chapter-8.html +70 -41
  9. data/doc/manual-html/chapter-9.html +88 -63
  10. data/doc/manual-html/index.html +6 -6
  11. data/doc/manual-html/needle.png +0 -0
  12. data/doc/manual-html/{manual.css → stylesheets/manual.css} +83 -10
  13. data/doc/manual-html/stylesheets/ruby.css +17 -0
  14. data/doc/manual/chapter.erb +20 -0
  15. data/doc/manual/img/Needle.ai +0 -0
  16. data/doc/manual/img/needle.png +0 -0
  17. data/doc/manual/manual.rb +80 -5
  18. data/doc/manual/manual.yml +3 -3
  19. data/doc/manual/page.erb +1 -1
  20. data/doc/manual/parts/01_use_cases.txt +70 -70
  21. data/doc/manual/parts/02_creating.txt +19 -19
  22. data/doc/manual/parts/02_namespaces.txt +29 -29
  23. data/doc/manual/parts/02_services.txt +40 -41
  24. data/doc/manual/parts/03_conventional.txt +20 -20
  25. data/doc/manual/parts/03_locator.txt +44 -44
  26. data/doc/manual/parts/04_overview.txt +1 -1
  27. data/doc/manual/parts/04_setup.txt +32 -32
  28. data/doc/manual/parts/customizing_contexts.txt +14 -14
  29. data/doc/manual/parts/customizing_interceptors.txt +25 -25
  30. data/doc/manual/parts/customizing_namespaces.txt +12 -12
  31. data/doc/manual/parts/interceptors_attaching.txt +29 -30
  32. data/doc/manual/parts/interceptors_custom.txt +16 -16
  33. data/doc/manual/parts/interceptors_ordering.txt +5 -5
  34. data/doc/manual/parts/libraries_creating.txt +18 -18
  35. data/doc/manual/parts/libraries_using.txt +19 -19
  36. data/doc/manual/parts/logging_configuration.txt +13 -13
  37. data/doc/manual/parts/logging_logfactory.txt +21 -22
  38. data/doc/manual/parts/models_models.txt +8 -8
  39. data/doc/manual/parts/models_overview.txt +1 -1
  40. data/doc/manual/parts/models_pipelines.txt +22 -22
  41. data/doc/manual/{manual.css → stylesheets/manual.css} +83 -10
  42. data/doc/manual/stylesheets/ruby.css +17 -0
  43. data/lib/needle/definition-context.rb +3 -2
  44. data/lib/needle/lifecycle/proxy.rb +1 -1
  45. data/lib/needle/version.rb +1 -1
  46. metadata +94 -85
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head>
3
3
  <title>Needle Manual :: Chapter 3: Service Locator</title>
4
- <link type="text/css" rel="stylesheet" href="manual.css" />
4
+ <link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
5
5
  </head>
6
6
 
7
7
  <body>
@@ -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.2.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
17
+ Needle Version: <strong>1.2.1</strong><br />
18
+ Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -208,7 +208,17 @@
208
208
 
209
209
  <div id="content">
210
210
 
211
- <h1>3. Service Locator</h1>
211
+ <div class="top"><div class="prevnext">
212
+
213
+ <a href="chapter-2.html">Previous (2. Registry)</a> |
214
+
215
+ <a href="index.html">Up</a>
216
+
217
+ | <a href="chapter-4.html">Next (4. Dependency Injection)</a>
218
+
219
+ </div></div>
220
+
221
+ <h1>3. Service Locator</h1>
212
222
 
213
223
 
214
224
 
@@ -222,7 +232,10 @@
222
232
  <div class="section">
223
233
  <p>The <em>service locator</em> design pattern can be considered a subset of dependency injection. Because it is simpler, it is as good of a place to start teaching DI as any.</p>
224
234
 
235
+
225
236
  <p>To demonstrate both techniques, we&#8217;ll pretend we&#8217;re going to write an online forum application. To start, let&#8217;s come up with a rough design by cataloging the components we&#8217;ll need.</p>
237
+
238
+
226
239
  <ul>
227
240
  <li><code>Logger</code>. This will be used to write messages to a file.</li>
228
241
  <li><code>Authenticator</code>. This will be used to validate whether a user is who they say they are.</li>
@@ -232,9 +245,13 @@
232
245
  <li><code>Application</code>. The controller that ties it all together.</li>
233
246
  </ul>
234
247
 
248
+
235
249
  <p>(Of course, a <em>real</em> online forum application would be significantly more complex, but the above components will do for our purposes.)</p>
236
250
 
251
+
237
252
  <p>The dependencies between these components are:</p>
253
+
254
+
238
255
  <ul>
239
256
  <li><code>Authenticator</code> <em>has</em> <code>Database</code> (for querying user authentication information) and <code>Logger</code></li>
240
257
  <li><code>Database</code> <em>has</em> <code>Logger</code> (for indicating database accesses and query times)</li>
@@ -256,31 +273,35 @@
256
273
  <p>A conventional architecture will have each component instantiate its own dependencies. For example, the <code>Application</code> would do something like this:</p>
257
274
 
258
275
 
259
- <pre>
260
- class Application
261
- def initialize
262
- @logger = Logger.new
263
- @authenticator = Authenticator.new
264
- @database = Database.new
265
- @view = View.new
266
- @session = Session.new
267
- end
268
- end
269
- </pre>
276
+ <div class='figure'>
277
+ <span class='caption'>A conventional application implementation [ruby]</span>
278
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">Application</span>
279
+ <span class="keyword">def </span><span class="method">initialize</span>
280
+ <span class="attribute">@logger</span> <span class="punct">=</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span>
281
+ <span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span>
282
+ <span class="attribute">@database</span> <span class="punct">=</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span>
283
+ <span class="attribute">@view</span> <span class="punct">=</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span>
284
+ <span class="attribute">@session</span> <span class="punct">=</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span>
285
+ <span class="keyword">end</span>
286
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
287
+
288
+
270
289
  <p>However, the above is already flawed, because the <code>Authenticator</code> and the <code>Session</code> both need access to the <code>Database</code>, so you really need to make sure you instantiate things in the right order and pass them as parameters to the constructor of each object that needs them, like so:</p>
271
290
 
272
291
 
273
- <pre>
274
- class Application
275
- def initialize
276
- @view = View.new
277
- @logger = Logger.new
278
- @database = Database.new( @logger )
279
- @authenticator = Authenticator.new( @logger, @database )
280
- @session = Session.new( @logger, @database )
281
- end
282
- end
283
- </pre>
292
+ <div class='figure'>
293
+ <span class='caption'>A parameterized application implementation [ruby]</span>
294
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">Application</span>
295
+ <span class="keyword">def </span><span class="method">initialize</span>
296
+ <span class="attribute">@view</span> <span class="punct">=</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span>
297
+ <span class="attribute">@logger</span> <span class="punct">=</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span>
298
+ <span class="attribute">@database</span> <span class="punct">=</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span> <span class="punct">)</span>
299
+ <span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span><span class="punct">,</span> <span class="attribute">@database</span> <span class="punct">)</span>
300
+ <span class="attribute">@session</span> <span class="punct">=</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="attribute">@logger</span><span class="punct">,</span> <span class="attribute">@database</span> <span class="punct">)</span>
301
+ <span class="keyword">end</span>
302
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
303
+
304
+
284
305
  <p>The problem with this is that if you later decide that <code>View</code> needs to access the database, you need to rearrange the order of how things are instantiated in the <code>Application</code> constructor.</p>
285
306
  </div>
286
307
 
@@ -297,68 +318,83 @@
297
318
  <p>The <em>service locator</em> pattern makes things a <em>little</em> easier. Instead of instantiating everything in the constructor of the <code>Application</code>, you can create a factory method somewhere that returns the new <code>Application</code> instance. Then, inside of this factory method, you assign each new object to collection, and pass that collection to each constructor.</p>
298
319
 
299
320
 
300
- <pre>
301
- require 'needle'
302
-
303
- def create_application
304
- locator = Needle::Registry.new
305
-
306
- locator.register( :view ) { View.new(locator) }
307
- locator.register( :logger ) { Logger.new(locator) }
308
- locator.register( :database ) { Database.new(locator) }
309
- locator.register( :authenticator ) {Authenticator.new(locator) }
310
- locator.register( :session ) { Session.new(locator) }
311
- locator.register( :app ) { Application.new(locator) }
312
-
313
- locator[:app]
314
- end
315
-
316
- class Application
317
- def initialize( locator )
318
- @view = locator[:view]
319
- @logger = locator[:logger]
320
- @database = locator[:database]
321
- @authenticator = locator[:authenticator]
322
- @session = locator[:session]
323
- end
324
- end
325
-
326
- class Session
327
- def initialize( locator )
328
- @database = locator[:database]
329
- @logger = locator[:logger]
330
- end
331
- end
332
-
333
- ...
334
- </pre>
321
+ <div class='figure'>
322
+ <span class='caption'>Service locator example [ruby]</span>
323
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">require</span> <span class="punct">'</span><span class="string">needle</span><span class="punct">'</span>
324
+
325
+ <span class="keyword">def </span><span class="method">create_application</span>
326
+ <span class="ident">locator</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">new</span>
327
+
328
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:view</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
329
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:logger</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
330
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:database</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
331
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:authenticator</span> <span class="punct">)</span> <span class="punct">{</span><span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
332
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:session</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
333
+ <span class="ident">locator</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:app</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
334
+
335
+ <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
336
+ <span class="keyword">end</span>
337
+
338
+ <span class="keyword">class </span><span class="class">Application</span>
339
+ <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">locator</span> <span class="punct">)</span>
340
+ <span class="attribute">@view</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:view</span><span class="punct">]</span>
341
+ <span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:logger</span><span class="punct">]</span>
342
+ <span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:database</span><span class="punct">]</span>
343
+ <span class="attribute">@authenticator</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:authenticator</span><span class="punct">]</span>
344
+ <span class="attribute">@session</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:session</span><span class="punct">]</span>
345
+ <span class="keyword">end</span>
346
+ <span class="keyword">end</span>
347
+
348
+ <span class="keyword">class </span><span class="class">Session</span>
349
+ <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">locator</span> <span class="punct">)</span>
350
+ <span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:database</span><span class="punct">]</span>
351
+ <span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:logger</span><span class="punct">]</span>
352
+ <span class="keyword">end</span>
353
+ <span class="keyword">end</span>
354
+
355
+ <span class="punct">...</span></pre></div></td></tr></table></div></div>
356
+
357
+
335
358
  <p>This has the benefit of allowing each object to construct itself <em>� la carte</em> from the objects in the locator. Also, each object no longer cares what class implements each service&#8212;it only cares that each object implements the methods it will attempt to invoke on that object.</p>
336
359
 
360
+
337
361
  <p>Also, because Needle defers the instantiation of each service until the service is actually requested, we can actually register each item with the locator in any arbitrary order. All that is happening is the block is associated with the symbol, so that when the service is requested, the corresponding block is invoked. What is more, by default each service is then cached, so that it is only instantiated once.</p>
338
362
 
363
+
339
364
  <p>Thus, when we get the <code>:app</code> service (on the last line), the <code>Application</code> constructor is invoked, passing the locator to the constructor. Inside the constructor, <code>Application</code> retrieves each of its dependencies from the locator, causing each of them to be instantiated in turn. By this means, everything is initialized and constructed when the <code>create_application</code> method returns.</p>
340
365
 
366
+
341
367
  <p>In the interest of brevity, the <code>create_application</code> could have been written like this, using a &#8220;builder&#8221; object (called <code>b</code> in the example below) to help register the services:</p>
342
368
 
343
369
 
344
- <pre>
345
- def create_application
346
- locator = Needle::Registry.define do |b|
347
- b.view { View.new(locator) }
348
- b.logger { Logger.new(locator) }
349
- b.database { Database.new(locator) }
350
- b.authenticator {Authenticator.new(locator) }
351
- b.session { Session.new(locator) }
352
- b.app { Application.new(locator) }
353
- end
354
-
355
- locator[:app]
356
- end
357
- </pre>
370
+ <div class='figure'>
371
+ <span class='caption'>Service locator example using #define [ruby]</span>
372
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">def </span><span class="method">create_application</span>
373
+ <span class="ident">locator</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">define</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">b</span><span class="punct">|</span>
374
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
375
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
376
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
377
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">{</span><span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
378
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
379
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">app</span> <span class="punct">{</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">locator</span><span class="punct">)</span> <span class="punct">}</span>
380
+ <span class="keyword">end</span>
381
+
382
+ <span class="ident">locator</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
383
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
358
384
  </div>
359
385
 
360
386
 
361
387
 
388
+ <div class="bottom"><div class="prevnext">
389
+
390
+ <a href="chapter-2.html">Previous (2. Registry)</a> |
391
+
392
+ <a href="index.html">Up</a>
393
+
394
+ | <a href="chapter-4.html">Next (4. Dependency Injection)</a>
395
+
396
+ </div></div>
397
+
362
398
 
363
399
  </div>
364
400
 
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head>
3
3
  <title>Needle Manual :: Chapter 4: Dependency Injection</title>
4
- <link type="text/css" rel="stylesheet" href="manual.css" />
4
+ <link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
5
5
  </head>
6
6
 
7
7
  <body>
@@ -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.2.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
17
+ Needle Version: <strong>1.2.1</strong><br />
18
+ Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -208,7 +208,17 @@
208
208
 
209
209
  <div id="content">
210
210
 
211
- <h1>4. Dependency Injection</h1>
211
+ <div class="top"><div class="prevnext">
212
+
213
+ <a href="chapter-3.html">Previous (3. Service Locator)</a> |
214
+
215
+ <a href="index.html">Up</a>
216
+
217
+ | <a href="chapter-5.html">Next (5. Interceptors)</a>
218
+
219
+ </div></div>
220
+
221
+ <h1>4. Dependency Injection</h1>
212
222
 
213
223
 
214
224
 
@@ -221,15 +231,24 @@
221
231
 
222
232
  <div class="section">
223
233
  <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>
234
+
235
+
236
+ <ol>
237
+ <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).</li>
238
+ </ol>
239
+
240
+
241
+ <ol>
242
+ <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.</li>
243
+ </ol>
244
+
245
+
224
246
  <ol>
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).
226
- </li>
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.
228
- </li>
229
- <li>For deep dependency graphs, it can become cumbersome to have to pass the locator to each constructor.</li>
247
+ <li>For deep dependency graphs, it can become cumbersome to have to pass the locator to each constructor.</li>
230
248
  </ol>
231
249
 
232
- <p>This is where <em>dependency injection</em> comes in. It allows you to define how each service is initialized, including setting dependencies (either via constructor parameters or via property accessors). In fact, it can do a lot more than that, even allowing you to specify how the lifecycle of the service should be managed and hooking &#8220;interceptors&#8221; onto the service to filter method invocations.</p>
250
+
251
+ <p>This is where <em>dependency injection</em> comes in. It allows you to define how each service is initialized, including setting dependencies (either via constructor parameters or via property accessors). In fact, it can do a lot more than that, even allowing you to specify how the lifestyle of the service should be managed and hooking &#8220;interceptors&#8221; onto the service to filter method invocations.</p>
233
252
  </div>
234
253
 
235
254
 
@@ -245,51 +264,64 @@
245
264
  <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>
246
265
 
247
266
 
248
- <pre>
249
- require 'needle'
250
-
251
- def create_application
252
- registry = Needle::Registry.define do |b|
253
- b.view { View.new }
254
- b.logger { Logger.new }
255
- b.database { Database.new( b.logger ) }
256
- b.authenticator { Authenticator.new(b.logger, b.database) }
257
- b.session { Session.new(b.logger, b.database) }
258
-
259
- b.app do
260
- app = Application.new
261
- app.logger = b.logger
262
- app.view = b.view
263
- app.database = b.database
264
- app.authenticator = b.authenticator
265
- app.session = b.session
266
- app
267
- end
268
- end
269
-
270
- registry[:app]
271
- end
272
-
273
- class Application
274
- attr_writer :view, :logger, :database, :authenticator, :session
275
- end
276
-
277
- class Session
278
- def initialize( logger, database )
279
- @database = database
280
- @logger = logger
281
- end
282
- end
283
-
284
- ...
285
- </pre>
267
+ <div class='figure'>
268
+ <span class='caption'>Dependency injection example [ruby]</span>
269
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">require</span> <span class="punct">'</span><span class="string">needle</span><span class="punct">'</span>
270
+
271
+ <span class="keyword">def </span><span class="method">create_application</span>
272
+ <span class="ident">registry</span> <span class="punct">=</span> <span class="constant">Needle</span><span class="punct">::</span><span class="constant">Registry</span><span class="punct">.</span><span class="ident">define</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">b</span><span class="punct">|</span>
273
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">{</span> <span class="constant">View</span><span class="punct">.</span><span class="ident">new</span> <span class="punct">}</span>
274
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">{</span> <span class="constant">Logger</span><span class="punct">.</span><span class="ident">new</span> <span class="punct">}</span>
275
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">{</span> <span class="constant">Database</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">)</span> <span class="punct">}</span>
276
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">{</span> <span class="constant">Authenticator</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span><span class="punct">,</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span><span class="punct">)</span> <span class="punct">}</span>
277
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">{</span> <span class="constant">Session</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span><span class="punct">,</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span><span class="punct">)</span> <span class="punct">}</span>
278
+
279
+ <span class="ident">b</span><span class="punct">.</span><span class="ident">app</span> <span class="keyword">do</span>
280
+ <span class="ident">app</span> <span class="punct">=</span> <span class="constant">Application</span><span class="punct">.</span><span class="ident">new</span>
281
+ <span class="ident">app</span><span class="punct">.</span><span class="ident">logger</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">logger</span>
282
+ <span class="ident">app</span><span class="punct">.</span><span class="ident">view</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">view</span>
283
+ <span class="ident">app</span><span class="punct">.</span><span class="ident">database</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">database</span>
284
+ <span class="ident">app</span><span class="punct">.</span><span class="ident">authenticator</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">authenticator</span>
285
+ <span class="ident">app</span><span class="punct">.</span><span class="ident">session</span> <span class="punct">=</span> <span class="ident">b</span><span class="punct">.</span><span class="ident">session</span>
286
+ <span class="ident">app</span>
287
+ <span class="keyword">end</span>
288
+ <span class="keyword">end</span>
289
+
290
+ <span class="ident">registry</span><span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span>
291
+ <span class="keyword">end</span>
292
+
293
+ <span class="keyword">class </span><span class="class">Application</span>
294
+ <span class="ident">attr_writer</span> <span class="symbol">:view</span><span class="punct">,</span> <span class="symbol">:logger</span><span class="punct">,</span> <span class="symbol">:database</span><span class="punct">,</span> <span class="symbol">:authenticator</span><span class="punct">,</span> <span class="symbol">:session</span>
295
+ <span class="keyword">end</span>
296
+
297
+ <span class="keyword">class </span><span class="class">Session</span>
298
+ <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">logger</span><span class="punct">,</span> <span class="ident">database</span> <span class="punct">)</span>
299
+ <span class="attribute">@database</span> <span class="punct">=</span> <span class="ident">database</span>
300
+ <span class="attribute">@logger</span> <span class="punct">=</span> <span class="ident">logger</span>
301
+ <span class="keyword">end</span>
302
+ <span class="keyword">end</span>
303
+
304
+ <span class="punct">...</span></pre></div></td></tr></table></div></div>
305
+
306
+
286
307
  <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>
287
308
 
309
+
288
310
  <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>
289
311
  </div>
290
312
 
291
313
 
292
314
 
315
+ <div class="bottom"><div class="prevnext">
316
+
317
+ <a href="chapter-3.html">Previous (3. Service Locator)</a> |
318
+
319
+ <a href="index.html">Up</a>
320
+
321
+ | <a href="chapter-5.html">Next (5. Interceptors)</a>
322
+
323
+ </div></div>
324
+
293
325
 
294
326
  </div>
295
327
 
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head>
3
3
  <title>Needle Manual :: Chapter 5: Interceptors</title>
4
- <link type="text/css" rel="stylesheet" href="manual.css" />
4
+ <link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
5
5
  </head>
6
6
 
7
7
  <body>
@@ -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.2.0</strong><br />
18
- Manual Last Updated: <strong>2004-11-18 15:36 GMT</strong>
17
+ Needle Version: <strong>1.2.1</strong><br />
18
+ Manual Last Updated: <strong>2005-07-27 05:49 UTC</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -208,7 +208,17 @@
208
208
 
209
209
  <div id="content">
210
210
 
211
- <h1>5. Interceptors</h1>
211
+ <div class="top"><div class="prevnext">
212
+
213
+ <a href="chapter-4.html">Previous (4. Dependency Injection)</a> |
214
+
215
+ <a href="index.html">Up</a>
216
+
217
+ | <a href="chapter-6.html">Next (6. Service Models)</a>
218
+
219
+ </div></div>
220
+
221
+ <h1>5. Interceptors</h1>
212
222
 
213
223
 
214
224
 
@@ -222,8 +232,10 @@
222
232
  <div class="section">
223
233
  <p>Interceptors are objects (or blocks) that sit between a client and a service and <em>intercept</em> messages (methods) sent to the service. Each service may have many such interceptors. When control is passed to an interceptor, it may then do something before and after passing control to the next interceptor, possibly even returning instead of passing control. This allows for some simple <acronym title="Aspect-Oriented Programming">AOP</acronym>-like hooks to be placed on your services.</p>
224
234
 
235
+
225
236
  <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
237
 
238
+
227
239
  <p>You can, of course, implement your own interceptors as well.</p>
228
240
  </div>
229
241
 
@@ -239,8 +251,10 @@
239
251
  <div class="section">
240
252
  <p>Interceptors are implemented as proxy objects that front the requested service. Thus, if you request a service that has 3 interceptors wrapped around it, you&#8217;re really getting a proxy object back that will invoke the interceptors (in order) before the requested method of the service is invoked.</p>
241
253
 
254
+
242
255
  <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>
243
256
 
257
+
244
258
  <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>
245
259
  </div>
246
260
 
@@ -256,66 +270,85 @@
256
270
  <div class="section">
257
271
  <p>There are two ways to attach interceptors to your services. The first is to implement an interceptor <em>factory</em> that returns new interceptor <em>instances</em>, and attach the factory to your service. The second is to specify a block that implements the required functionality. Both have their uses.</p>
258
272
 
273
+
259
274
  <h3>Interceptor Factories</h3>
260
275
 
276
+
261
277
  <p>Interceptor factories are useful in situations where you want to implement some functionality and have it apply to multiple services. Interceptors from factories are also faster (less overhead) than interceptors from blocks, and so might be appropriate where performance is an issue.</p>
262
278
 
279
+
263
280
  <p>An example is the LoggingInterceptor that ships with Needle. Because it is functionality that could be used on any number of services, it is implemented as a factory.</p>
264
281
 
282
+
265
283
  <p>You can attach interceptor factories to your service using the <code>#interceptor(...).with {...}</code> syntax:</p>
266
284
 
267
285
 
268
- <pre>
269
- reg.register( :foo ) {...}
270
- reg.intercept( :foo ).with { MyInterceptorFactory }
271
- </pre>
286
+ <div class='figure'>
287
+ <span class='caption'>Attaching an interceptor to a service [ruby]</span>
288
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
289
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
290
+
291
+
272
292
  <p>Note that you could also make the interceptor factory a service:</p>
273
293
 
274
294
 
275
- <pre>
276
- reg.register( :foo ) {...}
277
- reg.register( :my_interceptor ) { MyInterceptorFactory }
278
- reg.intercept( :foo ).with { |c| c.my_interceptor }
279
- </pre>
295
+ <div class='figure'>
296
+ <span class='caption'>Attaching an service as an interceptor [ruby]</span>
297
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
298
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:my_interceptor</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span>
299
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">c</span><span class="punct">|</span> <span class="ident">c</span><span class="punct">.</span><span class="ident">my_interceptor</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
300
+
301
+
280
302
  <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>
281
303
 
282
304
 
283
- <pre>
284
- reg.register( :foo ) {...}
285
- reg.register( :my_interceptor ) { MyInterceptorFactory }
286
- reg.intercept( :foo ).with! { my_interceptor }
287
- </pre>
305
+ <div class='figure'>
306
+ <span class='caption'>Attaching an service as an interceptor via #with! [ruby]</span>
307
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
308
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:my_interceptor</span> <span class="punct">)</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span>
309
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with!</span> <span class="punct">{</span> <span class="ident">my_interceptor</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
310
+
311
+
288
312
  <h3>Blocks</h3>
289
313
 
314
+
290
315
  <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
291
316
  <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>
292
317
 
293
318
 
294
- <pre>
295
- reg.register( :foo ) {...}
296
- reg.intercept( :foo ).doing { |chain,ctx| ...; chain.process_next( ctx ) }
297
- </pre>
319
+ <div class='figure'>
320
+ <span class='caption'>Defining interceptors on the fly [ruby]</span>
321
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
322
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">doing</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">chain</span><span class="punct">,</span><span class="ident">ctx</span><span class="punct">|</span> <span class="punct">...;</span> <span class="ident">chain</span><span class="punct">.</span><span class="ident">process_next</span><span class="punct">(</span> <span class="ident">ctx</span> <span class="punct">)</span> <span class="punct">}</span></pre></div></td></tr></table></div></div>
323
+
324
+
298
325
  <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>
299
326
 
327
+
300
328
  <h3>Options</h3>
301
329
 
330
+
302
331
  <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>
303
332
 
304
333
 
305
- <pre>
306
- reg.register( :foo ) {...}
307
- reg.intercept( :foo ).
308
- with { |c| c.logging_interceptor }.
309
- with_options( :exclude =&gt; [ "method1", "method2" ] )
310
- </pre>
334
+ <div class='figure'>
335
+ <span class='caption'>Configuring interceptors [ruby]</span>
336
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{...}</span>
337
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span>
338
+ <span class="ident">with</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">c</span><span class="punct">|</span> <span class="ident">c</span><span class="punct">.</span><span class="ident">logging_interceptor</span> <span class="punct">}.</span>
339
+ <span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:exclude</span> <span class="punct">=&gt;</span> <span class="punct">[</span> <span class="punct">&quot;</span><span class="string">method1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">method2</span><span class="punct">&quot;</span> <span class="punct">]</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
340
+
341
+
311
342
  <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>
312
343
 
313
344
 
314
- <pre>
315
- reg.intercept( :foo ).
316
- doing { |ch,ctx| ...; p ctx.data[:options][:value]; ... }.
317
- with_options( :value =&gt; "hello" )
318
- </pre>
345
+ <div class='figure'>
346
+ <span class='caption'>Configuring #doing interceptors [ruby]</span>
347
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span>
348
+ <span class="ident">doing</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">ch</span><span class="punct">,</span><span class="ident">ctx</span><span class="punct">|</span> <span class="punct">...;</span> <span class="ident">p</span> <span class="ident">ctx</span><span class="punct">.</span><span class="ident">data</span><span class="punct">[</span><span class="symbol">:options</span><span class="punct">][</span><span class="symbol">:value</span><span class="punct">];</span> <span class="punct">...</span> <span class="punct">}.</span>
349
+ <span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:value</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">hello</span><span class="punct">&quot;</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
350
+
351
+
319
352
  <p>With blocks, of course, the value of such an approach is limited.</p>
320
353
  </div>
321
354
 
@@ -331,16 +364,20 @@
331
364
  <div class="section">
332
365
  <p>As was mentioned, a service may have multiple interceptors attached to it. By default, a method will be filtered by the interceptors in the same order that they were attached, with the first interceptor that was attached being the first one to intercept every method call.</p>
333
366
 
367
+
334
368
  <p>You can specify a different ordering of the interceptors by giving each one a <em>priority</em>. The priority is a number, where interceptors with a higher priority sort <em>closer</em> to the service, and those with lower priorities sort <em>further</em> from the service.</p>
335
369
 
370
+
336
371
  <p>You can specify the priority as an option when attaching an interceptor:</p>
337
372
 
338
373
 
339
- <pre>
340
- reg.register( :foo ) { ... }
341
- reg.intercept( :foo ).with { Something }.with_options( :priority =&gt; 100 )
342
- reg.intercept( :foo ).with { SomethingElse }.with_options( :priority =&gt; 50 )
343
- </pre>
374
+ <div class='figure'>
375
+ <span class='caption'>Setting interceptor priorities [ruby]</span>
376
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">register</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">)</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">}</span>
377
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">Something</span> <span class="punct">}.</span><span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:priority</span> <span class="punct">=&gt;</span> <span class="number">100</span> <span class="punct">)</span>
378
+ <span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">SomethingElse</span> <span class="punct">}.</span><span class="ident">with_options</span><span class="punct">(</span> <span class="symbol">:priority</span> <span class="punct">=&gt;</span> <span class="number">50</span> <span class="punct">)</span></pre></div></td></tr></table></div></div>
379
+
380
+
344
381
  <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>
345
382
  </div>
346
383
 
@@ -356,34 +393,47 @@
356
393
  <div class="section">
357
394
  <p>Creating your own interceptors is very easy. As was demonstrated earlier, you can always use blocks to implement an interceptor. However, for more complex interceptors, or for interceptors that you want to reuse across multiple services, you can also implement your own interceptor <em>factories</em>.</p>
358
395
 
396
+
359
397
  <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>
360
398
 
361
399
 
362
- <pre>
363
- class MyInterceptorFactory
364
- def initialize( point, options )
365
- ...
366
- end
367
-
368
- def process( chain, context )
369
- # context.sym : the name of the method that was invoked
370
- # context.args : the array of arguments passed to the method
371
- # context.block : the block passed to the method, if any
372
- # context.data : a hash that may be used to share data between interceptors
373
- return context.process_next( context )
374
- end
375
- end
376
- </pre>
400
+ <div class='figure'>
401
+ <span class='caption'>Custom interceptor example [ruby]</span>
402
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">class </span><span class="class">MyInterceptorFactory</span>
403
+ <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span> <span class="ident">point</span><span class="punct">,</span> <span class="ident">options</span> <span class="punct">)</span>
404
+ <span class="punct">...</span>
405
+ <span class="keyword">end</span>
406
+
407
+ <span class="keyword">def </span><span class="method">process</span><span class="punct">(</span> <span class="ident">chain</span><span class="punct">,</span> <span class="ident">context</span> <span class="punct">)</span>
408
+ <span class="comment"># context.sym : the name of the method that was invoked</span>
409
+ <span class="comment"># context.args : the array of arguments passed to the method</span>
410
+ <span class="comment"># context.block : the block passed to the method, if any</span>
411
+ <span class="comment"># context.data : a hash that may be used to share data between interceptors</span>
412
+ <span class="keyword">return</span> <span class="ident">context</span><span class="punct">.</span><span class="ident">process_next</span><span class="punct">(</span> <span class="ident">context</span> <span class="punct">)</span>
413
+ <span class="keyword">end</span>
414
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
415
+
416
+
377
417
  <p>Once you&#8217;ve created your factory, you can attach it to a service:</p>
378
418
 
379
419
 
380
- <pre>
381
- reg.intercept( :foo ).with { MyInterceptorFactory }
382
- </pre>
420
+ <div class='figure'>
421
+ <span class='caption'>Attaching a custom interceptor [ruby]</span>
422
+ <div class='body'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="ident">reg</span><span class="punct">.</span><span class="ident">intercept</span><span class="punct">(</span> <span class="symbol">:foo</span> <span class="punct">).</span><span class="ident">with</span> <span class="punct">{</span> <span class="constant">MyInterceptorFactory</span> <span class="punct">}</span></pre></div></div></div>
383
423
  </div>
384
424
 
385
425
 
386
426
 
427
+ <div class="bottom"><div class="prevnext">
428
+
429
+ <a href="chapter-4.html">Previous (4. Dependency Injection)</a> |
430
+
431
+ <a href="index.html">Up</a>
432
+
433
+ | <a href="chapter-6.html">Next (6. Service Models)</a>
434
+
435
+ </div></div>
436
+
387
437
 
388
438
  </div>
389
439