needle 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/doc/faq/faq.yml +396 -14
  2. data/doc/manual-html/chapter-1.html +33 -4
  3. data/doc/manual-html/chapter-2.html +44 -6
  4. data/doc/manual-html/chapter-3.html +34 -5
  5. data/doc/manual-html/chapter-4.html +33 -4
  6. data/doc/manual-html/chapter-5.html +208 -4
  7. data/doc/manual-html/chapter-6.html +226 -4
  8. data/doc/manual-html/chapter-7.html +165 -4
  9. data/doc/manual-html/chapter-8.html +138 -6
  10. data/doc/manual-html/index.html +36 -9
  11. data/doc/manual/manual.rb +1 -1
  12. data/doc/manual/manual.yml +17 -4
  13. data/doc/manual/page.erb +2 -1
  14. data/doc/manual/parts/02_namespaces.txt +11 -2
  15. data/doc/manual/parts/03_overview.txt +1 -1
  16. data/doc/manual/parts/interceptors_architecture.txt +5 -0
  17. data/doc/manual/parts/interceptors_attaching.txt +64 -0
  18. data/doc/manual/parts/interceptors_custom.txt +25 -0
  19. data/doc/manual/parts/interceptors_ordering.txt +13 -0
  20. data/doc/manual/parts/interceptors_overview.txt +5 -0
  21. data/doc/manual/parts/libraries_creating.txt +30 -0
  22. data/doc/manual/parts/libraries_overview.txt +3 -0
  23. data/doc/manual/parts/libraries_using.txt +31 -0
  24. data/doc/manual/parts/logging_configuration.txt +30 -0
  25. data/doc/manual/parts/logging_logfactory.txt +31 -0
  26. data/doc/manual/parts/logging_overview.txt +5 -0
  27. data/doc/manual/parts/models_models.txt +35 -0
  28. data/doc/manual/parts/models_overview.txt +3 -0
  29. data/doc/manual/parts/models_pipelines.txt +63 -0
  30. data/lib/needle/container.rb +52 -7
  31. data/lib/needle/lifecycle/initialize.rb +1 -1
  32. data/lib/needle/log-factory.rb +46 -8
  33. data/lib/needle/thread.rb +6 -0
  34. data/lib/needle/version.rb +2 -2
  35. data/test/pipeline/tc_collection.rb +1 -1
  36. data/test/pipeline/tc_element.rb +2 -2
  37. data/test/services.rb +21 -0
  38. data/test/tc_container.rb +18 -0
  39. data/test/tc_logger.rb +35 -1
  40. metadata +17 -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>0.9.0</strong><br />
18
- Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
17
+ Needle Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-11-04 14:24 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -105,6 +105,16 @@
105
105
 
106
106
  <ol type="1">
107
107
 
108
+ <li><a href="chapter-5.html#s1">Overview</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Architecture</a></li>
111
+
112
+ <li><a href="chapter-5.html#s3">Attaching</a></li>
113
+
114
+ <li><a href="chapter-5.html#s4">Ordering</a></li>
115
+
116
+ <li><a href="chapter-5.html#s5">Custom</a></li>
117
+
108
118
  </ol>
109
119
  </li>
110
120
 
@@ -115,6 +125,12 @@
115
125
 
116
126
  <ol type="1">
117
127
 
128
+ <li><a href="chapter-6.html#s1">Overview</a></li>
129
+
130
+ <li><a href="chapter-6.html#s2">Pipelines</a></li>
131
+
132
+ <li><a href="chapter-6.html#s3">Models</a></li>
133
+
118
134
  </ol>
119
135
  </li>
120
136
 
@@ -125,25 +141,38 @@
125
141
 
126
142
  <ol type="1">
127
143
 
144
+ <li><a href="chapter-7.html#s1">Overview</a></li>
145
+
146
+ <li><a href="chapter-7.html#s2">LogFactory</a></li>
147
+
148
+ <li><a href="chapter-7.html#s3">Configuration</a></li>
149
+
128
150
  </ol>
129
151
  </li>
130
152
 
131
153
  <li>
132
154
  <a href="chapter-8.html">
133
- Creating Libraries
155
+ Service Libraries
134
156
  </a>
135
157
 
136
158
  <ol type="1">
137
159
 
160
+ <li><a href="chapter-8.html#s1">Overview</a></li>
161
+
162
+ <li><a href="chapter-8.html#s2">Creating Libraries</a></li>
163
+
164
+ <li><a href="chapter-8.html#s3">Using Libraries</a></li>
165
+
138
166
  </ol>
139
167
  </li>
140
168
 
141
169
  </ol>
142
170
 
143
- <h2>API Reference</h2>
171
+ <h2>Other Documentation</h2>
144
172
 
145
173
  <ul>
