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.
- 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>
|