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
@@ -1,6 +1,6 @@
1
1
  <html>
2
2
  <head>
3
- <title>Needle Manual :: Chapter 8: Creating Libraries</title>
3
+ <title>Needle Manual :: Chapter 8: Service Libraries</title>
4
4
  <link type="text/css" rel="stylesheet" href="manual.css" />
5
5
  </head>
6
6
 
@@ -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><strong>
132
154
  <a href="chapter-8.html">
133
- Creating Libraries
155
+ Service Libraries
134
156
  </a>
135
157
  </strong> <big>&larr;</big>
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>
@@ -163,7 +192,110 @@
163
192
 
164
193
  <div id="content">
165
194
 
166
- <h1>8. Creating Libraries</h1>
195
+ <h1>8. Service Libraries</h1>
196
+
197
+
198
+
199
+ <h2>
200
+ <a name="s1"></a>
201
+ 8.1. Overview
202
+ </h2>
203
+
204
+
205
+
206
+ <div class="section">
207
+ <p>Using Needle as it has been presented so far works fine when you are dealing with a single application, all self-encapsulated. When you start dealing with combining multiple libraries, each potentially written by a different author, into a single registry, things get a little more complicated.</p>
208
+
209
+ <p>Needle provides a way for service authors to share their services. All it requires is that authors centralize their service configuration.<br />
210
+ </p>
211
+ </div>
212
+
213
+
214
+
215
+ <h2>
216
+ <a name="s2"></a>
217
+ 8.2. Creating Libraries
218
+ </h2>
219
+
220
+
221
+
222
+ <div class="section">
223
+ <p>This centralization is implemented by creating a module for each library you want to have services for. That module should then define a module function called (by default) <code>register_services</code>. This function should accept a single parameter&#8212;the Needle container that the services will be added to.</p>
224
+
225
+ <p>For example, if I had a library of cryptographic routines and I wanted to make them accessible as Needle services, I would create a module to contain the service definitions. Typically, this module will be defined in a file called &#8220;services.rb&#8221;, although you can certainly name it whatever you like.</p>
226
+
227
+ <pre>
228
+ module Crypto
229
+
230
+ def register_services( container )
231
+ container.namespace_define( :crypto ) do |b|
232
+ b.prng do
233
+ require 'crypto/prng'
234
+ PRNG.new
235
+ end
236
+
237
+ b.des do
238
+ require 'crypto/des'
239
+ DES.new
240
+ end
241
+
242
+ ...
243
+ end
244
+ end
245
+ module_function :register_services
246
+
247
+ end
248
+ </pre>
249
+
250
+ <p>Notice that there are no explicit dependencies on Needle, only on the interfaces Needle publishes. Thus, third-parties can add service configuration modules to their libraries without introducing dependencies on Needle.</p>
251
+
252
+ <p>Once a service library has been created, it can then be accessed from another library or application that wishes to import those services.<br />
253
+ </p>
254
+ </div>
255
+
256
+
257
+
258
+ <h2>
259
+ <a name="s3"></a>
260
+ 8.3. Using Libraries
261
+ </h2>
262
+
263
+
264
+
265
+ <div class="section">
266
+ <p>Using the libraries is as simple as requiring the file that has the service definitions, and then invoking the <code>#register_services</code> module function:</p>
267
+
268
+ <pre>
269
+ require 'needle'
270
+
271
+ reg = Needle::Registry.new
272
+ reg.define do |b|
273
+ b.foo { Foo.new }
274
+
275
+ require 'crypto/services'
276
+ Crypto.register_services( reg )
277
+ end
278
+
279
+ prng = reg.crypto.prng
280
+ </pre>
281
+
282
+ <p>To make this easier, the Container class has a convenience method named <code>#require</code>:</p>
283
+
284
+ <pre>
285
+ require 'needle'
286
+
287
+ reg = Needle::Registry.new
288
+ reg.define do |b|
289
+ b.foo { Foo.new }
290
+ b.require 'crypto/services', "Crypto"
291
+ end
292
+
293
+ prng = reg.crypto.prng
294
+ </pre>
295
+
296
+ <p>The <code>Container#require</code> method will require the file, and then look for a <code>#register_services</code> method of the named module. It will execute that method, passing the container as an argument.<br />
297
+ </p>
298
+ </div>
167
299
 
