needle 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/faq/faq.yml +396 -14
- data/doc/manual-html/chapter-1.html +33 -4
- data/doc/manual-html/chapter-2.html +44 -6
- data/doc/manual-html/chapter-3.html +34 -5
- data/doc/manual-html/chapter-4.html +33 -4
- data/doc/manual-html/chapter-5.html +208 -4
- data/doc/manual-html/chapter-6.html +226 -4
- data/doc/manual-html/chapter-7.html +165 -4
- data/doc/manual-html/chapter-8.html +138 -6
- data/doc/manual-html/index.html +36 -9
- data/doc/manual/manual.rb +1 -1
- data/doc/manual/manual.yml +17 -4
- data/doc/manual/page.erb +2 -1
- data/doc/manual/parts/02_namespaces.txt +11 -2
- data/doc/manual/parts/03_overview.txt +1 -1
- data/doc/manual/parts/interceptors_architecture.txt +5 -0
- data/doc/manual/parts/interceptors_attaching.txt +64 -0
- data/doc/manual/parts/interceptors_custom.txt +25 -0
- data/doc/manual/parts/interceptors_ordering.txt +13 -0
- data/doc/manual/parts/interceptors_overview.txt +5 -0
- data/doc/manual/parts/libraries_creating.txt +30 -0
- data/doc/manual/parts/libraries_overview.txt +3 -0
- data/doc/manual/parts/libraries_using.txt +31 -0
- data/doc/manual/parts/logging_configuration.txt +30 -0
- data/doc/manual/parts/logging_logfactory.txt +31 -0
- data/doc/manual/parts/logging_overview.txt +5 -0
- data/doc/manual/parts/models_models.txt +35 -0
- data/doc/manual/parts/models_overview.txt +3 -0
- data/doc/manual/parts/models_pipelines.txt +63 -0
- data/lib/needle/container.rb +52 -7
- data/lib/needle/lifecycle/initialize.rb +1 -1
- data/lib/needle/log-factory.rb +46 -8
- data/lib/needle/thread.rb +6 -0
- data/lib/needle/version.rb +2 -2
- data/test/pipeline/tc_collection.rb +1 -1
- data/test/pipeline/tc_element.rb +2 -2
- data/test/services.rb +21 -0
- data/test/tc_container.rb +18 -0
- data/test/tc_logger.rb +35 -1
- metadata +17 -2
data/doc/faq/faq.yml
CHANGED
@@ -58,18 +58,400 @@
|
|
58
58
|
singleton, singleton_deferred, etc.).
|
59
59
|
|
60
60
|
- "How do I...":
|
61
|
-
- "create a new registry?":
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
- "
|
68
|
-
- "Like, :prototype?":
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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.
|
18
|
-
Manual Last Updated: <strong>2004-
|
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
|
-
|
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>
|
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>
|