needle 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>