168
300
 
169
301
 
@@ -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>
@@ -178,6 +207,8 @@
178
207
 
179
208
  API Documentation: <a href="http://needle.rubyforge.org/api">http://needle.rubyforge.org/api</a><br />
180
209
 
210
+ FAQ Document: <a href="http://needle.rubyforge.org/faq.html">http://needle.rubyforge.org/faq.html</a><br />
211
+
181
212
  Needle Wiki: <a href="http://needle.rubyforge.org/wiki/wiki.pl">http://needle.rubyforge.org/wiki/wiki.pl</a><br />
182
213
 
183
214
  </p>
@@ -187,11 +218,7 @@
187
218
  <table border='0' cellpadding='0' cellspacing='0' align='center'><tr><td>
188
219
  <ul>
189
220
 
190
- <li>added Container#define</li>
191
-
192
- <li>renamed Container#register! to Container#define!</li>
193
-
194
- <li>added documentation of Container#new!</li>
221
+ <li>added remaining chapters</li>
195
222
 
196
223
  </ul>
197
224
  </table>
@@ -100,7 +100,7 @@ module Needle
100
100
  def initialize( index, title, content )
101
101
  @index = index
102
102
  @title = RedCloth.new( title ).to_html.gsub( %r{</?p>}, "" ) if title
103
- @content = RedCloth.new( content )
103
+ @content = RedCloth.new( content || "" )
104
104
  end
105
105
  end
106
106
 
@@ -19,12 +19,11 @@ product: !^product
19
19
  - Project Page: http://rubyforge.org/projects/needle
20
20
  - User Manual: http://needle.rubyforge.org
21
21
  - API Documentation: http://needle.rubyforge.org/api
22
+ - FAQ Document: http://needle.rubyforge.org/faq.html
22
23
  - Needle Wiki: http://needle.rubyforge.org/wiki/wiki.pl
23
24
 
24
25
  recent_updates:
25
- - added Container#define
26
- - renamed Container#register! to Container#define!
27
- - added documentation of Container#new!
26
+ - added remaining chapters
28
27
 
29
28
  chapters:
30
29
 
@@ -51,9 +50,23 @@ chapters:
51
50
  - Setup: !!file parts/04_setup.txt
52
51
 
53
52
  - Interceptors:
53
+ - Overview: !!file parts/interceptors_overview.txt
54
+ - Architecture: !!file parts/interceptors_architecture.txt
55
+ - Attaching: !!file parts/interceptors_attaching.txt
56
+ - Ordering: !!file parts/interceptors_ordering.txt
57
+ - Custom: !!file parts/interceptors_custom.txt
54
58
 
55
59
  - Service Models:
60
+ - Overview: !!file parts/models_overview.txt
61
+ - Pipelines: !!file parts/models_pipelines.txt
62
+ - Models: !!file parts/models_models.txt
56
63
 
57
64
  - Logging:
65
+ - Overview: !!file parts/logging_overview.txt
66
+ - LogFactory: !!file parts/logging_logfactory.txt
67
+ - Configuration: !!file parts/logging_configuration.txt
58
68
 
59
- - Creating Libraries:
69
+ - Service Libraries:
70
+ - Overview: !!file parts/libraries_overview.txt
71
+ - Creating Libraries: !!file parts/libraries_creating.txt
72
+ - Using Libraries: !!file parts/libraries_using.txt
@@ -45,10 +45,11 @@
45
45
  <% end %>
46
46
  </ol>
47
47
 
48
- <h2>API Reference</h2>
48
+ <h2>Other Documentation</h2>
49
49
 
50
50
  <ul>
51
51
  <li><a href="http://needle.rubyforge.org/api/index.html">Needle API</a></li>
52
+ <li><a href="http://needle.rubyforge.org/faq.html">Needle FAQ</a></li>
52
53
  </ul>
53
54
 
54
55
  <h2>Tutorials</h2>
@@ -35,10 +35,19 @@ Because it is often the case that you will be creating a namespace and then imme
35
35
  end
36
36
  </pre>
37
37
 
38
- And, to mirror the @namespace@ method, there is also a @namespace!@ method. This method creates a new namespace and then does a @define!@ call on that namespace.
38
+ If you prefer the @define@ approach to registering services, you may like @namespace_define@, which creates the new namespace and immediately calls @define@ on it:
39
39
 