146
174
  <li><a href="http://needle.rubyforge.org/api/index.html">Needle API</a></li>
175
+ <li><a href="http://needle.rubyforge.org/faq.html">Needle FAQ</a></li>
147
176
  </ul>
148
177
 
149
178
  <h2>Tutorials</h2>
@@ -351,10 +380,19 @@
351
380
  end
352
381
  </pre>
353
382
 
354
- <p>And, to mirror the <code>namespace</code> method, there is also a <code>namespace!</code> method. This method creates a new namespace and then does a <code>define!</code> call on that namespace.</p>
383
+ <p>If you prefer the <code>define</code> approach to registering services, you may like <code>namespace_define</code>, which creates the new namespace and immediately calls <code>define</code> on it:</p>
384
+
385
+ <pre>
386
+ registry.namespace_define :stuff do |b|
387
+ b.foo { Bar.new }
388
+ ...
389
+ end
390
+ </pre>
391
+
392
+ <p>And, to mirror the <code>namespace_define</code> method, there is also a <code>namespace_define!</code> method. This method creates a new namespace and then does a <code>define!</code> call on that namespace.</p>
355
393
 
356
394
  <pre>
357
- registry.namespace! :stuff do
395
+ registry.namespace_define! :stuff do
358
396
  foo { Bar.new }
359
397
  ...
360
398
  end
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
16
  <div class="info">
17
- Needle Version: <strong>0.9.0</strong><br />
18
- Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
17
+ Needle Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-11-04 14:24 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -105,6 +105,16 @@
105
105
 
106
106
  <ol type="1">
107
107
 
108
+ <li><a href="chapter-5.html#s1">Overview</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Architecture</a></li>
111
+
112
+ <li><a href="chapter-5.html#s3">Attaching</a></li>
113
+
114
+ <li><a href="chapter-5.html#s4">Ordering</a></li>
115
+
116
+ <li><a href="chapter-5.html#s5">Custom</a></li>
117
+
108
118
  </ol>
109
119
  </li>
110
120
 
@@ -115,6 +125,12 @@
115
125
 
116
126
  <ol type="1">
117
127
 
128
+ <li><a href="chapter-6.html#s1">Overview</a></li>
129
+
130
+ <li><a href="chapter-6.html#s2">Pipelines</a></li>
131
+
132
+ <li><a href="chapter-6.html#s3">Models</a></li>
133
+
118
134
  </ol>
119
135
  </li>
120
136
 
@@ -125,25 +141,38 @@
125
141
 
126
142
  <ol type="1">
127
143
 
144
+ <li><a href="chapter-7.html#s1">Overview</a></li>
145
+
146
+ <li><a href="chapter-7.html#s2">LogFactory</a></li>
147
+
148
+ <li><a href="chapter-7.html#s3">Configuration</a></li>
149
+
128
150
  </ol>
129
151
  </li>
130
152
 
131
153
  <li>
132
154
  <a href="chapter-8.html">
133
- Creating Libraries
155
+ Service Libraries
134
156
  </a>
135
157
 
136
158
  <ol type="1">
137
159
 
160
+ <li><a href="chapter-8.html#s1">Overview</a></li>
161
+
162
+ <li><a href="chapter-8.html#s2">Creating Libraries</a></li>
163
+
164
+ <li><a href="chapter-8.html#s3">Using Libraries</a></li>
165
+
138
166
  </ol>
139
167
  </li>
140
168
 
141
169
  </ol>
142
170
 
143
- <h2>API Reference</h2>
171
+ <h2>Other Documentation</h2>
144
172
 
145
173
  <ul>
146
174
  <li><a href="http://needle.rubyforge.org/api/index.html">Needle API</a></li>
175
+ <li><a href="http://needle.rubyforge.org/faq.html">Needle FAQ</a></li>
147
176
  </ul>
148
177
 
149
178
  <h2>Tutorials</h2>
@@ -188,7 +217,7 @@
188
217
  <li><code>Application</code>. The controller that ties it all together.</li>
189
218
  </ul>
190
219
 
191
- <p>(Of course, a <em>real</em> online forum application would be significantly more complex, but the above components will do for our puroses.)</p>
220
+ <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>
192
221
 
193
222
  <p>The dependencies between these components are:</p>
194
223
 
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
16
  <div class="info">
17
- Needle Version: <strong>0.9.0</strong><br />
18
- Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
17
+ Needle Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-11-04 14:24 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -105,6 +105,16 @@
105
105
 
106
106
  <ol type="1">
107
107
 
108
+ <li><a href="chapter-5.html#s1">Overview</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Architecture</a></li>
111
+
112
+ <li><a href="chapter-5.html#s3">Attaching</a></li>
113
+
114
+ <li><a href="chapter-5.html#s4">Ordering</a></li>
115
+
116
+ <li><a href="chapter-5.html#s5">Custom</a></li>
117
+
108
118
  </ol>
