copland 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. data/doc/README +88 -0
  2. data/doc/manual-html/chapter-1.html +454 -0
  3. data/doc/manual-html/chapter-10.html +399 -0
  4. data/doc/manual-html/chapter-11.html +600 -0
  5. data/doc/manual-html/chapter-12.html +406 -0
  6. data/doc/manual-html/chapter-2.html +382 -0
  7. data/doc/manual-html/chapter-3.html +424 -0
  8. data/doc/manual-html/chapter-4.html +432 -0
  9. data/doc/manual-html/chapter-5.html +381 -0
  10. data/doc/manual-html/chapter-6.html +364 -0
  11. data/doc/manual-html/chapter-7.html +434 -0
  12. data/doc/manual-html/chapter-8.html +373 -0
  13. data/doc/manual-html/chapter-9.html +324 -0
  14. data/doc/manual-html/copland.png +0 -0
  15. data/doc/manual-html/index.html +331 -0
  16. data/doc/manual-html/manual.css +179 -0
  17. data/doc/manual-html/tutorial-1.html +407 -0
  18. data/doc/manual-html/tutorial-2.html +451 -0
  19. data/doc/manual-html/tutorial-3.html +484 -0
  20. data/doc/manual-html/tutorial-4.html +446 -0
  21. data/doc/manual-html/tutorial-5.html +520 -0
  22. data/doc/manual/chapter.erb +18 -0
  23. data/doc/manual/example.erb +18 -0
  24. data/doc/manual/img/copland.png +0 -0
  25. data/doc/manual/index.erb +30 -0
  26. data/doc/manual/manual.css +179 -0
  27. data/doc/manual/manual.rb +239 -0
  28. data/doc/manual/manual.yml +2643 -0
  29. data/doc/manual/page.erb +102 -0
  30. data/doc/manual/tutorial.erb +30 -0
  31. data/doc/packages/copland.html +764 -0
  32. data/doc/packages/copland.lib.html +439 -0
  33. data/doc/packages/copland.remote.html +2096 -0
  34. data/doc/packages/copland.webrick.html +925 -0
  35. data/doc/packages/index.html +49 -0
  36. data/doc/packages/packrat.css +125 -0
  37. data/examples/calc/calc.rb +47 -0
  38. data/examples/calc/package.yml +35 -0
  39. data/examples/calc/services.rb +74 -0
  40. data/examples/solitaire-cipher/README +11 -0
  41. data/examples/solitaire-cipher/Rakefile +57 -0
  42. data/examples/solitaire-cipher/bin/main.rb +14 -0
  43. data/examples/solitaire-cipher/lib/cipher.rb +230 -0
  44. data/examples/solitaire-cipher/lib/cli.rb +24 -0
  45. data/examples/solitaire-cipher/lib/package.yml +106 -0
  46. data/examples/solitaire-cipher/test/tc_deck.rb +30 -0
  47. data/examples/solitaire-cipher/test/tc_key-stream.rb +19 -0
  48. data/examples/solitaire-cipher/test/tc_keying-algorithms.rb +31 -0
  49. data/examples/solitaire-cipher/test/tc_solitaire-cipher.rb +66 -0
  50. data/examples/solitaire-cipher/test/tc_unkeyed-algorithm.rb +17 -0
  51. data/examples/solitaire-cipher/test/tests.rb +2 -0
  52. data/lib/copland.rb +56 -0
  53. data/lib/copland/class-factory.rb +95 -0
  54. data/lib/copland/configuration-point.rb +38 -0
  55. data/lib/copland/configuration-point/common.rb +203 -0
  56. data/lib/copland/configuration-point/errors.rb +44 -0
  57. data/lib/copland/configuration-point/list.rb +59 -0
  58. data/lib/copland/configuration-point/map.rb +59 -0
  59. data/lib/copland/configuration/errors.rb +43 -0
  60. data/lib/copland/configuration/loader.rb +113 -0
  61. data/lib/copland/configuration/yaml/configuration-point.rb +87 -0
  62. data/lib/copland/configuration/yaml/implementor.rb +134 -0
  63. data/lib/copland/configuration/yaml/interceptor.rb +63 -0
  64. data/lib/copland/configuration/yaml/listener.rb +56 -0
  65. data/lib/copland/configuration/yaml/loader.rb +122 -0
  66. data/lib/copland/configuration/yaml/package.rb +125 -0
  67. data/lib/copland/configuration/yaml/parser.rb +71 -0
  68. data/lib/copland/configuration/yaml/schema.rb +165 -0
  69. data/lib/copland/configuration/yaml/service-point.rb +116 -0
  70. data/lib/copland/configuration/yaml/utils.rb +82 -0
  71. data/lib/copland/default-schema-processor.rb +144 -0
  72. data/lib/copland/errors.rb +82 -0
  73. data/lib/copland/event-producer.rb +95 -0
  74. data/lib/copland/impl/builder-factory.rb +112 -0
  75. data/lib/copland/impl/copland-config.yml +1 -0
  76. data/lib/copland/impl/include-exclude.rb +140 -0
  77. data/lib/copland/impl/logging-interceptor.rb +106 -0
  78. data/lib/copland/impl/package.yml +217 -0
  79. data/lib/copland/impl/startup.rb +116 -0
  80. data/lib/copland/impl/symbol-source-manager.rb +131 -0
  81. data/lib/copland/impl/symbol-source.rb +63 -0
  82. data/lib/copland/instantiator.rb +38 -0
  83. data/lib/copland/instantiator/abstract.rb +91 -0
  84. data/lib/copland/instantiator/complex.rb +96 -0
  85. data/lib/copland/instantiator/identity.rb +58 -0
  86. data/lib/copland/instantiator/simple.rb +68 -0
  87. data/lib/copland/interceptor-chain.rb +166 -0
  88. data/lib/copland/interceptor.rb +139 -0
  89. data/lib/copland/log-factory.rb +206 -0
  90. data/lib/copland/models.rb +39 -0
  91. data/lib/copland/models/abstract.rb +78 -0
  92. data/lib/copland/models/prototype-deferred.rb +58 -0
  93. data/lib/copland/models/prototype.rb +58 -0
  94. data/lib/copland/models/proxy.rb +100 -0
  95. data/lib/copland/models/singleton-deferred.rb +59 -0
  96. data/lib/copland/models/singleton.rb +77 -0
  97. data/lib/copland/models/threaded.rb +65 -0
  98. data/lib/copland/ordering.rb +123 -0
  99. data/lib/copland/package.rb +246 -0
  100. data/lib/copland/registry.rb +368 -0
  101. data/lib/copland/schema.rb +206 -0
  102. data/lib/copland/service-point.rb +282 -0
  103. data/lib/copland/utils.rb +221 -0
  104. data/lib/copland/version.rb +47 -0
  105. data/test/conf-test/list-bad-key.yml +30 -0
  106. data/test/conf-test/list-bad-missing.yml +28 -0
  107. data/test/conf-test/list-bad-type.yml +28 -0
  108. data/test/conf-test/list-good.yml +29 -0
  109. data/test/conf-test/map-bad-key.yml +25 -0
  110. data/test/conf-test/map-bad-missing.yml +24 -0
  111. data/test/conf-test/map-bad-type.yml +23 -0
  112. data/test/conf-test/map-good.yml +25 -0
  113. data/test/configuration-point/package.yml +52 -0
  114. data/test/configuration/yaml/config/copland-config.yml +2 -0
  115. data/test/configuration/yaml/config/module.yml +2 -0
  116. data/test/configuration/yaml/config/subdir/copland-config.yml +2 -0
  117. data/test/configuration/yaml/config/subdir/package.yml +4 -0
  118. data/test/configuration/yaml/defaults/package.yml +5 -0
  119. data/test/configuration/yaml/defaults/subdir/package.yml +4 -0
  120. data/test/configuration/yaml/tc_config-loader.rb +86 -0
  121. data/test/configuration/yaml/tc_configuration-point-processor.rb +134 -0
  122. data/test/configuration/yaml/tc_implementor-processor.rb +104 -0
  123. data/test/configuration/yaml/tc_interceptor-processor.rb +85 -0
  124. data/test/configuration/yaml/tc_listener-processor.rb +69 -0
  125. data/test/configuration/yaml/tc_loader.rb +74 -0
  126. data/test/configuration/yaml/tc_package-processor.rb +120 -0
  127. data/test/configuration/yaml/tc_parser.rb +94 -0
  128. data/test/configuration/yaml/tc_schema-parser.rb +160 -0
  129. data/test/configuration/yaml/tc_service-point-processor.rb +104 -0
  130. data/test/configuration/yaml/tc_type-validator.rb +90 -0
  131. data/test/custom-logger.yml +3 -0
  132. data/test/impl/logging/package.yml +44 -0
  133. data/test/impl/logging/services.rb +84 -0
  134. data/test/impl/startup/package.yml +46 -0
  135. data/test/impl/startup/services.rb +47 -0
  136. data/test/impl/symbols/package.yml +24 -0
  137. data/test/impl/symbols/services.rb +38 -0
  138. data/test/impl/tc_builder-factory.rb +173 -0
  139. data/test/impl/tc_logging-interceptor.rb +148 -0
  140. data/test/impl/tc_startup.rb +59 -0
  141. data/test/impl/tc_symbol-sources.rb +61 -0
  142. data/test/logger.yml +6 -0
  143. data/test/mock.rb +201 -0
  144. data/test/schema/bad-package.yml +65 -0
  145. data/test/schema/package.yml +102 -0
  146. data/test/schema/services.rb +5 -0
  147. data/test/services/package.yml +79 -0
  148. data/test/services/simple.rb +87 -0
  149. data/test/tc_class-factory.rb +93 -0
  150. data/test/tc_complex-instantiator.rb +107 -0
  151. data/test/tc_configuration-point-contrib.rb +74 -0
  152. data/test/tc_configuration-point-schema.rb +122 -0
  153. data/test/tc_configuration-point.rb +91 -0
  154. data/test/tc_default-schema-processor.rb +297 -0
  155. data/test/tc_identity-instantiator.rb +61 -0
  156. data/test/tc_interceptors.rb +84 -0
  157. data/test/tc_logger.rb +131 -0
  158. data/test/tc_models.rb +176 -0
  159. data/test/tc_package.rb +165 -0
  160. data/test/tc_proxy.rb +65 -0
  161. data/test/tc_registry.rb +141 -0
  162. data/test/tc_schema.rb +78 -0
  163. data/test/tc_service-point.rb +178 -0
  164. data/test/tc_service.rb +70 -0
  165. data/test/tc_simple-instantiator.rb +61 -0
  166. data/test/tests.rb +93 -0
  167. data/tutorial/01/main.rb +7 -0
  168. data/tutorial/01/package.yml +8 -0
  169. data/tutorial/01/tutorial.rb +7 -0
  170. data/tutorial/02/main.rb +10 -0
  171. data/tutorial/02/package.yml +27 -0
  172. data/tutorial/02/tutorial.rb +46 -0
  173. data/tutorial/03/main.rb +24 -0
  174. data/tutorial/03/package.yml +29 -0
  175. data/tutorial/03/tutorial.rb +48 -0
  176. data/tutorial/04/main.rb +24 -0
  177. data/tutorial/04/package.yml +35 -0
  178. data/tutorial/04/tutorial.rb +48 -0
  179. data/tutorial/05/functions/package.yml +16 -0
  180. data/tutorial/05/functions/services.rb +15 -0
  181. data/tutorial/05/main.rb +10 -0
  182. data/tutorial/05/package.yml +35 -0
  183. data/tutorial/05/tutorial.rb +53 -0
  184. metadata +260 -0
