copland 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/README +88 -0
- data/doc/manual-html/chapter-1.html +454 -0
- data/doc/manual-html/chapter-10.html +399 -0
- data/doc/manual-html/chapter-11.html +600 -0
- data/doc/manual-html/chapter-12.html +406 -0
- data/doc/manual-html/chapter-2.html +382 -0
- data/doc/manual-html/chapter-3.html +424 -0
- data/doc/manual-html/chapter-4.html +432 -0
- data/doc/manual-html/chapter-5.html +381 -0
- data/doc/manual-html/chapter-6.html +364 -0
- data/doc/manual-html/chapter-7.html +434 -0
- data/doc/manual-html/chapter-8.html +373 -0
- data/doc/manual-html/chapter-9.html +324 -0
- data/doc/manual-html/copland.png +0 -0
- data/doc/manual-html/index.html +331 -0
- data/doc/manual-html/manual.css +179 -0
- data/doc/manual-html/tutorial-1.html +407 -0
- data/doc/manual-html/tutorial-2.html +451 -0
- data/doc/manual-html/tutorial-3.html +484 -0
- data/doc/manual-html/tutorial-4.html +446 -0
- data/doc/manual-html/tutorial-5.html +520 -0
- data/doc/manual/chapter.erb +18 -0
- data/doc/manual/example.erb +18 -0
- data/doc/manual/img/copland.png +0 -0
- data/doc/manual/index.erb +30 -0
- data/doc/manual/manual.css +179 -0
- data/doc/manual/manual.rb +239 -0
- data/doc/manual/manual.yml +2643 -0
- data/doc/manual/page.erb +102 -0
- data/doc/manual/tutorial.erb +30 -0
- data/doc/packages/copland.html +764 -0
- data/doc/packages/copland.lib.html +439 -0
- data/doc/packages/copland.remote.html +2096 -0
- data/doc/packages/copland.webrick.html +925 -0
- data/doc/packages/index.html +49 -0
- data/doc/packages/packrat.css +125 -0
- data/examples/calc/calc.rb +47 -0
- data/examples/calc/package.yml +35 -0
- data/examples/calc/services.rb +74 -0
- data/examples/solitaire-cipher/README +11 -0
- data/examples/solitaire-cipher/Rakefile +57 -0
- data/examples/solitaire-cipher/bin/main.rb +14 -0
- data/examples/solitaire-cipher/lib/cipher.rb +230 -0
- data/examples/solitaire-cipher/lib/cli.rb +24 -0
- data/examples/solitaire-cipher/lib/package.yml +106 -0
- data/examples/solitaire-cipher/test/tc_deck.rb +30 -0
- data/examples/solitaire-cipher/test/tc_key-stream.rb +19 -0
- data/examples/solitaire-cipher/test/tc_keying-algorithms.rb +31 -0
- data/examples/solitaire-cipher/test/tc_solitaire-cipher.rb +66 -0
- data/examples/solitaire-cipher/test/tc_unkeyed-algorithm.rb +17 -0
- data/examples/solitaire-cipher/test/tests.rb +2 -0
- data/lib/copland.rb +56 -0
- data/lib/copland/class-factory.rb +95 -0
- data/lib/copland/configuration-point.rb +38 -0
- data/lib/copland/configuration-point/common.rb +203 -0
- data/lib/copland/configuration-point/errors.rb +44 -0
- data/lib/copland/configuration-point/list.rb +59 -0
- data/lib/copland/configuration-point/map.rb +59 -0
- data/lib/copland/configuration/errors.rb +43 -0
- data/lib/copland/configuration/loader.rb +113 -0
- data/lib/copland/configuration/yaml/configuration-point.rb +87 -0
- data/lib/copland/configuration/yaml/implementor.rb +134 -0
- data/lib/copland/configuration/yaml/interceptor.rb +63 -0
- data/lib/copland/configuration/yaml/listener.rb +56 -0
- data/lib/copland/configuration/yaml/loader.rb +122 -0
- data/lib/copland/configuration/yaml/package.rb +125 -0
- data/lib/copland/configuration/yaml/parser.rb +71 -0
- data/lib/copland/configuration/yaml/schema.rb +165 -0
- data/lib/copland/configuration/yaml/service-point.rb +116 -0
- data/lib/copland/configuration/yaml/utils.rb +82 -0
- data/lib/copland/default-schema-processor.rb +144 -0
- data/lib/copland/errors.rb +82 -0
- data/lib/copland/event-producer.rb +95 -0
- data/lib/copland/impl/builder-factory.rb +112 -0
- data/lib/copland/impl/copland-config.yml +1 -0
- data/lib/copland/impl/include-exclude.rb +140 -0
- data/lib/copland/impl/logging-interceptor.rb +106 -0
- data/lib/copland/impl/package.yml +217 -0
- data/lib/copland/impl/startup.rb +116 -0
- data/lib/copland/impl/symbol-source-manager.rb +131 -0
- data/lib/copland/impl/symbol-source.rb +63 -0
- data/lib/copland/instantiator.rb +38 -0
- data/lib/copland/instantiator/abstract.rb +91 -0
- data/lib/copland/instantiator/complex.rb +96 -0
- data/lib/copland/instantiator/identity.rb +58 -0
- data/lib/copland/instantiator/simple.rb +68 -0
- data/lib/copland/interceptor-chain.rb +166 -0
- data/lib/copland/interceptor.rb +139 -0
- data/lib/copland/log-factory.rb +206 -0
- data/lib/copland/models.rb +39 -0
- data/lib/copland/models/abstract.rb +78 -0
- data/lib/copland/models/prototype-deferred.rb +58 -0
- data/lib/copland/models/prototype.rb +58 -0
- data/lib/copland/models/proxy.rb +100 -0
- data/lib/copland/models/singleton-deferred.rb +59 -0
- data/lib/copland/models/singleton.rb +77 -0
- data/lib/copland/models/threaded.rb +65 -0
- data/lib/copland/ordering.rb +123 -0
- data/lib/copland/package.rb +246 -0
- data/lib/copland/registry.rb +368 -0
- data/lib/copland/schema.rb +206 -0
- data/lib/copland/service-point.rb +282 -0
- data/lib/copland/utils.rb +221 -0
- data/lib/copland/version.rb +47 -0
- data/test/conf-test/list-bad-key.yml +30 -0
- data/test/conf-test/list-bad-missing.yml +28 -0
- data/test/conf-test/list-bad-type.yml +28 -0
- data/test/conf-test/list-good.yml +29 -0
- data/test/conf-test/map-bad-key.yml +25 -0
- data/test/conf-test/map-bad-missing.yml +24 -0
- data/test/conf-test/map-bad-type.yml +23 -0
- data/test/conf-test/map-good.yml +25 -0
- data/test/configuration-point/package.yml +52 -0
- data/test/configuration/yaml/config/copland-config.yml +2 -0
- data/test/configuration/yaml/config/module.yml +2 -0
- data/test/configuration/yaml/config/subdir/copland-config.yml +2 -0
- data/test/configuration/yaml/config/subdir/package.yml +4 -0
- data/test/configuration/yaml/defaults/package.yml +5 -0
- data/test/configuration/yaml/defaults/subdir/package.yml +4 -0
- data/test/configuration/yaml/tc_config-loader.rb +86 -0
- data/test/configuration/yaml/tc_configuration-point-processor.rb +134 -0
- data/test/configuration/yaml/tc_implementor-processor.rb +104 -0
- data/test/configuration/yaml/tc_interceptor-processor.rb +85 -0
- data/test/configuration/yaml/tc_listener-processor.rb +69 -0
- data/test/configuration/yaml/tc_loader.rb +74 -0
- data/test/configuration/yaml/tc_package-processor.rb +120 -0
- data/test/configuration/yaml/tc_parser.rb +94 -0
- data/test/configuration/yaml/tc_schema-parser.rb +160 -0
- data/test/configuration/yaml/tc_service-point-processor.rb +104 -0
- data/test/configuration/yaml/tc_type-validator.rb +90 -0
- data/test/custom-logger.yml +3 -0
- data/test/impl/logging/package.yml +44 -0
- data/test/impl/logging/services.rb +84 -0
- data/test/impl/startup/package.yml +46 -0
- data/test/impl/startup/services.rb +47 -0
- data/test/impl/symbols/package.yml +24 -0
- data/test/impl/symbols/services.rb +38 -0
- data/test/impl/tc_builder-factory.rb +173 -0
- data/test/impl/tc_logging-interceptor.rb +148 -0
- data/test/impl/tc_startup.rb +59 -0
- data/test/impl/tc_symbol-sources.rb +61 -0
- data/test/logger.yml +6 -0
- data/test/mock.rb +201 -0
- data/test/schema/bad-package.yml +65 -0
- data/test/schema/package.yml +102 -0
- data/test/schema/services.rb +5 -0
- data/test/services/package.yml +79 -0
- data/test/services/simple.rb +87 -0
- data/test/tc_class-factory.rb +93 -0
- data/test/tc_complex-instantiator.rb +107 -0
- data/test/tc_configuration-point-contrib.rb +74 -0
- data/test/tc_configuration-point-schema.rb +122 -0
- data/test/tc_configuration-point.rb +91 -0
- data/test/tc_default-schema-processor.rb +297 -0
- data/test/tc_identity-instantiator.rb +61 -0
- data/test/tc_interceptors.rb +84 -0
- data/test/tc_logger.rb +131 -0
- data/test/tc_models.rb +176 -0
- data/test/tc_package.rb +165 -0
- data/test/tc_proxy.rb +65 -0
- data/test/tc_registry.rb +141 -0
- data/test/tc_schema.rb +78 -0
- data/test/tc_service-point.rb +178 -0
- data/test/tc_service.rb +70 -0
- data/test/tc_simple-instantiator.rb +61 -0
- data/test/tests.rb +93 -0
- data/tutorial/01/main.rb +7 -0
- data/tutorial/01/package.yml +8 -0
- data/tutorial/01/tutorial.rb +7 -0
- data/tutorial/02/main.rb +10 -0
- data/tutorial/02/package.yml +27 -0
- data/tutorial/02/tutorial.rb +46 -0
- data/tutorial/03/main.rb +24 -0
- data/tutorial/03/package.yml +29 -0
- data/tutorial/03/tutorial.rb +48 -0
- data/tutorial/04/main.rb +24 -0
- data/tutorial/04/package.yml +35 -0
- data/tutorial/04/tutorial.rb +48 -0
- data/tutorial/05/functions/package.yml +16 -0
- data/tutorial/05/functions/services.rb +15 -0
- data/tutorial/05/main.rb +10 -0
- data/tutorial/05/package.yml +35 -0
- data/tutorial/05/tutorial.rb +53 -0
- metadata +260 -0
@@ -0,0 +1,446 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Copland Manual :: Tutorial 4: Logging Interceptor</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—</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 “service factory”, 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 “service model”, and shows the difference between “singleton” and “prototype”.</p>
|
255
|
+
</li>
|
256
|
+
|
257
|
+
<li><strong>
|
258
|
+
<a href="tutorial-4.html">
|
259
|
+
Logging Interceptor
|
260
|
+
</a>
|
261
|
+
</strong> <big>←</big><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 #4. Logging Interceptor</h1>
|
295
|
+
|
296
|
+
<p>The sources for this tutorial may be found in the <tt>tutorial/04</tt>
|
297
|
+
directory of the Copland distribution.</p>
|
298
|
+
|
299
|
+
|
300
|
+
|
301
|
+
<h2>Introduction</h2>
|
302
|
+
|
303
|
+
<p>Sometimes (particularly when debugging) you want to be able to trace your program’s execution. You want to see when certain methods are being invoked, and with what parameters, and what the return values are. If an exception is being raised, you’d like to see that, too.</p>
|
304
|
+
|
305
|
+
<p>Although the calculator example we’ve been using up to this point is trivial enough that there’s really no need for such tracing, it is an easy one to demonstrate it on. So, let’s take the code we wrote for the last tutorial and add logging, just for the halibut.</p>
|
306
|
+
|
307
|
+
<p>What we’ll do is modify the program so that it logs everytime a method of the Calculator or Adder services is invoked from outside the service.</p>
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
<h2>Steps</h2>
|
312
|
+
|
313
|
+
<ol>
|
314
|
+
|
315
|
+
|
316
|
+
<li><h3>copland.LoggingInterceptor</h3>
|
317
|
+
|
318
|
+
<p><em>Interceptors</em> are another kind of service, similar to factory services, that Copland uses to <em>intercept</em> method calls. An instance of the interceptor service sits (conceptually) between the caller and the method, and acts as a filter for everything going into or out of the method.</p>
|
319
|
+
|
320
|
+
<p>There is currently only one interceptor that ships with Copland—copland.LoggingInterceptor. It sits between the caller and the method and happily logs away, noting the parameters, return values, and exceptions that are raised.</p></li>
|
321
|
+
|
322
|
+
|
323
|
+
|
324
|
+
<li><h3>Adding the Interceptor</h3>
|
325
|
+
|
326
|
+
<p>Here we get to demonstrate one of (in my opinion) the “coolest” aspects of Copland. We can add the logging solely by editing our package descriptor—<em>nothing else needs to change!</em> Our Ruby objects remain blissfully ignorant that the logging has been added. Slick, huh?</p>
|
327
|
+
|
328
|
+
<p>So, let’s open our package descriptor and add the interceptor to the Adder service first:</p>
|
329
|
+
|
330
|
+
<pre>
|
331
|
+
Adder:
|
332
|
+
implementor: tutorial/Adder
|
333
|
+
interceptors:
|
334
|
+
- service: copland.LoggingInterceptor
|
335
|
+
</pre>
|
336
|
+
|
337
|
+
<p>The <code>interceptors</code> element is always a list of interceptors that should be added to the service. (By default, the interceptors will be invoked in the order they were added. You can change this, but it’s a bit beyond the scope of this tutorial.) Each element of the list <em>must</em> be a hash, each with the <em>service</em> element (at least) defined. That element must name a valid interceptor service. In this case, the interceptor service is copland.LoggingInterceptor.</p>
|
338
|
+
|
339
|
+
<p>Now, let’s add the logging interceptor to the Calculator service:</p>
|
340
|
+
|
341
|
+
<pre>
|
342
|
+
Calculator:
|
343
|
+
interceptors:
|
344
|
+
- service: copland.LoggingInterceptor
|
345
|
+
...
|
346
|
+
</pre>
|
347
|
+
|
348
|
+
<p>Note that it is not important <em>where</em> the <code>interceptors</code> element appears in the service point—just as long as it appears at the “top level” of the service point definition.</p></li>
|
349
|
+
|
350
|
+
|
351
|
+
|
352
|
+
<li><h3>Running the Program</h3>
|
353
|
+
|
354
|
+
<p>So, we’ve got the interceptors in place now. Let’s try running the program and seeing what happens!</p>
|
355
|
+
|
356
|
+
<p>You should see the exact same output from the last tutorial—the list of multiples and powers. However, there should be a file named “copland.log” in the same directory. This file has been appearing every time you’ve run your programs during these tutorials, but it has been largely empty because nothing has been logged. This time, however, there will be quite a bit of text in the log, looking something like this:</p>
|
357
|
+
|
358
|
+
<pre>
|
359
|
+
# Logfile created on Sat Sep 04 09:29:58 MDT 2004 by logger.rb/1.5.2.4
|
360
|
+
D, [2004-09-04T09:29:58.963327 #23288] DEBUG -- tutorial.Calculator: memory( )
|
361
|
+
D, [2004-09-04T09:29:58.963471 #23288] DEBUG -- tutorial.Calculator: memory => 0
|
362
|
+
D, [2004-09-04T09:29:58.963522 #23288] DEBUG -- tutorial.Calculator: memory( )
|
363
|
+
D, [2004-09-04T09:29:58.963564 #23288] DEBUG -- tutorial.Calculator: memory => 0
|
364
|
+
D, [2004-09-04T09:29:58.963651 #23288] DEBUG -- tutorial.Calculator: add( 5 )
|
365
|
+
D, [2004-09-04T09:29:58.999262 #23288] DEBUG -- tutorial.Adder: add( 5, 0 )
|
366
|
+
D, [2004-09-04T09:29:58.999486 #23288] DEBUG -- tutorial.Adder: add => 5.0
|
367
|
+
D, [2004-09-04T09:29:58.999547 #23288] DEBUG -- tutorial.Calculator: add => 5.0
|
368
|
+
D, [2004-09-04T09:29:58.999617 #23288] DEBUG -- tutorial.Calculator: memory=( 5.0 )
|
369
|
+
D, [2004-09-04T09:29:58.999663 #23288] DEBUG -- tutorial.Calculator: memory= => 5.0
|
370
|
+
...
|
371
|
+
</pre>
|
372
|
+
|
373
|
+
<p>Let’s analyze the output a bit. First, it’s saying that the <code>#memory</code> method was invoked, with no parameters, and that it returned 0. Then, it was invoked again, and returned 0 again. (This is because we’ve got two calculators going at once, both of them logging their method invocations.) Next, <code>#add</code> was invoked, with a parameter of 5. Then, the Adder’s <code>#add</code> is invoked, with two parameters (5, and 0). That method then returns a value of 5.0, followed by the Calculator’s <code>#add</code> method returning 5.0. Then, the <code>#memory=</code> method is invoked, with a value of 5.0, which it also returns.</p>
|
374
|
+
|
375
|
+
<p>That’s a bit more verbose than we intended—for example, we didn’t really care to see all the <code>memory</code> method invocations. We’d like to be able to <em>exclude</em> those methods from the logger.</p></li>
|
376
|
+
|
377
|
+
|
378
|
+
|
379
|
+
<li><h3>Excluding Methods</h3>
|
380
|
+
|
381
|
+
<p>The LoggingInterceptor supports (among others) two parameters, <code>exclude</code> and <code>include</code>. Each of these elements is an array of special regular expressions that should match method names.</p>
|
382
|
+
|
383
|
+
<p>By default, all methods are included. If you specify a set of <code>exclude</code> patterns, any method that matches any one of those patterns will be excluded from consideration. If you further specify a set of <code>include</code> patterns, then any method that has been excluded from consideration, and which matches any one of the <code>include</code> patterns, will be reincluded for consideration.</p>
|
384
|
+
|
385
|
+
<p>So, let’s exclude the <code>#memory</code> and <code>#memory=</code> methods from the Calculator’s logging interceptor. We can do it by name each method explicitly, like this:</p>
|
386
|
+
|
387
|
+
<pre>
|
388
|
+
Calculator:
|
389
|
+
interceptors:
|
390
|
+
- service: copland.LoggingInterceptor
|
391
|
+
exclude:
|
392
|
+
- memory
|
393
|
+
- memory=
|
394
|
+
...
|
395
|
+
</pre>
|
396
|
+
|
397
|
+
Or, we can be a little more concise and use regular expressions:
|
398
|
+
<pre>
|
399
|
+
Calculator:
|
400
|
+
interceptors:
|
401
|
+
- service: copland.LoggingInterceptor
|
402
|
+
exclude:
|
403
|
+
- memory=?
|
404
|
+
...
|
405
|
+
</pre>
|
406
|
+
|
407
|
+
<p>Delete the original copland.log (otherwise subsequent runs will just append to it) and then rerun your script. None of the <code>memory</code> methods are being logged! Much better.</p></li>
|
408
|
+
|
409
|
+
|
410
|
+
</ol>
|
411
|
+
|
412
|
+
|
413
|
+
|
414
|
+
<h2>Summary</h2>
|
415
|
+
|
416
|
+
<p>In this tutorial you learned how to apply a logging interceptor to a service. You also learned how to exclude certain methods from being logged.</p>
|
417
|
+
|
418
|
+
<p>Note that you can easily specify that only certain methods should be logged (instead of the reverse, where only certain methods should <em>not</em> be logged). To do this, first exclude all methods (with a ”.*” regular expression), and then explicitly include the methods you want to log.</p>
|
419
|
+
|
420
|
+
<p>Also, it should be noted that the regular expressions for the include and exclude patterns are special: you can also specify the <em>arity</em> of the methods that should be included or excluded. For example, if you want to exclude all methods that are invoked with 3 parameters, you could do:</p>
|
421
|
+
|
422
|
+
<pre>
|
423
|
+
exclude:
|
424
|
+
- .*(3)
|
425
|
+
</pre>
|
426
|
+
|
427
|
+
<p>If you prefix the arity number with a comparison operator (less-than or greater-than), you can exclude (or include) methods that are invoked with less than or greater than that number of parameters:</p>
|
428
|
+
|
429
|
+
<pre>
|
430
|
+
exclude:
|
431
|
+
- .*(>3)
|
432
|
+
include:
|
433
|
+
- .*(5)
|
434
|
+
</pre>
|
435
|
+
|
436
|
+
<p>The above would exclude any method invoked with more than three parameters, unless it was invoked with exactly five parameters.</p>
|
437
|
+
|
438
|
+
|
439
|
+
|
440
|
+
|
441
|
+
</div>
|
442
|
+
|
443
|
+
</td></tr>
|
444
|
+
</table>
|
445
|
+
</body>
|
446
|
+
</html>
|
@@ -0,0 +1,520 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Copland Manual :: Tutorial 5: Configuration Points</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—</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 “service factory”, 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 “service model”, and shows the difference between “singleton” and “prototype”.</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><strong>
|
266
|
+
<a href="tutorial-5.html">
|
267
|
+
Configuration Points
|
268
|
+
</a>
|
269
|
+
</strong> <big>←</big><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 #5. Configuration Points</h1>
|
295
|
+
|
296
|
+
<p>The sources for this tutorial may be found in the <tt>tutorial/05</tt>
|
297
|
+
directory of the Copland distribution.</p>
|
298
|
+
|
299
|
+
|
300
|
+
|
301
|
+
<h2>Introduction</h2>
|
302
|
+
|
303
|
+
<p>Suppose, next, we want to add the ability to register new functions with the calculator, so that third parties that wish to reuse our snappy little number cruncher can add their own custom operations.</p>
|
304
|
+
|
305
|
+
<p>Think for a minute how you would solve this. There are several approaches that could be taken, none of them necessarily any better or worse than the other. The drawback for each of them is that <em>you would have to implement the infrastructure yourself</em>.</p>
|
306
|
+
|
307
|
+
<p>Copland provides a ready-made package-centric configuration infrastructure, which (as you will see) allows any package to contribute configuration data to configuration points in any other package.</p>
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
<h2>Steps</h2>
|
312
|
+
|
313
|
+
<ol>
|
314
|
+
|
315
|
+
|
316
|
+
<li><h3>Modify Calculator</h3>
|
317
|
+
|
318
|
+
<p>First, let’s modify our Calculator class again. We’ll add <em>another</em> writer attribute, called <code>functions</code>, which we’ll assume will always be a Hash (or Hash-like) object. Each pair in the hash will be a named object that implements the <code>:compute</code> message.</p>
|
319
|
+
|
320
|
+
<pre>
|
321
|
+
class Calculator
|
322
|
+
attr_writer :adder
|
323
|
+
attr_writer :subtractor
|
324
|
+
...
|
325
|
+
attr_writer :functions
|
326
|
+
</pre>
|
327
|
+
|
328
|
+
<p>Then, we’ll implement a new method on Calculator, called <code>function</code>, which allows clients to specify a function to execute and the arguments to give it. We won’t bother with error checking:</p>
|
329
|
+
|
330
|
+
<pre>
|
331
|
+
def function( name, *arguments )
|
332
|
+
@functions[ name ].compute( *arguments )
|
333
|
+
end
|
334
|
+
</pre></li>
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
<li><h3>Create a Configuration Point</h3>
|
339
|
+
|
340
|
+
<p>Next, we’ll create a configuration point. A configuration point may be either a <em>list</em>, or a <em>map</em>. We want a map, so that it will work nicely as a lookup for function services.</p>
|
341
|
+
|
342
|
+
<p>Configuration points are defined in their own section of the package descriptor, under the <code>configuration-points</code> key. Thus:</p>
|
343
|
+
|
344
|
+
<pre>
|
345
|
+
id: tutorial
|
346
|
+
|
347
|
+
service-points:
|
348
|
+
...
|
349
|
+
|
350
|
+
configuration-points:
|
351
|
+
|
352
|
+
CalculatorFunctions:
|
353
|
+
type: map
|
354
|
+
</pre>
|
355
|
+
|
356
|
+
<p>This creates a new (and empty) configuration point, called CalculatorFunctions. It is of type “map”, which means it quacks like a Hash. Since it belongs to the tutorial package, its fully qualified name is “tutorial.CalculatorFunctions”.</p>
|
357
|
+
|
358
|
+
<p>For now, we’ll leave it empty. We’ll contribute values to it in a little bit.</p></li>
|
359
|
+
|
360
|
+
|
361
|
+
|
362
|
+
<li><h3>Edit the Calculator Service Point</h3>
|
363
|
+
|
364
|
+
<p>Now, we edit the service point that defines our Calculator service. Specifically, we add another property initializer:</p>
|
365
|
+
|
366
|
+
<pre>
|
367
|
+
Calculator:
|
368
|
+
model: prototype
|
369
|
+
implementor:
|
370
|
+
factory: copland.BuilderFactory
|
371
|
+
class: tutorial/Calculator
|
372
|
+
properties:
|
373
|
+
adder: !!service Adder
|
374
|
+
...
|
375
|
+
functions: !!configuration CalculatorFunctions
|
376
|
+
</pre>
|
377
|
+
|
378
|
+
<p>Here, we’re telling Copland to associate the CalculatorFunctions configuration point with the <code>functions</code> property of our Calculator.</p>
|
379
|
+
|
380
|
+
<p>This means that anything any package adds to that configuration point is going to be visible to our Calculator, via its <code>functions</code> property. The only part we’re missing, then, is what goes into that configuration point.</p></li>
|
381
|
+
|
382
|
+
|
383
|
+
|
384
|
+
<li><h3>Prepare to Create the <code>tutorial.functions</code> Package</h3>
|
385
|
+
|
386
|
+
<p>Just to keep things nice and neat, we’ll create another package in which we’ll define our “custom” calculator functions.</p>
|
387
|
+
|
388
|
+
<p>Create a new subdirectory in the same directory as your calculator implementation. Call it <code>functions</code>. Then change to that directory.</p>
|
389
|
+
|
390
|
+
<pre>
|
391
|
+
$ mkdir functions
|
392
|
+
$ cd functions
|
393
|
+
</pre></li>
|
394
|
+
|
395
|
+
|
396
|
+
|
397
|
+
<li><h3>Implement Some Functions</h3>
|
398
|
+
|
399
|
+
<p>We need to decide which custom functions to implement. I’ll arbitrarily recommend the trigonometric “sin” function, and the natural logarithm, mostly because they’re fun to say, but also because they’re two of many available functions that Ruby already provides us implementations for.</p>
|
400
|
+
|
401
|
+
<p>So, let’s create a “services.rb” file in our new “functions” subdirectory. We’ll implement two classes, one for each new function. Each class only has to respond to the “compute” message, accepting the expected parameters and returning the computed result. Thus:</p>
|
402
|
+
|
403
|
+
<pre>
|
404
|
+
class Sine
|
405
|
+
|
406
|
+
def compute( a )
|
407
|
+
Math.sin( a )
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|
411
|
+
|
412
|
+
class NaturalLogarithm
|
413
|
+
|
414
|
+
def compute( n )
|
415
|
+
Math.log( n )
|
416
|
+
end
|
417
|
+
|
418
|
+
end
|
419
|
+
</pre></li>
|
420
|
+
|
421
|
+
|
422
|
+
|
423
|
+
<li><h3>Define the Service Points</h3>
|
424
|
+
|
425
|
+
<p>Now, we create the package descriptor for our new package. Create a new file called “package.yml” in the “functions” subdirectory:</p>
|
426
|
+
|
427
|
+
<pre>
|
428
|
+
---
|
429
|
+
id: tutorial.functions
|
430
|
+
|
431
|
+
service-points:
|
432
|
+
|
433
|
+
Sine:
|
434
|
+
implementor: functions/services/Sine
|
435
|
+
|
436
|
+
NaturalLogarithm:
|
437
|
+
implementor: functions/services/NaturalLogarithm
|
438
|
+
</pre>
|
439
|
+
|
440
|
+
<p>Note the name of the package: <code>tutorial.functions</code>. This is the recommended way of naming your packages, with names of subpackages including the names of their ancestor packages. However, you are in no way constrained to name them this way—Copland does not enforce it.</p></li>
|
441
|
+
|
442
|
+
|
443
|
+
|
444
|
+
<li><h3>Contribute the Services to the Configuration Point</h3>
|
445
|
+
|
446
|
+
<p>Next, we tie it all together. Our <code>tutorial.functions</code> package needs to contribute the two services it defines to the <code>tutorial.CalculatorFunctions</code> configuration point. This way, when the Calculator service is instantiated, it will come ready-made with a map of all functions that other packages want to be made available.</p>
|
447
|
+
|
448
|
+
<p>Contributes are made in the <code>contributions</code> section of the package descriptor. Just specify the name of the configuration point to contribute to, and then the values you want to contribute. For configuration points of type list, the values should be formatted as a list. For maps, the values should be formatted as a map.</p>
|
449
|
+
|
450
|
+
<pre>
|
451
|
+
id: tutorial.functions
|
452
|
+
|
453
|
+
service-points:
|
454
|
+
...
|
455
|
+
|
456
|
+
contributions:
|
457
|
+
|
458
|
+
tutorial.CalculatorFunctions:
|
459
|
+
sin: !!service Sine
|
460
|
+
ln: !!service NaturalLogarithm
|
461
|
+
</pre>
|
462
|
+
|
463
|
+
<p>Here we’ve registered the Sine service under the name “sin”, and the NaturalLogarithm service under the name “ln”.</p></li>
|
464
|
+
|
465
|
+
|
466
|
+
|
467
|
+
<li><h3>Put it Together</h3>
|
468
|
+
|
469
|
+
<p>Now, in our “main.rb” driver file, we just need to call our new <code>function</code> interface and see if it really works:</p>
|
470
|
+
|
471
|
+
<pre>
|
472
|
+
require 'copland'
|
473
|
+
|
474
|
+
registry = Copland::Registry.build
|
475
|
+
|
476
|
+
calc = registry.service( "tutorial.Calculator" )
|
477
|
+
|
478
|
+
puts "sin(pi/4) = #{calc.function( "sin", Math::PI/4 )}"
|
479
|
+
puts "ln(e^3) = #{calc.function( "ln", Math::E ** 3 )}"
|
480
|
+
|
481
|
+
registry.shutdown
|
482
|
+
</pre>
|
483
|
+
|
484
|
+
<p>If all was done correctly, you should see the following output:</p>
|
485
|
+
|
486
|
+
<pre>
|
487
|
+
$ ruby main.rb
|
488
|
+
sin(pi/4) = 0.707106781186547
|
489
|
+
ln(e^3) = 3.0
|
490
|
+
</pre></li>
|
491
|
+
|
492
|
+
|
493
|
+
</ol>
|
494
|
+
|
495
|
+
|
496
|
+
|
497
|
+
<h2>Summary</h2>
|
498
|
+
|
499
|
+
<p>The following techniques were demonstrated in this tutorial:</p>
|
500
|
+
|
501
|
+
<ol>
|
502
|
+
<li>Applications with multiple Copland packages</li>
|
503
|
+
<li>Creating a configuration point</li>
|
504
|
+
<li>Contributing to a configuration point</li>
|
505
|
+
<li>Associating a configuration point with a property of a service</li>
|
506
|
+
</ol>
|
507
|
+
|
508
|
+
<p>Additionally, you saw that subdirectories would (by default) be recursively searched for package descriptors.</p>
|
509
|
+
|
510
|
+
<p>Play with this tutorial some more. Try adding some more functions. Try adding some more packages that contribute to the <code>tutorial.CalculatorFunctions</code> configuration point. The more you use these features, the better you’ll understand them.</p>
|
511
|
+
|
512
|
+
|
513
|
+
|
514
|
+
|
515
|
+
</div>
|
516
|
+
|
517
|
+
</td></tr>
|
518
|
+
</table>
|
519
|
+
</body>
|
520
|
+
</html>
|