109
119
  </li>
110
120
 
@@ -115,6 +125,12 @@
115
125
 
116
126
  <ol type="1">
117
127
 
128
+ <li><a href="chapter-6.html#s1">Overview</a></li>
129
+
130
+ <li><a href="chapter-6.html#s2">Pipelines</a></li>
131
+
132
+ <li><a href="chapter-6.html#s3">Models</a></li>
133
+
118
134
  </ol>
119
135
  </li>
120
136
 
@@ -125,25 +141,38 @@
125
141
 
126
142
  <ol type="1">
127
143
 
144
+ <li><a href="chapter-7.html#s1">Overview</a></li>
145
+
146
+ <li><a href="chapter-7.html#s2">LogFactory</a></li>
147
+
148
+ <li><a href="chapter-7.html#s3">Configuration</a></li>
149
+
128
150
  </ol>
129
151
  </li>
130
152
 
131
153
  <li>
132
154
  <a href="chapter-8.html">
133
- Creating Libraries
155
+ Service Libraries
134
156
  </a>
135
157
 
136
158
  <ol type="1">
137
159
 
160
+ <li><a href="chapter-8.html#s1">Overview</a></li>
161
+
162
+ <li><a href="chapter-8.html#s2">Creating Libraries</a></li>
163
+
164
+ <li><a href="chapter-8.html#s3">Using Libraries</a></li>
165
+
138
166
  </ol>
139
167
  </li>
140
168
 
141
169
  </ol>
142
170
 
143
- <h2>API Reference</h2>
171
+ <h2>Other Documentation</h2>
144
172
 
145
173
  <ul>
146
174
  <li><a href="http://needle.rubyforge.org/api/index.html">Needle API</a></li>
175
+ <li><a href="http://needle.rubyforge.org/faq.html">Needle FAQ</a></li>
147
176
  </ul>
148
177
 
149
178
  <h2>Tutorials</h2>
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
16
  <div class="info">
17
- Needle Version: <strong>0.9.0</strong><br />
18
- Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
17
+ Needle Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-11-04 14:24 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -105,6 +105,16 @@
105
105
  </strong> <big>&larr;</big>
106
106
  <ol type="1">
107
107
 
108
+ <li><a href="chapter-5.html#s1">Overview</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Architecture</a></li>
111
+
112
+ <li><a href="chapter-5.html#s3">Attaching</a></li>
113
+
114
+ <li><a href="chapter-5.html#s4">Ordering</a></li>
115
+
116
+ <li><a href="chapter-5.html#s5">Custom</a></li>
117
+
108
118
  </ol>
109
119
  </li>
110
120
 
@@ -115,6 +125,12 @@
115
125
 
116
126
  <ol type="1">
117
127
 
128
+ <li><a href="chapter-6.html#s1">Overview</a></li>
129
+
130
+ <li><a href="chapter-6.html#s2">Pipelines</a></li>
131
+
132
+ <li><a href="chapter-6.html#s3">Models</a></li>
133
+
118
134
  </ol>
119
135
  </li>
120
136
 
@@ -125,25 +141,38 @@
125
141
 
126
142
  <ol type="1">
127
143
 
144
+ <li><a href="chapter-7.html#s1">Overview</a></li>
145
+
146
+ <li><a href="chapter-7.html#s2">LogFactory</a></li>
147
+
148
+ <li><a href="chapter-7.html#s3">Configuration</a></li>
149
+
128
150
  </ol>
129
151
  </li>
130
152
 
131
153
  <li>
132
154
  <a href="chapter-8.html">
133
- Creating Libraries
155
+ Service Libraries
134
156
  </a>
135
157
 
136
158
  <ol type="1">
137
159
 
160
+ <li><a href="chapter-8.html#s1">Overview</a></li>
161
+
162
+ <li><a href="chapter-8.html#s2">Creating Libraries</a></li>
163
+
164
+ <li><a href="chapter-8.html#s3">Using Libraries</a></li>
165
+
138
166
  </ol>
139
167
  </li>
140
168
 
141
169
  </ol>
142
170
 
143
- <h2>API Reference</h2>
171
+ <h2>Other Documentation</h2>
144
172
 
145
173
  <ul>
146
174
  <li><a href="http://needle.rubyforge.org/api/index.html">Needle API</a></li>
175
+ <li><a href="http://needle.rubyforge.org/faq.html">Needle FAQ</a></li>
147
176
  </ul>
148
177
 
149
178
  <h2>Tutorials</h2>
@@ -167,6 +196,181 @@
167
196
 
168
197
 
169
198
 
