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
@@ -58,18 +58,400 @@
58
58
  singleton, singleton_deferred, etc.).
59
59
 
60
60
  - "How do I...":
61
- - "create a new registry?":
62
- - "register a service?":
63
- - "create a namespace?":
64
- - "write log messages?":
65
- - "exclude methods from being intercepted?":
61
+ - "create a new registry?": >-
62
+ There are several ways to create a new registry. The simplist is just to
63
+ invoke Registry#new.
64
+
65
+
66
+ <pre>
67
+ reg = Needle::Registry.new
68
+ </pre>
69
+
70
+
71
+ This will create a new Registry instance. You can also send a block to
72
+ #new, in which case the new registry will be yielded to it:
73
+
74
+
75
+ <pre>
76
+ reg = Needle::Registry.new do |r|
77
+ ...
78
+ end
79
+ </pre>
80
+
81
+
82
+ There are two other factory methods you can use for creating a Registry
83
+ instance. Both require a block.
84
+
85
+
86
+ <pre>
87
+ r1 = Needle::Registry.define do |builder|
88
+ ...
89
+ end
90
+
91
+ r2 = Needle::Registry.define! do
92
+ ...
93
+ end
94
+ </pre>
95
+
96
+
97
+ Registry#define creates a "builder" object that you can use define
98
+ services more conveniently. Register#define! (with a bang) does the same
99
+ thing, but evaluates the block within the context of the builder.
100
+
101
+ - "register a service?": >-
102
+ The first way to register a service is by calling #register on the registry
103
+ (or a namespace):
104
+
105
+
106
+ <pre>
107
+ reg.register( :foo ) { Foo.new }
108
+ </pre>
109
+
110
+
111
+ The (first) parameter to #register is the name of the service, and the block
112
+ should return the implementation of the service. If needed, the block can
113
+ accept two parameters--the container that the service is being registered
114
+ with, and an object that represents the service being defined (called a "service
115
+ point"):
116
+
117
+
118
+ <pre>
119
+ reg.register( :foo ) do |container,point|
120
+ Foo.new( container[:bar], point.fullname )
121
+ end
122
+ </pre>
123
+
124
+
125
+ You can also use Container#define and Container#define! to register services.
126
+ These approaches are friendlier if you are needing to register several services
127
+ at once.
128
+
129
+
130
+ <pre>
131
+ reg.define do |builder|
132
+ builder.foo { Foo.new }
133
+ builder.bar { |c,p| Bar.new( c[:foo], p.name ) }
134
+ end
135
+
136
+ reg.define! do
137
+ baz { |c,p| Baz.new( c[:bar], p.name ) }
138
+ zoom { Buggy.new }
139
+ end
140
+ </pre>
141
+
142
+
143
+ Container#define yields a new "builder" object to the block. Messages sent to the
144
+ builder are interpreted as service names, and if a block is sent with the message,
145
+ a new service is registered under that name.
146
+
147
+
148
+ Container#define! does likewise, except it evaluates the block within the context
149
+ of the builder object.
150
+
151
+
152
+ If you do not pass a block to #define, it will return the builder object, so you
153
+ could do something like the following if you only need to define one or two
154
+ services:
155
+
156
+
157
+ <pre>
158
+ reg.define.foo { ... }
159
+ </pre>
160
+
161
+
162
+ Lastly, you can get the builder directly and add services using it:
163
+
164
+
165
+ <pre>
166
+ builder = reg.builder
167
+ builder.baz { ... }
168
+ builder.bar { ... }
169
+ </pre>
170
+
171
+
172
+ (This last is the same as calling #define without arguments, but is more readable
173
+ if you intend to use the builder object multiple times.)
174
+
175
+ - "reference a service?": >-
176
+ Referencing a service can be done in either of two ways. The first is to treat the
177
+ container (i.e., registry) as a hash, passing the name of the service as an argument
178
+ to Container#[]:
179
+
180
+
181
+ <pre>
182
+ svc = registry[:foo]
183
+ svc.do_something_interesting
184
+ </pre>
185
+
186
+
187
+ A more convenient (but slightly more peril-fraught) approach is to send the name of
188
+ the method to the registry as a message:
189
+
190
+
191
+ <pre>
192
+ svc = registry.foo
193
+ </pre>
194
+
195
+
196
+ Be aware that this latter approach will only work when the service name does not
197
+ conflict with the name of an existing method on the container. For example, if
198
+ you were to do:
199
+
200
+
201
+ <pre>
202
+ registry.register( :hash ) { "hello, world" }
203
+ p registry.hash
204
+ </pre>
205
+
206
+
207
+ You would get the hash value of the registry object, instead of the value value
208
+ of the service (which would be "hello, world").
209
+
210
+ - "select a service model for a service (i.e., change the default model of lifecycle management)?": >-
211
+ By default, a service will be managed as a singleton, i.e., every request of that service
212
+ will return the same object instance. This is the _singleton_ service model.
213
+
214
+
215
+ To select a different service model, pass it as an option when you register the service:
216
+
217
+
218
+ <pre>
219
+ registry.register( :foo, :model => :prototype ) {...}
220
+ registry.define.bar( :model => :threaded ) {...}
221
+ registry.define! do
222
+ baz( :model => :singleton_deferred ) {...}
223
+ ...
224
+ end
225
+ ...
226
+ </pre>
227
+
228
+ - "create a namespace?": >-
229
+ Namespaces allow you to organize your services into hierarchical packages. You can create
230
+ namespaces in a few ways. The first (and simplest) is to just call Container#namespace:
231
+
232
+
233
+ <pre>
234
+ registry.namespace( :stuff )
235
+ </pre>
236
+
237
+
238
+ This will create a namespace in the registry, called stuff. If you send a block as well,
239
+ the block will be invoked (with the new namespace yielded to it) the first time the
240
+ namespace is requested:
241
+
242
+
243
+ <pre>
244
+ registry.namespace( :stuff ) do |ns|
245
+ ns.register( :foo ) {...}
246
+ ns.define.bar {...}
247
+ ns.define! do
248
+ baz {...}
249
+ buf {...}
250
+ end
251
+ end
252
+ </pre>
253
+
254
+ Because it is so common to immediately define services on the new namespace, there
255
+ are some convenience methods to make this more...convenient.
256
+
257
+
258
+ <pre>
259
+ registry.namespace_define!( :stuff ) do
260
+ foo {...}
261
+ bar {...}
262
+ baz {...}
263
+ end
264
+
265
+ registry.namespace_define( :more_stuff ) do |b|
266
+ b.blah {...}
267
+ b.argh {...}
268
+ b.hack {...}
269
+ end
270
+ </pre>
271
+
272
+
273
+ The first one, above, creates the namespace and calls Container#define!. The second
274
+ creates the namespace and calls Container#define. In both cases, _the namespace is
275
+ created immediately_, unlike Container#namespace which only creates the namespace
276
+ when it is first requested.
277
+
278
+
279
+ Lastly, note that namespace's are just special services. Thus, you can pass options
280
+ to the namespace methods just as you can with Container#register and friends.
281
+
282
+ - "write log messages?": >-
283
+ You can obtain a new logger instance from the @:logs@ service. Once you have a
284
+ logger instance, you can invoke the #debug, #info, #warn, #error, and #fatal methods
285
+ on the instance to log messages of the corresponding severity.
286
+
287
+
288
+ <pre>
289
+ logger = registry.logs.get( "a name for my logger" )
290
+ logger.debug "This is a debug message"
291
+ logger.info "This is an informational message"
292
+ ...
293
+ </pre>
294
+
295
+
296
+ Log messages are written, by default, to a file called "needle.log", in the same
297
+ directory that the application was invoked from.
298
+
299
+
300
+ You can also use a logging interceptor to automatically log all external method
301
+ invocations on a service. This includes method entry and exit, as well as any
302
+ exceptions that are raised inside the method.
303
+
304
+
305
+ <pre>
306
+ registry.register( :foo ) { ... }
307
+ registry.intercept( :foo ).with { |r| r.logging_interceptor }
308
+
309
+ foo.something
310
+ foo.another_method( 1, 2, 3 )
311
+ </pre>
312
+
313
+
314
+ See the chapter in the "User's Manual":http://needle.rubyforge.org about logging
315
+ for more information on how to use and configure loggers.
316
+
317
+ - "exclude methods from being intercepted?": >-
318
+ Only interceptors that explicitly support exclusion of methods can help you here.
319
+ Fortunately, the LoggingInterceptor is one of them. (If you write your own interceptor
320
+ and would like similar functionality, see the IncludeExclude module.)
321
+
322
+
323
+ In the case of the LoggingInterceptor, just pass an array of patterns (matching
324
+ method names and/or arities) as the "exclude" option, when declaring the interceptor:
325
+
326
+
327
+ <pre>
328
+ registry.register( :foo ) { ... }
329
+ registry.intercept( :foo ).
330
+ with { |r| r.logging_interceptor }.
331
+ with_options :exclude => [ 'foo', 'bar(>4)', '*(<2)' ]
332
+ </pre>
333
+
334
+
335
+ The above will exclude from interception any method named 'foo', or any invocation
336
+ of 'bar' with more than 4 arguments, or any method invocation with fewer than two
337
+ arguments.
338
+
339
+
340
+ You can also give an array of patterns to _include_. These cause methods to be
341
+ explicitly intercepted even if they match an exclude pattern:
342
+
343
+
344
+ <pre>
345
+ registry.register( :foo ) { ... }
346
+ registry.intercept( :foo ).
347
+ with { |r| r.logging_interceptor }.
348
+ with_options :exclude => [ 'foo', 'bar(>4)', '*(<2)' ],
349
+ :include => [ 'baz' ]
350
+
351
+ foo = registry.foo
352
+ foo.baz
353
+ </pre>
354
+
355
+
356
+ This would result in the call to #baz being intercepted, even though it matches
357
+ an exclude pattern (@*(<2)@).
358
+
359
+ - "include services defined in another library?": >-
360
+ This requires that the other library be implemented in such a way that it expects
361
+ to be "included" by other libraries/applications. For example, Needle encourages
362
+ the use of a method called @register_services@, which accepts a container as a
363
+ parameter:
364
+
365
+
366
+ <pre>
367
+ module A
368
+ module B
369
+ def register_services( container )
370
+ ...
371
+ end
372
+ module_function :register_services
373
+ end
374
+ end
375
+ </pre>
376
+
377
+
378
+ If the library has been implemented in this way, you can simply do a require of
379
+ the library and then invoke the @register_services@ method.
380
+
381
+
382
+ There is a convenience method in Container for doing this. Just call Container#require,
383
+ passing the file to require and a string (or symbol) identifying the name of the
384
+ module that contains the registration method. You can also pass a symbol as the third
385
+ parameter naming the registration method, but it defaults to @:register_services@.
386
+
387
+
388
+ <pre>
389
+ require 'a/b'
390
+ A::B.register_services( container )
391
+
392
+ # or
393
+
394
+ container.require( 'a/b', "A::B" )
395
+ </pre>
396
+
397
+
398
+ The definition context (i.e., the "builder" object) also supports the require method,
399
+ so you can do:
400
+
401
+
402
+ <pre>
403
+ container.define do |b|
404
+ b.require "a/b", "A::B"
405
+ b.foo { ... }
406
+ ...
407
+ end
408
+ </pre>
409
+
66
410
  - "When should I...":
67
- - "specify a service model?":
68
- - "Like, :prototype?":
69
- - "Like, :prototype_deferred?":
70
- - "Like, :singleton?":
71
- - "Like, :singleton_deferred?":
72
- - "Like, :threaded?":
73
- - "Like, :threaded_deferred?":
74
- - "use interceptors?":
75
- - "create my own pipeline element?":
411
+ - "use a different service model?":
412
+ - "Like, :prototype?": >-
413
+ The prototype service model is appropriate when the service:
414
+
415
+
416
+ * has internal state
417
+
418
+ * will be used multiple times for different situations
419
+
420
+
421
+ For example, if you have a GUI library, a "button" service could be a prototype,
422
+ because you will likely have many buttons in an application, with each button
423
+ being an independent instance.
424
+
425
+ - "Like, :singleton?": >-
426
+ The singleton service model is the default, so you should rarely need to explicitly
427
+ specify it as a model. It is appropriate for services that:
428
+
429
+
430
+ * guard some specific functionality
431
+
432
+ * represent state that is global across an application
433
+
434
+ - "Like, :threaded?": >-
435
+ Threaded is similar to singleton, but it allows one unique instance of the service
436
+ _per thread_. Thus, it is appropriate to the same situations as singleton, but
437
+ specific to a thread, instead of an application. This is useful for web applications
438
+ that are run in a single virtual machine, and which share a single registry.
439
+
440
+ - "Like, deferred?": >-
441
+ Deferred models use a proxy to enforce lazy initialization of the service. A service
442
+ using a deferred service model (ie, @:prototype_deferred@, @:singleton_deferred@, or
443
+ @:threaded_deferred@) will not be instantiated until the first time a method is invoked
444
+ on the service.
445
+
446
+
447
+ This makes a deferred model appropriate when a service is expensive to instantiate, since
448
+ you can wait to do the expensive initialization until it is really needed. Applications
449
+ will start up faster when their dependences use deferred instantiation.
450
+
451
+ - "Like, initialize?": >-
452
+ This is useful when you have a method that you want to be invoked automatically after
453
+ a service has been instantiated. Consider the case where a service is initialized
454
+ primarily using setters, but requires some logic to be executed to complete the
455
+ initialization phase. In this case, you could always explicitly invoke the initialization
456
+ method(s) in the constructor block, but if many services use the same initialization
457
+ method, it can be more convenient to use an "initialize" service model.
@@ -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>