@@ -0,0 +1,451 @@
1
+ <html>
2
+ <head>
3
+ <title>Copland Manual :: Tutorial 2: Service Factories</title>
4
+ <link type="text/css" rel="stylesheet" href="manual.css" />
5
+ </head>
6
+
7
+ <body>
8
+ <div id="banner">
9
+ <table border='0' cellpadding='0' cellspacing='0' width='100%'>
10
+ <tr><td valign='top' align='left'>
11
+ <div class="title">
12
+ <span class="product">Copland&mdash;</span><br />
13
+ <span class="tagline">compose yourself...</span>
14
+ </div>
15
+ </td><td valign='middle' align='right'>
16
+ <div class="info">
17
+ Copland Version: <strong>0.8.0</strong><br />
18
+ Manual Last Updated: <strong>2004-09-27 03:37 GMT</strong>
19
+ </div>
20
+ </td></tr>
21
+ </table>
22
+ </div>
23
+
24
+ <table border='0' width='100%' cellpadding='0' cellspacing='0'>
25
+ <tr><td valign='top'>
26
+
27
+ <div id="navigation">
28
+ <h1>Copland Manual</h1>
29
+
30
+ <h2>Chapters</h2>
31
+ <ol type="I">
32
+
33
+ <li>
34
+ <a href="chapter-1.html">
35
+ Introduction
36
+ </a>
37
+
38
+ <ol type="1">
39
+
40
+ <li><a href="chapter-1.html#s1">What is Copland?</a></li>
41
+
42
+ <li><a href="chapter-1.html#s2">Features</a></li>
43
+
44
+ <li><a href="chapter-1.html#s3">Getting Copland</a></li>
45
+
46
+ <li><a href="chapter-1.html#s4">License Information</a></li>
47
+
48
+ <li><a href="chapter-1.html#s5">Support</a></li>
49
+
50
+ </ol>
51
+ </li>
52
+
53
+ <li>
54
+ <a href="chapter-2.html">
55
+ Justification
56
+ </a>
57
+
58
+ <ol type="1">
59
+
60
+ <li><a href="chapter-2.html#s1">IoC in One Paragraph</a></li>
61
+
62
+ <li><a href="chapter-2.html#s2">Why IoC?</a></li>
63
+
64
+ <li><a href="chapter-2.html#s3">A Case Study</a></li>
65
+
66
+ </ol>
67
+ </li>
68
+
69
+ <li>
70
+ <a href="chapter-3.html">
71
+ Getting Started
72
+ </a>
73
+
74
+ <ol type="1">
75
+
76
+ <li><a href="chapter-3.html#s1">Terminology</a></li>
77
+
78
+ <li><a href="chapter-3.html#s2">Quickstart</a></li>
79
+
80
+ </ol>
81
+ </li>
82
+
83
+ <li>
84
+ <a href="chapter-4.html">
85
+ Copland's Design
86
+ </a>
87
+
88
+ <ol type="1">
89
+
90
+ <li><a href="chapter-4.html#s1">HiveMind</a></li>
91
+
92
+ <li><a href="chapter-4.html#s2">Registry Initialization</a></li>
93
+
94
+ <li><a href="chapter-4.html#s3">Service Instantiation</a></li>
95
+
96
+ <li><a href="chapter-4.html#s4">Interceptor Chains</a></li>
97
+
98
+ </ol>
99
+ </li>
100
+
101
+ <li>
102
+ <a href="chapter-5.html">
103
+ Packages
104
+ </a>
105
+
106
+ <ol type="1">
107
+
108
+ <li><a href="chapter-5.html#s1">Descriptor Syntax</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Tips</a></li>
111
+
112
+ </ol>
113
+ </li>
114
+
115
+ <li>
116
+ <a href="chapter-6.html">
117
+ Service Points
118
+ </a>
119
+
120
+ <ol type="1">
121
+
122
+ <li><a href="chapter-6.html#s1">Descriptor Syntax</a></li>
123
+
124
+ </ol>
125
+ </li>
126
+
127
+ <li>
128
+ <a href="chapter-7.html">
129
+ Service Models
130
+ </a>
131
+
132
+ <ol type="1">
133
+
134
+ <li><a href="chapter-7.html#s1">Standard Models</a></li>
135
+
136
+ <li><a href="chapter-7.html#s2">Deferred Instantiation</a></li>
137
+
138
+ <li><a href="chapter-7.html#s3">Custom Service Models</a></li>
139
+
140
+ </ol>
141
+ </li>
142
+
143
+ <li>
144
+ <a href="chapter-8.html">
145
+ Configuration Points
146
+ </a>
147
+
148
+ <ol type="1">
149
+
150
+ <li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
151
+
152
+ <li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
153
+
154
+ </ol>
155
+ </li>
156
+
157
+ <li>
158
+ <a href="chapter-9.html">
159
+ Contributions
160
+ </a>
161
+
162
+ <ol type="1">
163
+
164
+ </ol>
165
+ </li>
166
+
167
+ <li>
168
+ <a href="chapter-10.html">
169
+ Service Factories
170
+ </a>
171
+
172
+ <ol type="1">
173
+
174
+ <li><a href="chapter-10.html#s1">Schemas</a></li>
175
+
176
+ <li><a href="chapter-10.html#s2">How do they work?</a></li>
177
+
178
+ <li><a href="chapter-10.html#s3">BuilderFactory</a></li>
179
+
180
+ </ol>
181
+ </li>
182
+
183
+ <li>
184
+ <a href="chapter-11.html">
185
+ Schemas
186
+ </a>
187
+
188
+ <ol type="1">
189
+
190
+ <li><a href="chapter-11.html#s1">Basic Format</a></li>
191
+
192
+ <li><a href="chapter-11.html#s2">Subschemas</a></li>
193
+
194
+ <li><a href="chapter-11.html#s3">Arrays</a></li>
195
+
196
+ <li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
197
+
198
+ <li><a href="chapter-11.html#s5">Extending Schemas</a></li>
199
+
200
+ <li><a href="chapter-11.html#s6">Limitations</a></li>
201
+
202
+ </ol>
203
+ </li>
204
+
205
+ <li>
206
+ <a href="chapter-12.html">
207
+ Listeners and Event Producers
208
+ </a>
209
+
210
+ <ol type="1">
211
+
212
+ <li><a href="chapter-12.html#s1">Event Producers</a></li>
213
+
214
+ <li><a href="chapter-12.html#s2">Listeners</a></li>
215
+
216
+ <li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
217
+
218
+ </ol>
219
+ </li>
220
+
221
+ </ol>
222
+
223
+ <h2>API Reference</h2>
224
+
225
+ <ul>
226
+ <li><a href="http://copland.rubyforge.org/api/index.html">Copland API</a></li>
227
+ <li><a href="http://copland.rubyforge.org/packrat/index.html">Package Reference</a></li>
228
+ </ul>
229
+
230
+ <h2>Tutorials</h2>
231
+ <ol>
232
+
233
+ <li>
234
+ <a href="tutorial-1.html">
235
+ Creating Services
236
+ </a>
237
+ <br />
238
+ <p>The basics of creating new services in Copland.</p>
239
+ </li>
240
+
241
+ <li><strong>
242
+ <a href="tutorial-2.html">
243
+ Service Factories
244
+ </a>
245
+ </strong> <big>&larr;</big><br />
246
+ <p>Introduces the concept of a &#8220;service factory&#8221;, and shows how to use them to create complex services.</p>
247
+ </li>
248
+
249
+ <li>
250
+ <a href="tutorial-3.html">
251
+ Service Models
252
+ </a>
253
+ <br />
254
+ <p>Introduces the concept of the &#8220;service model&#8221;, and shows the difference between &#8220;singleton&#8221; and &#8220;prototype&#8221;.</p>
255
+ </li>
256
+
257
+ <li>
258
+ <a href="tutorial-4.html">
259
+ Logging Interceptor
260
+ </a>
261
+ <br />
262
+ <p>Shows how to use the logging interceptor to add logging for method invocations on any service.</p>
263
+ </li>
264
+
265
+ <li>
266
+ <a href="tutorial-5.html">
267
+ Configuration Points
268
+ </a>
269
+ <br />
270
+ <p>Demonstrates the use of configuration points for decentralizing service configuration.</p>
271
+ </li>
272
+
273
+ </ol>
274
+
275
+ <p align="center"><strong>More To Come...</strong></p>
276
+
277
+ <!--
278
+ <h2>Examples</h2>
279
+ <ol>
280
+
281
+ </ol>
282
+ -->
283
+
284
+ <div class="license">
285
+ <a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
286
+ This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
287
+ </div>
288
+ </div>
289
+
290
+ </td><td valign='top' width="100%">
291
+
292
+ <div id="content">
293
+
294
+ <h1>Tutorial #2. Service Factories</h1>
295
+
296
+ <p>The sources for this tutorial may be found in the <tt>tutorial/02</tt>
297
+ directory of the Copland distribution.</p>
298
+
299
+
300
+
301
+ <h2>Introduction</h2>
302
+
303
+ <p>As you saw in the last tutorial, you can create services by mapping them directly to Ruby classes. The last tutorial used the <em>simple</em> implementor to do this, which has its limitations. For one, the class must have a no-argument constructor, which restricts what classes you can use with it.</p>
304
+
305
+ <p>This tutorial will demonstrate the use of <em>service factories</em> to perform more complex styles of instantiation and initialization.</p>
306
+
307
+ <p>A <em>service factory</em> is just a special kind of service that is used to create other services. There are several different service factories that Copland provides by default; this tutorial will only use the BuilderFactory.</p>
308
+
309
+ <p>This tutorial will continue the application started in the first tutorial. We&#8217;ll extend the &#8220;adder&#8221; example into a simple calculator object that delegates its operations to different services.</p>
310
+
311
+
312
+
313
+ <h2>Steps</h2>
314
+
315
+ <ol>
316
+
317
+
318
+ <li><h3>Implement the Services</h3>
319
+
320
+ <p>Most calculators support at least four operations: addition, multiplication, division, and subtraction. We&#8217;ve already got a service that does addition: let&#8217;s write three more that do the multiplication, division, and subtraction:</p>
321
+
322
+ <pre>
323
+ class Subtractor
324
+ def subtract( a, b )
325
+ a.to_f - b.to_f
326
+ end
327
+ end
328
+
329
+ class Multiplier
330
+ def multiply( a, b )
331
+ a.to_f * b.to_f
332
+ end
333
+ end
334
+
335
+ class Divider
336
+ def divide( a, b )
337
+ a.to_f / b.to_f
338
+ end
339
+ end
340
+ </pre>
341
+
342
+ <p>Lastly, we&#8217;ll create our calculator class:</p>
343
+
344
+ <pre>
345
+ class Calculator
346
+ attr_writer :adder
347
+ attr_writer :subtractor
348
+ attr_writer :multiplier
349
+ attr_writer :divider
350
+
351
+ def add( a, b )
352
+ @adder.add( a, b )
353
+ end
354
+
355
+ def subtract( a, b )
356
+ @subtractor.subtract( a, b )
357
+ end
358
+
359
+ def multiply( a, b )
360
+ @multiplier.multiply( a, b )
361
+ end
362
+
363
+ def divide( a, b )
364
+ @divider.divide( a, b )
365
+ end
366
+ end
367
+ </pre>
368
+
369
+ <p>Notice that we never instantiate any of the delegate classes: we&#8217;re going to leave that up to Copland. Instead, we simply provide some setters, which Copland will use to set those dependencies. (Note that these setters can also aid in unit testing, since you can easily set each of those properties to some mock object. We won&#8217;t demonstrate that, though, since unit testing is beyond the scope of this tutorial.)</p></li>
370
+
371
+
372
+
373
+ <li><h3>Package Descriptor</h3>
374
+
375
+ <p>We now add to our package descriptor. Just as we defined a service point for the Adder class, we now have to add service points for each of the other classes we created.</p>
376
+
377
+ <p>The Subtractor, Multiplier, and Divider service points will look very much like the Adder service point. Each uses the <em>simple</em> implementor.</p>
378
+
379
+ <pre>
380
+ Subtractor:
381
+ implementor: tutorial/Subtractor
382
+
383
+ Multiplier:
384
+ implementor: tutorial/Multiplier
385
+
386
+ Divider:
387
+ implementor: tutorial/Divider
388
+ </pre>
389
+
390
+ <p>The Calculator service point, however, is a bit more complicated. Not only do we need to say what class implements the service, but we also need to say what services get wired into it for each of its properties. To do this, we&#8217;ll use the <code>copland.BuilderFactory</code> service.</p>
391
+
392
+ <pre>
393
+ Calculator:
394
+ implementor:
395
+ factory: copland.BuilderFactory
396
+ class: tutorial/Calculator
397
+ properties:
398
+ adder: !!service tutorial.Adder
399
+ subtractor: !!service tutorial.Subtractor
400
+ divider: !!service tutorial.Divider
401
+ multiplier: !!service tutorial.Multiplier
402
+ </pre>
403
+
404
+ <p>The <code>implementor</code> section, in this case, is a map, instead of a string. The map specifies the service <em>factory</em> to use (<code>copland.BuilderFactory</code>, in this case), the <em>class</em> that will implement the service, and the properties that will be set. (Note that if you are using <code>copland.BuilderFactory</code> as your service factory, you can omit the <code>factory</code> element. It is retained explicitly for this tutorial to demonstrate the use of the <code>factory</code> element.)</p>
405
+
406
+ <p>Note the special syntax of the properties: that <code>!!service</code> bit says that the following name is the name of a service point that should be instantiated and passed as the value of the corresponding property. In other words, when the BuilderFactory instantiates the Calculator class, it will also obtain references to the Adder, Subtractor, Divider, and Multiplier services, and wire them into the appropriate properties of the new Calculator object.</p>
407
+
408
+ <p>Lastly, note that we used the fully-qualified service names for the dependencies (i.e., &#8220;tutorial.Adder&#8221;). Because the Calculator service point is in the same package as the dependencies, we could have simply given the names of the service points, unqualified (without the package names).</p></li>
409
+
410
+
411
+
412
+ <li><h3>Putting it all Together</h3>
413
+
414
+ <p>We&#8217;ll modify the &#8220;main.rb&#8221; driver file slightly, to test our new Calculator service:</p>
415
+
416
+ <pre>
417
+ require 'copland'
418
+
419
+ registry = Copland::Registry.build
420
+
421
+ calc = registry.service( "tutorial.Calculator" )
422
+
423
+ puts calc.add( "5", 7 )
424
+ puts calc.subtract( "5", 7 )
425
+ puts calc.multiply( "5", 7 )
426
+ puts calc.divide( "5", 7 )
427
+ </pre>
428
+
429
+ <p>Once run, you should see the program spit out the answers, as you would expect.<br />
430
+ </p></li>
431
+
432
+
433
+ </ol>
434
+
435
+
436
+
437
+ <h2>Summary</h2>
438
+
439
+ <p>This tutorial showed you how to use more complicated implementors. In particular, it showed you how to have Copland automatically wire dependencies together, instantiating services as needed. However, you only saw how to use properties to wire services together; you can also specify constructor parameters that will be passed to the new service when it is instantiated.</p>
440
+
441
+ <p>You also saw how to use the <code>!!service</code> directive, to instruct Copland to interpret a value as a service point name, instead of simply as a string. There are several such directives; see the Copland documentation for a comprehensive list.</p>
442
+
443
+
444
+
445
+
446
+ </div>
447
+
448
+ </td></tr>
449
+ </table>
450
+ </body>
451
+ </html>
@@ -0,0 +1,484 @@
1
+ <html>
2
+ <head>
3
+ <title>Copland Manual :: Tutorial 3: Service Models</title>
4
+ <link type="text/css" rel="stylesheet" href="manual.css" />
5
+ </head>
6
+
7
+ <body>
8
+ <div id="banner">
9
+ <table border='0' cellpadding='0' cellspacing='0' width='100%'>
10
+ <tr><td valign='top' align='left'>
11
+ <div class="title">
12
+ <span class="product">Copland&mdash;</span><br />
13
+ <span class="tagline">compose yourself...</span>
14
+ </div>
15
+ </td><td valign='middle' align='right'>
16
+ <div class="info">
17
+ Copland Version: <strong>0.8.0</strong><br />
18
+ Manual Last Updated: <strong>2004-09-27 03:37 GMT</strong>
19
+ </div>
20
+ </td></tr>
21
+ </table>
22
+ </div>
23
+
24
+ <table border='0' width='100%' cellpadding='0' cellspacing='0'>
25
+ <tr><td valign='top'>
26
+
27
+ <div id="navigation">
28
+ <h1>Copland Manual</h1>
29
+
30
+ <h2>Chapters</h2>
31
+ <ol type="I">
32
+
33
+ <li>
34
+ <a href="chapter-1.html">
35
+ Introduction
36
+ </a>
37
+
38
+ <ol type="1">
39
+
40
+ <li><a href="chapter-1.html#s1">What is Copland?</a></li>
41
+
42
+ <li><a href="chapter-1.html#s2">Features</a></li>
43
+
44
+ <li><a href="chapter-1.html#s3">Getting Copland</a></li>
45
+
46
+ <li><a href="chapter-1.html#s4">License Information</a></li>
47
+
48
+ <li><a href="chapter-1.html#s5">Support</a></li>
49
+
50
+ </ol>
51
+ </li>
52
+
53
+ <li>
54
+ <a href="chapter-2.html">
55
+ Justification
56
+ </a>
57
+
58
+ <ol type="1">
59
+
60
+ <li><a href="chapter-2.html#s1">IoC in One Paragraph</a></li>
61
+
62
+ <li><a href="chapter-2.html#s2">Why IoC?</a></li>
63
+
64
+ <li><a href="chapter-2.html#s3">A Case Study</a></li>
65
+
66
+ </ol>
67
+ </li>
68
+
69
+ <li>
70
+ <a href="chapter-3.html">
71
+ Getting Started
72
+ </a>
73
+
74
+ <ol type="1">
75
+
76
+ <li><a href="chapter-3.html#s1">Terminology</a></li>
77
+
78
+ <li><a href="chapter-3.html#s2">Quickstart</a></li>
79
+
80
+ </ol>
81
+ </li>
82
+
83
+ <li>
84
+ <a href="chapter-4.html">
85
+ Copland's Design
86
+ </a>
87
+
88
+ <ol type="1">
89
+
90
+ <li><a href="chapter-4.html#s1">HiveMind</a></li>
91
+
92
+ <li><a href="chapter-4.html#s2">Registry Initialization</a></li>
93
+
94
+ <li><a href="chapter-4.html#s3">Service Instantiation</a></li>
95
+
96
+ <li><a href="chapter-4.html#s4">Interceptor Chains</a></li>
97
+
98
+ </ol>
99
+ </li>
100
+
101
+ <li>
102
+ <a href="chapter-5.html">
103
+ Packages
104
+ </a>
105
+
106
+ <ol type="1">
107
+
108
+ <li><a href="chapter-5.html#s1">Descriptor Syntax</a></li>
109
+
110
+ <li><a href="chapter-5.html#s2">Tips</a></li>
111
+
112
+ </ol>
113
+ </li>
114
+
115
+ <li>
116
+ <a href="chapter-6.html">
117
+ Service Points
118
+ </a>
119
+
120
+ <ol type="1">
121
+
122
+ <li><a href="chapter-6.html#s1">Descriptor Syntax</a></li>
123
+
124
+ </ol>
125
+ </li>
126
+
127
+ <li>
128
+ <a href="chapter-7.html">
129
+ Service Models
130
+ </a>
131
+
132
+ <ol type="1">
133
+
134
+ <li><a href="chapter-7.html#s1">Standard Models</a></li>
135
+
136
+ <li><a href="chapter-7.html#s2">Deferred Instantiation</a></li>
137
+
138
+ <li><a href="chapter-7.html#s3">Custom Service Models</a></li>
139
+
140
+ </ol>
141
+ </li>
142
+
143
+ <li>
144
+ <a href="chapter-8.html">
145
+ Configuration Points
146
+ </a>
147
+
148
+ <ol type="1">
149
+
150
+ <li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
151
+
152
+ <li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
153
+
154
+ </ol>
155
+ </li>
156
+
157
+ <li>
158
+ <a href="chapter-9.html">
159
+ Contributions
160
+ </a>
161
+
162
+ <ol type="1">
163
+
164
+ </ol>
165
+ </li>
166
+
167
+ <li>
168
+ <a href="chapter-10.html">
169
+ Service Factories
170
+ </a>
171
+
172
+ <ol type="1">
173
+
174
+ <li><a href="chapter-10.html#s1">Schemas</a></li>
175
+
176
+ <li><a href="chapter-10.html#s2">How do they work?</a></li>
177
+
178
+ <li><a href="chapter-10.html#s3">BuilderFactory</a></li>
179
+
180
+ </ol>
181
+ </li>
182
+
183
+ <li>
184
+ <a href="chapter-11.html">
185
+ Schemas
186
+ </a>
187
+
188
+ <ol type="1">
189
+
190
+ <li><a href="chapter-11.html#s1">Basic Format</a></li>
191
+
192
+ <li><a href="chapter-11.html#s2">Subschemas</a></li>
193
+
194
+ <li><a href="chapter-11.html#s3">Arrays</a></li>
195
+
196
+ <li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
197
+
198
+ <li><a href="chapter-11.html#s5">Extending Schemas</a></li>
199
+
200
+ <li><a href="chapter-11.html#s6">Limitations</a></li>
201
+
202
+ </ol>
203
+ </li>
204
+
205
+ <li>
206
+ <a href="chapter-12.html">
207
+ Listeners and Event Producers
208
+ </a>
209
+
210
+ <ol type="1">
211
+
212
+ <li><a href="chapter-12.html#s1">Event Producers</a></li>
213
+
214
+ <li><a href="chapter-12.html#s2">Listeners</a></li>
215
+
216
+ <li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
217
+
218
+ </ol>
219
+ </li>
220
+
221
+ </ol>
222
+
223
+ <h2>API Reference</h2>
224
+
225
+ <ul>
226
+ <li><a href="http://copland.rubyforge.org/api/index.html">Copland API</a></li>
227
+ <li><a href="http://copland.rubyforge.org/packrat/index.html">Package Reference</a></li>
228
+ </ul>
229
+
230
+ <h2>Tutorials</h2>
231
+ <ol>
232
+
233
+ <li>
234
+ <a href="tutorial-1.html">
235
+ Creating Services
236
+ </a>
237
+ <br />
238
+ <p>The basics of creating new services in Copland.</p>
239
+ </li>
240
+
241
+ <li>
242
+ <a href="tutorial-2.html">
243
+ Service Factories
244
+ </a>
245
+ <br />
246
+ <p>Introduces the concept of a &#8220;service factory&#8221;, and shows how to use them to create complex services.</p>
247
+ </li>
248
+
249
+ <li><strong>
250
+ <a href="tutorial-3.html">
251
+ Service Models
252
+ </a>
253
+ </strong> <big>&larr;</big><br />
254
+ <p>Introduces the concept of the &#8220;service model&#8221;, and shows the difference between &#8220;singleton&#8221; and &#8220;prototype&#8221;.</p>
255
+ </li>
256
+
257
+ <li>
258
+ <a href="tutorial-4.html">
259
+ Logging Interceptor
260
+ </a>
261
+ <br />
262
+ <p>Shows how to use the logging interceptor to add logging for method invocations on any service.</p>
263
+ </li>
264
+
265
+ <li>
266
+ <a href="tutorial-5.html">
267
+ Configuration Points
268
+ </a>
269
+ <br />
270
+ <p>Demonstrates the use of configuration points for decentralizing service configuration.</p>
271
+ </li>
272
+
273
+ </ol>
274
+
275
+ <p align="center"><strong>More To Come...</strong></p>
276
+
277
+ <!--
278
+ <h2>Examples</h2>
279
+ <ol>
280
+
281
+ </ol>
282
+ -->
283
+
284
+ <div class="license">
285
+ <a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
286
+ This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
287
+ </div>
288
+ </div>
289
+
290
+ </td><td valign='top' width="100%">
291
+
292
+ <div id="content">
293
+
294
+ <h1>Tutorial #3. Service Models</h1>
295
+
296
+ <p>The sources for this tutorial may be found in the <tt>tutorial/03</tt>
297
+ directory of the Copland distribution.</p>
298
+
299
+
300
+
301
+ <h2>Introduction</h2>
302
+
303
+ <p>Let&#8217;s take our calculator example one step further and add a &#8220;memory&#8221; function. By storing a value into the memory, you can then call the various operators with only one parameter, and have them operate on the remembered value.</p>
304
+
305
+ <p>Sound cool? It&#8217;s also pretty easy! Here goes&#8230;</p>
306
+
307
+
308
+
309
+ <h2>Steps</h2>
310
+
311
+ <ol>
312
+
313
+
314
+ <li><h3>Add the Memory</h3>
315
+
316
+ <p>First, we need to modify the calculator to hack in support for memory. This involves adding an instance variable and two methods, getters and setters for that variable:</p>
317
+
318
+ <pre>
319
+ attr_accessor :memory
320
+ </pre>
321
+
322
+ <p>We don&#8217;t worry about initializing the corresponding instance variable in the code&#8212;that&#8217;s more properly a task for the IoC container. We just edit the &#8220;package.yml&#8221; file and add another property initializer to the Calculator service:</p>
323
+
324
+ <pre>
325
+ Calculator:
326
+ implementor:
327
+ factory: copland.BuilderFactory
328
+ class: tutorial/Calculator
329
+ properties:
330
+ adder: !!service Adder
331
+ subtractor: !!service Subtractor
332
+ divider: !!service Divider
333
+ multiplier: !!service Multiplier
334
+ memory: 0
335
+ </pre>
336
+
337
+ <p>This then says then when constructing a Calculator service, always set the memory property to 0.</p></li>
338
+
339
+
340
+
341
+ <li><h3>Modify the Operators</h3>
342
+
343
+ <p>Next, we need to modify the operators so that they each treat the second parameter as optional, defaulting to our memory variable:</p>
344
+
345
+ <pre>
346
+ def add( a, b=memory )
347
+ @adder.add( a, b )
348
+ end
349
+
350
+ def subtract( a, b=memory )
351
+ @subtractor.subtract( a, b )
352
+ end
353
+
354
+ def multiply( a, b=memory )
355
+ @multiplier.multiply( a, b )
356
+ end
357
+
358
+ def divide( a, b=memory )
359
+ @divider.divide( a, b )
360
+ end
361
+ </pre></li>
362
+
363
+
364
+
365
+ <li><h3>Play</h3>
366
+
367
+ <p>We can now try it by doing multiples and powers of 5. Edit our &#8220;main.rb&#8221; driver file to look something like this:</p>
368
+
369
+ <pre>
370
+ require 'copland'
371
+
372
+ registry = Copland::Registry.build
373
+
374
+ calc = registry.service( "tutorial.Calculator" )
375
+
376
+ puts "Multiples of 5:"
377
+ 10.times do
378
+ puts calc.memory
379
+ calc.memory = calc.add( 5 )
380
+ end
381
+
382
+ calc.memory = 1.0
383
+
384
+ puts
385
+ puts "Powers of 5:"
386
+ 10.times do
387
+ puts calc.memory
388
+ calc.memory = calc.multiply( 5 )
389
+ end
390
+ </pre>
391
+
392
+ <p>When run, it should spit out a list of the multiples of five, and the powers of five! Slick, huh?</p>
393
+
394
+ <p>But wait! Let&#8217;s try another trick&#8212;let&#8217;s get <span class="caps">TWO</span> calculators going at once and have them each dealing with a different base. Should be pretty straightforward to do; perhaps something like this:</p>
395
+
396
+ <pre>
397
+ require 'copland'
398
+
399
+ registry = Copland::Registry.build
400
+
401
+ calc1 = registry.service( "tutorial.Calculator" )
402
+ calc2 = registry.service( "tutorial.Calculator" )
403
+
404
+ puts "Multiples:"
405
+ 10.times do
406
+ puts "#{calc1.memory}\t#{calc2.memory}"
407
+ calc1.memory = calc1.add( 5 )
408
+ calc2.memory = calc2.add( 2 )
409
+ end
410
+
411
+ calc1.memory = 1.0
412
+ calc2.memory = 1.0
413
+
414
+ puts
415
+ puts "Powers:"
416
+ 10.times do
417
+ puts "#{calc1.memory}\t#{calc2.memory}"
418
+ calc1.memory = calc1.multiply( 5 )
419
+ calc2.memory = calc2.multiply( 2 )
420
+ end
421
+ </pre>
422
+
423
+ <p>We save it, run it, and&#8212;<em>what?!?</em> We&#8217;re getting multiples of 7 and powers of 10, for each column&#8230; Huh?!?</p></li>
424
+
425
+
426
+
427
+ <li><h3>Diagnosing the Problem</h3>
428
+
429
+ <p>What&#8217;s happening is this: because you haven&#8217;t specified a <em>service model</em> for the Calculator service point, the default model (<code>singleton-deferred</code>) is being used. Both the <code>singleton</code> and <code>singleton-deferred</code> models are alike in that anytime you request an instance of a service point that uses one of those models, you get <em>the exact same instance back</em>. Just like &#8220;instantiating&#8221; a singleton class.</p>
430
+
431
+ <p>That&#8217;s right. When we requested two instances of the Calculator service, we were actually getting two references to the <em>same instance</em>, instead. Thus, each iteration through the &#8220;multiples&#8221; loop was adding 5+2=7 to the memory, and each iteration through the &#8220;powers&#8221; loop was multiply 5*2=10 by the memory.</p>
432
+
433
+ <p>Huh. Okay, so we know the problem. How do we get the behavior we wanted?</p></li>
434
+
435
+
436
+
437
+ <li><h3>Fixing the Problem</h3>
438
+
439
+ <p>So we understand <em>why</em> the problem is happening. But how do we fix it?</p>
440
+
441
+ <p>Well, first let&#8217;s understand about service models. The service model is what controls <em>when</em> a service point is instantiated. For the singleton models, the service point is only instantiated once&#8212;the first time it is requested. What we want is a service model that will instantiate the service point <em>every</em> time we request it.</p>
442
+
443
+ <p>We&#8217;re in luck. There is just such a service model: <em>prototype</em>. By setting the service model to <code>prototype</code>, we&#8217;ll cause each request for the <code>calc.Calculator</code> service to return a new instance of the Calculator class. Just set the model by specifying the <code>model</code> element in your service point descriptor (in the <code>package.yml</code> file):</p>
444
+
445
+ <pre>
446
+ Calculator:
447
+ model: prototype
448
+ implementor:
449
+ ...
450
+ </pre>
451
+
452
+ <p>Save your file, and run your &#8220;main.rb&#8221; script again&#8212;the output should look much better!</p></li>
453
+
454
+
455
+ </ol>
456
+
457
+
458
+
459
+ <h2>Summary</h2>
460
+
461
+ <p>In this tutorial, you learned:</p>
462
+
463
+ <ol>
464
+ <li>The default service model for a service is <code>singleton-deferred</code>. This model (and it&#8217;s cousin, the <code>singleton</code> service model) both cause a service point to be instantiated only the first time the service is requested.</li>
465
+ <li>To get a service point that is instantiated <em>every</em> time it is requested, use the <code>prototype</code> service model.</li>
466
+ </ol>
467
+
468
+ <p>In general, use the <code>prototype</code> model (or possibly the <code>threaded</code> model) when you have a service that remembers some kind of state. For stateless services, the <code>singleton</code> models are appropriate.</p>
469
+
470
+ <p>Some models are <em>deferring</em> models. This means that the service is not actually constructed until the first time a method is invoked on the new service. The difference is subtle, but important: <code>singleton</code> and <code>singleton-deferred</code> are identical, except with <code>singleton</code> the service is constructed as soon as it is requested, whereas with <code>singleton-deferred</code>, the service won&#8217;t actually be constructed until the last possible moment, when you need to invoke a method of the service.</p>
471
+
472
+ <p>Likewise, there is a <code>prototype-deferred</code> model, to compliment the <code>prototype</code> model.</p>
473
+
474
+ <p>The only other standard service model is the <code>threaded</code> model, which constructs a new instance of the service for each thread that requests it. In that way, it is like a cross between the <code>singleton</code> and <code>prototype</code> models.</p>
475
+
476
+
477
+
478
+
479
+ </div>
480
+
481
+ </td></tr>
482
+ </table>
483
+ </body>
484
+ </html>