199
+ <h2>
200
+ <a name="s1"></a>
201
+ 5.1. Overview
202
+ </h2>
203
+
204
+
205
+
206
+ <div class="section">
207
+ <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>
208
+
209
+ <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>
210
+
211
+ <p>You can, of course, implement your own interceptors as well.<br />
212
+ </p>
213
+ </div>
214
+
215
+
216
+
217
+ <h2>
218
+ <a name="s2"></a>
219
+ 5.2. Architecture
220
+ </h2>
221
+
222
+
223
+
224
+ <div class="section">
225
+ <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>
226
+
227
+ <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>
228
+
229
+ <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 />
230
+ </p>
231
+ </div>
232
+
233
+
234
+
235
+ <h2>
236
+ <a name="s3"></a>
237
+ 5.3. Attaching
238
+ </h2>
239
+
240
+
241
+
242
+ <div class="section">
243
+ <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>
244
+
245
+ <h3>Interceptor Factories</h3>
246
+
247
+ <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>
248
+
249
+ <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>
250
+
251
+ <p>You can attach interceptor factories to your service using the <code>#interceptor(...).with {...}</code> syntax:</p>
252
+
253
+ <pre>
254
+ reg.register( :foo ) {...}
255
+ reg.intercept( :foo ).with { MyInterceptorFactory }
256
+ </pre>
257
+
258
+ <p>Note that you could also make the interceptor factory a service:</p>
259
+
260
+ <pre>
261
+ reg.register( :foo ) {...}
262
+ reg.register( :my_interceptor ) { MyInterceptorFactory }
263
+ reg.intercept( :foo ).with { |c| c.my_interceptor }
264
+ </pre>
265
+
266
+ <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>
267
+
268
+ <pre>
269
+ reg.register( :foo ) {...}
270
+ reg.register( :my_interceptor ) { MyInterceptorFactory }
271
+ reg.intercept( :foo ).with! { my_interceptor }
272
+ </pre>
273
+
274
+ <h3>Blocks</h3>
275
+
276
+ <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 />
277
+ <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>
278
+
279
+ <pre>
280
+ reg.register( :foo ) {...}
281
+ reg.intercept( :foo ).doing { |chain,ctx| ...; chain.process_next( ctx ) }
282
+ </pre>
283
+
284
+ <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>
285
+
286
+ <h3>Options</h3>
287
+
288
+ <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>
289
+
290
+ <pre>
291
+ reg.register( :foo ) {...}
292
+ reg.intercept( :foo ).
293
+ with { |c| c.logging_interceptor }.
294
+ with_options( :exclude =&gt; [ "method1", "method2" ] )
295
+ </pre>
296
+
297
+ <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>
298
+
299
+ <pre>
300
+ reg.intercept( :foo ).
301
+ doing { |ch,ctx| ...; p ctx.data[:options][:value]; ... }.
302
+ with_options( :value =&gt; "hello" )
303
+ </pre>
304
+
305
+ <p>With blocks, of course, the value of such an approach is limited.<br />
306
+ </p>
307
+ </div>
308
+
309
+
310
+
311
+ <h2>
312
+ <a name="s4"></a>
313
+ 5.4. Ordering
314
+ </h2>
315
+
316
+
317
+
318
+ <div class="section">
319
+ <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>
320
+
321
+ <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>
322
+
323
+ <p>You can specify the priority as an option when attaching an interceptor:</p>
324
+
325
+ <pre>
326
+ reg.register( :foo ) { ... }
327
+ reg.intercept( :foo ).with { Something }.with_options( :priority =&gt; 100 )
328
+ reg.intercept( :foo ).with { SomethingElse }.with_options( :priority =&gt; 50 )
329
+ </pre>
330
+
331
+ <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 />
332
+ </p>
333
+ </div>
334
+
335
+
336
+
337
+ <h2>
338
+ <a name="s5"></a>
339
+ 5.5. Custom
340
+ </h2>
341
+
342
+
343
+
344
+ <div class="section">
345
+ <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>
346
+
347
+ <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>
348
+
349
+ <pre>
350
+ class MyInterceptorFactory
351
+ def initialize( point, options )
352
+ ...
353
+ end
354
+
355
+ def process( chain, context )
356
+ # context.sym : the name of the method that was invoked
357
+ # context.args : the array of arguments passed to the method
358
+ # context.block : the block passed to the method, if any
359
+ # context.data : a hash that may be used to share data between interceptors
360
+ return context.process_next( context )
361
+ end
362
+ end
363
+ </pre>
364
+
365
+ <p>Once you&#8217;ve created your factory, you can attach it to a service:</p>
366
+
367
+ <pre>
368
+ reg.intercept( :foo ).with { MyInterceptorFactory }
369
+ </pre>
370
+ </div>
371
+
372
+
373
+
170
374
 
171
375
  </div>
172
376