40
40
  <pre>
41
- registry.namespace! :stuff do
41
+ registry.namespace_define :stuff do |b|
42
+ b.foo { Bar.new }
43
+ ...
44
+ end
45
+ </pre>
46
+
47
+ And, to mirror the @namespace_define@ method, there is also a @namespace_define!@ method. This method creates a new namespace and then does a @define!@ call on that namespace.
48
+
49
+ <pre>
50
+ registry.namespace_define! :stuff do
42
51
  foo { Bar.new }
43
52
  ...
44
53
  end
@@ -9,7 +9,7 @@ To demonstrate both techniques, we'll pretend we're going to write an online for
9
9
  * @View@. The presentation manager, used to render pages to the user.
10
10
  * @Application@. The controller that ties it all together.
11
11
 
12
- (Of course, a _real_ online forum application would be significantly more complex, but the above components will do for our puroses.)
12
+ (Of course, a _real_ online forum application would be significantly more complex, but the above components will do for our purposes.)
13
13
 
14
14
  The dependencies between these components are:
15
15
 
@@ -0,0 +1,5 @@
1
+ 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're really getting a proxy object back that will invoke the interceptors (in order) before the requested method of the service is invoked.
2
+
3
+ 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.
4
+
5
+ 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'll have one instance of each interceptor for each instance of your service.
@@ -0,0 +1,64 @@
1
+ There are two ways to attach interceptors to your services. The first is to implement an interceptor _factory_ that returns new interceptor _instances_, and attach the factory to your service. The second is to specify a block that implements the required functionality. Both have their uses.
2
+
3
+ h3. Interceptor Factories
4
+
5
+ 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.
6
+
7
+ 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.
8
+
9
+ You can attach interceptor factories to your service using the @#interceptor(...).with {...}@ syntax:
10
+
11
+ <pre>
12
+ reg.register( :foo ) {...}
13
+ reg.intercept( :foo ).with { MyInterceptorFactory }
14
+ </pre>
15
+
16
+ Note that you could also make the interceptor factory a service:
17
+
18
+ <pre>
19
+ reg.register( :foo ) {...}
20
+ reg.register( :my_interceptor ) { MyInterceptorFactory }
21
+ reg.intercept( :foo ).with { |c| c.my_interceptor }
22
+ </pre>
23
+
24
+ And, to make accessing interceptor services even more convenient, you can use the @#with!@ method (which executes its block within the context of the calling container):
25
+
26
+ <pre>
27
+ reg.register( :foo ) {...}
28
+ reg.register( :my_interceptor ) { MyInterceptorFactory }
29
+ reg.intercept( :foo ).with! { my_interceptor }
30
+ </pre>
31
+
32
+
33
+ h3. Blocks
34
+
35
+ 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
36
+ @#doing@ method. Just give it a block that accepts two parameters (the chain, and context) and you're good to go!
37
+
38
+ <pre>
39
+ reg.register( :foo ) {...}
40
+ reg.intercept( :foo ).doing { |chain,ctx| ...; chain.process_next( ctx ) }
41
+ </pre>
42
+
43
+ Note that this approach is about 40% slower than using an interceptor factory, so it should not be used if performance is an issue.
44
+
45
+ h3. Options
46
+
47
+ Some interceptors can accept configuration options. For example, the LoggingInterceptor allows clients to specify methods that should and shouldn't be intercepted. Options are specified via the @#with_options@ method.
48
+
49
+ <pre>
50
+ reg.register( :foo ) {...}
51
+ reg.intercept( :foo ).
52
+ with { |c| c.logging_interceptor }.
53
+ with_options( :exclude => [ "method1", "method2" ] )
54
+ </pre>
55
+
56
+ Options can apply to the blocks given to the @#doing@ method, too. The block may access the options via the @#data[:options]@ member of the context:
57
+
58
+ <pre>
59
+ reg.intercept( :foo ).
60
+ doing { |ch,ctx| ...; p ctx.data[:options][:value]; ... }.
61
+ with_options( :value => "hello" )
62
+ </pre>
63
+
64
+ With blocks, of course, the value of such an approach is limited.