copland 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/doc/manual-html/chapter-1.html +227 -36
  2. data/doc/manual-html/chapter-10.html +155 -82
  3. data/doc/manual-html/chapter-11.html +90 -267
  4. data/doc/manual-html/chapter-12.html +289 -71
  5. data/doc/manual-html/chapter-13.html +430 -0
  6. data/doc/manual-html/chapter-2.html +45 -21
  7. data/doc/manual-html/chapter-3.html +45 -21
  8. data/doc/manual-html/chapter-4.html +45 -21
  9. data/doc/manual-html/chapter-5.html +45 -21
  10. data/doc/manual-html/chapter-6.html +49 -21
  11. data/doc/manual-html/chapter-7.html +45 -21
  12. data/doc/manual-html/chapter-8.html +66 -26
  13. data/doc/manual-html/chapter-9.html +48 -24
  14. data/doc/manual-html/index.html +54 -22
  15. data/doc/manual-html/manual.css +12 -0
  16. data/doc/manual-html/tutorial-1.html +45 -21
  17. data/doc/manual-html/tutorial-2.html +45 -21
  18. data/doc/manual-html/tutorial-3.html +45 -21
  19. data/doc/manual-html/tutorial-4.html +45 -21
  20. data/doc/manual-html/tutorial-5.html +45 -21
  21. data/doc/manual/manual.css +12 -0
  22. data/doc/manual/manual.rb +1 -1
  23. data/doc/manual/manual.yml +426 -20
  24. data/doc/packages/copland.html +41 -9
  25. data/doc/packages/copland.lib.html +36 -8
  26. data/doc/packages/copland.remote.html +46 -10
  27. data/doc/packages/copland.webrick.html +16 -65
  28. data/doc/packages/index.html +1 -1
  29. data/doc/presentation/copland.mgp +1083 -0
  30. data/doc/presentation/to_html.rb +52 -0
  31. data/lib/copland/configuration-point/common.rb +32 -1
  32. data/lib/copland/configuration/yaml/service-point.rb +10 -1
  33. data/lib/copland/log-factory.rb +28 -12
  34. data/lib/copland/logger.rb +155 -0
  35. data/lib/copland/models/singleton.rb +8 -2
  36. data/lib/copland/package.rb +32 -14
  37. data/lib/copland/service-point.rb +7 -0
  38. data/lib/copland/thread.rb +104 -0
  39. data/lib/copland/utils.rb +10 -3
  40. data/lib/copland/version.rb +2 -2
  41. data/test/configuration/yaml/tc_service-point-processor.rb +8 -0
  42. data/test/custom-logger.yml +2 -1
  43. data/test/impl/tc_logging-interceptor.rb +12 -12
  44. data/test/logger.yml +1 -1
  45. data/test/mock.rb +2 -0
  46. data/test/tc_logger.rb +19 -6
  47. data/test/tc_package.rb +25 -0
  48. data/test/tc_queryable-mutex.rb +75 -0
  49. data/test/tc_registry.rb +8 -4
  50. metadata +9 -2
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
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>
17
+ Copland Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-10-12 02:22 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -39,13 +39,21 @@
39
39
 
40
40
  <li><a href="chapter-1.html#s1">What is Copland?</a></li>
41
41
 
42
- <li><a href="chapter-1.html#s2">Features</a></li>
42
+ <li><a href="chapter-1.html#s2">What Can Copland Do For Me?</a></li>
43
43
 
44
- <li><a href="chapter-1.html#s3">Getting Copland</a></li>
44
+ <li><a href="chapter-1.html#s3">Copland <em>sans</em> Buzzwords</a></li>
45
45
 
46
- <li><a href="chapter-1.html#s4">License Information</a></li>
46
+ <li><a href="chapter-1.html#s4">Copland <em>avec</em> Buzzwords</a></li>
47
47
 
48
- <li><a href="chapter-1.html#s5">Support</a></li>
48
+ <li><a href="chapter-1.html#s5">The Buzzwords Themselves</a></li>
49
+
50
+ <li><a href="chapter-1.html#s6">Features</a></li>
51
+
52
+ <li><a href="chapter-1.html#s7">Getting Copland</a></li>
53
+
54
+ <li><a href="chapter-1.html#s8">License Information</a></li>
55
+
56
+ <li><a href="chapter-1.html#s9">Support</a></li>
49
57
 
50
58
  </ol>
51
59
  </li>
@@ -149,7 +157,9 @@
149
157
 
150
158
  <li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
151
159
 
152
- <li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
160
+ <li><a href="chapter-8.html#s2">FactoryDefaults</a></li>
161
+
162
+ <li><a href="chapter-8.html#s3">ApplicationDefaults</a></li>
153
163
 
154
164
  </ol>
155
165
  </li>
@@ -166,54 +176,68 @@
166
176
 
167
177
  <li>
168
178
  <a href="chapter-10.html">
179
+ Logging
180
+ </a>
181
+
182
+ <ol type="1">
183
+
184
+ <li><a href="chapter-10.html#s1">Log Factory</a></li>
185
+
186
+ <li><a href="chapter-10.html#s2">Configuration</a></li>
187
+
188
+ </ol>
189
+ </li>
190
+
191
+ <li>
192
+ <a href="chapter-11.html">
169
193
  Service Factories
170
194
  </a>
171
195
 
172
196
  <ol type="1">
173
197
 
174
- <li><a href="chapter-10.html#s1">Schemas</a></li>
198
+ <li><a href="chapter-11.html#s1">Schemas</a></li>
175
199
 
176
- <li><a href="chapter-10.html#s2">How do they work?</a></li>
200
+ <li><a href="chapter-11.html#s2">How do they work?</a></li>
177
201
 
178
- <li><a href="chapter-10.html#s3">BuilderFactory</a></li>
202
+ <li><a href="chapter-11.html#s3">BuilderFactory</a></li>
179
203
 
180
204
  </ol>
181
205
  </li>
182
206
 
183
207
  <li>
184
- <a href="chapter-11.html">
208
+ <a href="chapter-12.html">
185
209
  Schemas
186
210
  </a>
187
211
 
188
212
  <ol type="1">
189
213
 
190
- <li><a href="chapter-11.html#s1">Basic Format</a></li>
214
+ <li><a href="chapter-12.html#s1">Basic Format</a></li>
191
215
 
192
- <li><a href="chapter-11.html#s2">Subschemas</a></li>
216
+ <li><a href="chapter-12.html#s2">Subschemas</a></li>
193
217
 
194
- <li><a href="chapter-11.html#s3">Arrays</a></li>
218
+ <li><a href="chapter-12.html#s3">Arrays</a></li>
195
219
 
196
- <li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
220
+ <li><a href="chapter-12.html#s4">Named vs. Anonymous Schemas</a></li>
197
221
 
198
- <li><a href="chapter-11.html#s5">Extending Schemas</a></li>
222
+ <li><a href="chapter-12.html#s5">Extending Schemas</a></li>
199
223
 
200
- <li><a href="chapter-11.html#s6">Limitations</a></li>
224
+ <li><a href="chapter-12.html#s6">Limitations</a></li>
201
225
 
202
226
  </ol>
203
227
  </li>
204
228
 
205
229
  <li>
206
- <a href="chapter-12.html">
230
+ <a href="chapter-13.html">
207
231
  Listeners and Event Producers
208
232
  </a>
209
233
 
210
234
  <ol type="1">
211
235
 
212
- <li><a href="chapter-12.html#s1">Event Producers</a></li>
236
+ <li><a href="chapter-13.html#s1">Event Producers</a></li>
213
237
 
214
- <li><a href="chapter-12.html#s2">Listeners</a></li>
238
+ <li><a href="chapter-13.html#s2">Listeners</a></li>
215
239
 
216
- <li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
240
+ <li><a href="chapter-13.html#s3">The Registry as an Event Producer</a></li>
217
241
 
218
242
  </ol>
219
243
  </li>
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
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>
17
+ Copland Version: <strong>1.0.0</strong><br />
18
+ Manual Last Updated: <strong>2004-10-12 02:22 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -39,13 +39,21 @@
39
39
 
40
40
  <li><a href="chapter-1.html#s1">What is Copland?</a></li>
41
41
 
42
- <li><a href="chapter-1.html#s2">Features</a></li>
42
+ <li><a href="chapter-1.html#s2">What Can Copland Do For Me?</a></li>
43
43
 
44
- <li><a href="chapter-1.html#s3">Getting Copland</a></li>
44
+ <li><a href="chapter-1.html#s3">Copland <em>sans</em> Buzzwords</a></li>
45
45
 
46
- <li><a href="chapter-1.html#s4">License Information</a></li>
46
+ <li><a href="chapter-1.html#s4">Copland <em>avec</em> Buzzwords</a></li>
47
47
 
48
- <li><a href="chapter-1.html#s5">Support</a></li>
48
+ <li><a href="chapter-1.html#s5">The Buzzwords Themselves</a></li>
49
+
50
+ <li><a href="chapter-1.html#s6">Features</a></li>
51
+
52
+ <li><a href="chapter-1.html#s7">Getting Copland</a></li>
53
+
54
+ <li><a href="chapter-1.html#s8">License Information</a></li>
55
+
56
+ <li><a href="chapter-1.html#s9">Support</a></li>
49
57
 
50
58
  </ol>
51
59
  </li>
@@ -149,7 +157,9 @@
149
157
 
150
158
  <li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
151
159
 
152
- <li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
160
+ <li><a href="chapter-8.html#s2">FactoryDefaults</a></li>
161
+
162
+ <li><a href="chapter-8.html#s3">ApplicationDefaults</a></li>
153
163
 
154
164
  </ol>
155
165
  </li>
@@ -166,54 +176,68 @@
166
176
 
167
177
  <li>
168
178
  <a href="chapter-10.html">
179
+ Logging
180
+ </a>
181
+
182
+ <ol type="1">
183
+
184
+ <li><a href="chapter-10.html#s1">Log Factory</a></li>
185
+
186
+ <li><a href="chapter-10.html#s2">Configuration</a></li>
187
+
188
+ </ol>
189
+ </li>
190
+
191
+ <li>
192
+ <a href="chapter-11.html">
169
193
  Service Factories
170
194
  </a>
171
195
 
172
196
  <ol type="1">
173
197
 
174
- <li><a href="chapter-10.html#s1">Schemas</a></li>
198
+ <li><a href="chapter-11.html#s1">Schemas</a></li>
175
199
 
176
- <li><a href="chapter-10.html#s2">How do they work?</a></li>
200
+ <li><a href="chapter-11.html#s2">How do they work?</a></li>
177
201
 
178
- <li><a href="chapter-10.html#s3">BuilderFactory</a></li>
202
+ <li><a href="chapter-11.html#s3">BuilderFactory</a></li>
179
203
 
180
204
  </ol>
181
205
  </li>
182
206
 
183
207
  <li>
184
- <a href="chapter-11.html">
208
+ <a href="chapter-12.html">
185
209
  Schemas
186
210
  </a>
187
211
 
188
212
  <ol type="1">
189
213
 
190
- <li><a href="chapter-11.html#s1">Basic Format</a></li>
214
+ <li><a href="chapter-12.html#s1">Basic Format</a></li>
191
215
 
192
- <li><a href="chapter-11.html#s2">Subschemas</a></li>
216
+ <li><a href="chapter-12.html#s2">Subschemas</a></li>
193
217
 
194
- <li><a href="chapter-11.html#s3">Arrays</a></li>
218
+ <li><a href="chapter-12.html#s3">Arrays</a></li>
195
219
 
196
- <li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
220
+ <li><a href="chapter-12.html#s4">Named vs. Anonymous Schemas</a></li>
197
221
 
198
- <li><a href="chapter-11.html#s5">Extending Schemas</a></li>
222
+ <li><a href="chapter-12.html#s5">Extending Schemas</a></li>
199
223
 
200
- <li><a href="chapter-11.html#s6">Limitations</a></li>
224
+ <li><a href="chapter-12.html#s6">Limitations</a></li>
201
225
 
202
226
  </ol>
203
227
  </li>
204
228
 
205
229
  <li>
206
- <a href="chapter-12.html">
230
+ <a href="chapter-13.html">
207
231
  Listeners and Event Producers
208
232
  </a>
209
233
 
210
234
  <ol type="1">
211
235
 
212
- <li><a href="chapter-12.html#s1">Event Producers</a></li>
236
+ <li><a href="chapter-13.html#s1">Event Producers</a></li>
213
237
 
214
- <li><a href="chapter-12.html#s2">Listeners</a></li>
238
+ <li><a href="chapter-13.html#s2">Listeners</a></li>
215
239
 
216
- <li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
240
+ <li><a href="chapter-13.html#s3">The Registry as an Event Producer</a></li>
217
241
 
218
242
  </ol>
219
243
  </li>
@@ -148,6 +148,18 @@ a:hover {
148
148
  margin-bottom: 1em;
149
149
  }
150
150
 
151
+ #content h4 {
152
+ background: #FFE;
153
+ color: #000;
154
+ font-size: normal;
155
+ font-weight: bold;
156
+ font-variant: small-caps;
157
+ padding: 0.25em;
158
+ padding-left: 0.5em;
159
+ border: 1px dotted #777;
160
+ margin-bottom: 1em;
161
+ }
162
+
151
163
  #navigation h1 {
152
164
  margin: 0px;
153
165
  padding: 1em;
@@ -101,7 +101,7 @@ module Copland
101
101
 
102
102
  def initialize( index, title, content )
103
103
  @index = index
104
- @title = title
104
+ @title = RedCloth.new( title ).to_html.gsub( %r{</?p>}, "" ) if title
105
105
  @content = RedCloth.new( content )
106
106
  end
107
107
  end
@@ -19,22 +19,248 @@ product: !^product
19
19
  project: http://rubyforge.org/projects/copland
20
20
 
21
21
  recent_updates:
22
- - described the "initializer block" feature of Registry#service.
22
+ - documented the new "visibility" attribute of service points
23
+ - added chapter about Logging configuration
24
+ - fixed misinformation about symbol sources
25
+ - added discussion about FactoryDefaults vs. ApplicationDefaults
26
+ - added (HiveMind-inspired) section in Introduction describing concrete benefits of Copland
23
27
 
24
28
  chapters:
25
29
 
26
30
  - Introduction:
27
31
  - What is Copland?: >
28
32
  Copland is an _Inversion of Control_ (IoC) container, written in
29
- "Ruby":http://www.ruby-lang.org, for use in Ruby programs.
30
- Depending on whether or not the term "IoC" means anything at all to you,
31
- you can read either the next section ("Copland _sans_ Buzzwords"), or the
32
- one after it ("Copland _avec_ Buzzwords").
33
+ "Ruby":http://www.ruby-lang.org, for use in Ruby programs. In a nutshell,
34
+ it allows you to simplify the instantiation and initialization of your
35
+ classes.
33
36
 
34
37
 
35
- h3. Copland _sans_ Buzzwords
38
+ - What Can Copland Do For Me?: >
39
+ So, what can Copland do for you? Ultimately, it can reduce the amount of code
40
+ that you have to write, simplifying many common programming tasks for you. This
41
+ has the two-fold benefit of both decreasing application development time, and of
42
+ decreasing the effort needed to maintain your application.
36
43
 
37
44
 
45
+ But what, _specifically_, can Copland do for you?
46
+
47
+
48
+ Try these on for size:
49
+
50
+
51
+ * "Log Method Execution":#logmethods
52
+
53
+ * "Reference Another Service":#refsvc
54
+
55
+ * "Service Configuration":#svcconfig
56
+
57
+ * "Unit Testing":#unittest
58
+
59
+ * "Lifecycle Management":#lifecycle
60
+
61
+
62
+ (Thanks to Howard Lewis Ship for his "HiveMind":http://jakarta.apache.org/hivemind
63
+ documentation, from which most of the above bullet points were adapted.)
64
+
65
+
66
+ h3. A. Log Method Execution
67
+ <a name="logmethods"></a>
68
+
69
+
70
+ Copland has an integrated logging framework, and the ability to log
71
+ execution trace information _without modifying a single line of your code_. This
72
+ means that you can easily see what methods get called, with what arguments,
73
+ and what the return values are, all without having to add a single line of
74
+ logging code to your classes.
75
+
76
+
77
+ Consider the following code, demonstrating how this would be done _without_
78
+ Copland:
79
+
80
+
81
+ <pre>
82
+ def foo( arg1, arg2 )
83
+ @log.debug( "in foo with #{arg1} and #{arg2}" ) if @log.debug?
84
+ ...
85
+ result = the_result_of_the_method
86
+ @log.debug( "finishing foo with #{result}" ) if @log.debug
87
+ return result
88
+ rescue Exception => e
89
+ @log.debug( "foo raised exception #{e.message} (#{e.class})" ) if @log.debug?
90
+ raise
91
+ end
92
+ </pre>
93
+
94
+
95
+ Now, multiply that by the number of methods in your class... the logging messages
96
+ quickly overpower the rest of the code, and detract from the flow of your program.
97
+ This makes your program harder to debug, test, and maintain.
98
+
99
+
100
+ Now, consider the same method using Copland's integrated logging framework...
101
+
102
+
103
+ <pre>
104
+ def foo( arg1, arg2 )
105
+ ...
106
+ return the_result_of_the_method
107
+ end
108
+ </pre>
109
+
110
+
111
+ Uh, huh. That's right. _There's no explicit logging code in there._ Instead, you just
112
+ tell Copland that the methods of the class should be logged, and away it goes. This has
113
+ the added benefit of allowing your objects to be unit tested, without spewing log
114
+ messages everywhere. (Look for the tutorial about "Logging Interceptors" for an actual
115
+ demonstration of how to do this.)
116
+
117
+
118
+ h3. B. Reference Another Service
119
+ <a name="refsvc"></a>
120
+
121
+
122
+ Invariably in a large application services will reference other services. This is
123
+ typically accomplished through something like this:
124
+
125
+
126
+ <pre>
127
+ def foo( parms )
128
+ @service ||= lookup_service
129
+ @service.do_something( parms )
130
+ end
131
+ </pre>
132
+
133
+
134
+ Whether the lookup is done lazily, as shown above, or when the class is first
135
+ instantiated is irrelevant. The point is that you either have to implement a bunch
136
+ of code to look up a service based on some criteria, or you hard code the class of
137
+ the service (which creates tight coupling and makes things like unit testing harder).
138
+
139
+
140
+ With Copland, you just declare a setter for the service, and then tell Copland that
141
+ the class depends on the other service:
142
+
143
+
144
+ <pre>
145
+ attr_writer :service
146
+
147
+ def foo( parms )
148
+ @service.do_something( parms )
149
+ end
150
+ </pre>
151
+
152
+
153
+ Then, when your service is instantiated, Copland will automatically look for,
154
+ instantiate, and set the dependencies for you. This makes for cleaner code, and
155
+ looser coupling between services.
156
+
157
+
158
+ h3. C. Service Configuration
159
+ <a name="svcconfig"></a>
160
+
161
+
162
+ Often, a large application or library will need some way to allow different classes
163
+ to be configured at runtime. Whether you have a factory class that requires the
164
+ available producable classes to register themselves with it, or whether you just want
165
+ to allow third-parties to be able to extend your application, you wind up implementing
166
+ some form of decentralized configuration.
167
+
168
+
169
+ Copland allows you to define _configuration points_, which any package may then
170
+ contribute values to. Furthermore, just as services can reference other services,
171
+ services can reference configuration points, and Copland will manage them just like
172
+ any other dependency.
173
+
174
+
175
+ See the tutorial about "Configuration Points" for an example of this feature.
176
+
177
+
178
+ h3. D. Unit Testing
179
+ <a name="unittest"></a>
180
+
181
+
182
+ Large applications can prove troublesome to unit test exhaustively, especially if there
183
+ is any kind of tight coupling between components. Such coupling of components can make
184
+ it difficult to test them separately.
185
+
186
+
187
+ Copland, by its very nature, encourages loose coupling of components. Also, because
188
+ dependencies are never instantiated in code, but are instead accepted via setters or
189
+ constructor arguments, it is trivial to replace those dependencies with mock objects
190
+ at unit test time.
191
+
192
+
193
+ Consider this tightly coupled example:
194
+
195
+
196
+ <pre>
197
+ def foo( args )
198
+ @some_dependency ||= MyNewDependency.new
199
+ @some_dependency.do_something(args)
200
+ end
201
+ </pre>
202
+
203
+
204
+ It is impossible to test the method @#foo@ without also testing the MyNewDependency
205
+ class. However, if the @@some_dependency@ object is made a property that is set
206
+ externally, you can replace it at test time with a blank:
207
+
208
+
209
+ <pre>
210
+ attr_writer :some_dependency
211
+
212
+ def foo( args )
213
+ @some_dependency.do_something( args )
214
+ end
215
+ </pre>
216
+
217
+
218
+ The unit test would become something like this:
219
+
220
+
221
+ <pre>
222
+ def test_foo
223
+ @obj.some_dependecy = MyMockDependency.new
224
+ @obj.foo( args )
225
+ assert @obj.is_in_some_state
226
+ end
227
+ </pre>
228
+
229
+
230
+ h3. E. Lifecycle Management
231
+ <a name="lifecycle"></a>
232
+
233
+
234
+ Singleton objects are a fact of life in complex systems. The singleton design pattern
235
+ is powerful and useful. However, using the Singleton mixin, or declaring methods at the
236
+ class level, can make your code difficult to unit test since the state of such objects
237
+ cannot be easily reset.
238
+
239
+
240
+ Copland has a solution. You can tell Copland to treat a service as either a _prototype_
241
+ service (meaning it will be instantiated every time you ask for it, like calling @#new@),
242
+ or a _singleton_ service (meaning it will only be instantiated once, and the same instance
243
+ will be returned for subsequent requests).
244
+
245
+
246
+ Your object is still just a plain ol' ordinary Ruby object, but Copland has effectively
247
+ transformed it into a singleton. This means you can unit test it as if it were nothing
248
+ special, but when it is used in your application it will act like a singleton.
249
+
250
+
251
+ Lifecycle management also means that you can control _when_ a service is instantiated.
252
+ The _prototype_ and _singleton_ models will always be instantiated as soon as they are
253
+ requested. Sometimes, though, you don't want that--you'd like the instantiation to be
254
+ deferred as long as possible.
255
+
256
+
257
+ With Copland, you can indicate that a service should use deferred instantiation. This will
258
+ cause the service to not actually be instantiated until a method is actually invoked on it.
259
+ Using this model, you can have services depend on themselves, or other forms of cyclical
260
+ dependencies.
261
+
262
+
263
+ - Copland _sans_ Buzzwords: >
38
264
  Imagine being able to take all the various pieces of your program and implement
39
265
  them in a vacuum. You just assume that all dependencies will be satisfied at runtime,
40
266
  by properties being set, or parameters being passed to each object's constructor.
@@ -71,9 +297,7 @@ chapters:
71
297
  specify those relationships and dependencies as run-time configuration options.
72
298
 
73
299
 
74
- h3. Copland _avec_ Buzzwords
75
-
76
-
300
+ - Copland _avec_ Buzzwords: >
77
301
  If you are already familiar with IoC, then you either love it or hate it. In the first
78
302
  case, you probably only want to know what features Copland has compared to other IoC
79
303
  containers you've used. In the second case, there's probably not much I can say to
@@ -97,9 +321,7 @@ chapters:
97
321
  you've never used YAML, you'll find it surprisingly easy to pick up.
98
322
 
99
323
 
100
- h3. The Buzzwords Themselves
101
-
102
-
324
+ - The Buzzwords Themselves: >
103
325
  As "Martin Fowler":http://www.martinfowler.com
104
326
  "points out":http://martinfowler.com/articles/injection.html, the term "Inversion of Control"
105
327
  is a poorly-chosen one. Still, it is the one that most people know the concept by, so I'll
@@ -823,6 +1045,11 @@ chapters:
823
1045
  here, to be notified when some service-specific event is triggered. See the chapter on
824
1046
  "Listeners and Event Producers" for more information.|
825
1047
 
1048
+ |^. @visibility@|This must be either the value "public" or "private". It defaults to "public".
1049
+ If it is "private", then the service point is not visible outside of its containing package.
1050
+ it is often the case that a particular package will have a few public services that are
1051
+ facades for multiple private services. See the @copland.webrick@ package for an example.|
1052
+
826
1053
 
827
1054
  Of these attributes, only @implementor@ is required.
828
1055
 
@@ -1027,8 +1254,8 @@ chapters:
1027
1254
 
1028
1255
  Of these attributes, only @type@ is required.
1029
1256
 
1030
- - DefaultSymbolSource: >
1031
- One of the core pre-defined configuration points is the map @copland.DefaultSymbolSource@.
1257
+ - FactoryDefaults: >
1258
+ One of the core pre-defined configuration points is the map @copland.FactoryDefaults@.
1032
1259
  Although you will rarely access this configuration point directly, it is integrated
1033
1260
  tightly with Copland. Any value you add to it becomes available as a _substitution
1034
1261
  symbol_.
@@ -1038,13 +1265,13 @@ chapters:
1038
1265
  utilities like "ant":http://ant.apache.org and "maven":http://maven.apache.org make
1039
1266
  heavy use of them. What they are, is this: any time Copland encounters a value that
1040
1267
  contains a certain pattern, it replaces that pattern with the value of the same name
1041
- from the DefaultSymbolSource. The pattern is a dollar sign, followed by curly braces
1268
+ from the FactoryDefaults. The pattern is a dollar sign, followed by curly braces
1042
1269
  that contain the name of the symbol.
1043
1270
 
1044
1271
 
1045
1272
  For example, suppose you want to allow the application to configure which class gets
1046
1273
  used when a particular service point is instantiated. You can do this by pulling the
1047
- name of the class from the DefaultSymbolSource as a substitution symbol:
1274
+ name of the class from the FactoryDefaults as a substitution symbol:
1048
1275
 
1049
1276
 
1050
1277
  <pre>
@@ -1054,9 +1281,21 @@ chapters:
1054
1281
 
1055
1282
 
1056
1283
  Then, the application would contribute a value named @the.class.to.use@ to
1057
- @copland.DefaultSymbolSource@, and when @SomeServicePoint@ is instantiated, it would
1284
+ @copland.FactoryDefaults@, and when @SomeServicePoint@ is instantiated, it would
1058
1285
  use the value thus provided.
1059
1286
 
1287
+ - ApplicationDefaults: >
1288
+ The @copland.ApplicationDefaults@ configuration point works together with the
1289
+ @FactoryDefaults@ configuration point to provide a flexible way to override
1290
+ default values of substitution symbols.
1291
+
1292
+
1293
+ When a substitution symbol is requested, the @ApplicationDefaults@ configuration
1294
+ point is searched first. If the requested symbol is not found there, the
1295
+ @FactoryDefaults@ configuration point is searched. This allows package developers
1296
+ to define default values (in @FactoryDefaults@), and allow clients of the packages
1297
+ to override those defaults as needed (in @ApplicationDefaults@).
1298
+
1060
1299
  - Contributions:
1061
1300
  - >
1062
1301
  _Contributions_ are the means by which packages may add values to configuration points.
@@ -1070,20 +1309,187 @@ chapters:
1070
1309
  you want to contribute.
1071
1310
 
1072
1311
 
1073
- For example, to contribute a value to the DefaultSymbolSource configuration point:
1312
+ For example, to contribute a value to the ApplicationDefaults configuration point:
1074
1313
 
1075
1314
 
1076
1315
  <pre>
1077
1316
  contributions:
1078
1317
 
1079
- copland.DefaultSymbolSource:
1318
+ copland.ApplicationDefaults:
1080
1319
  user.name: fritz
1081
1320
  </pre>
1082
1321
 
1083
1322
 
1084
- That little snippet just added a value called @user.name@ to the @copland.DefaultSymbolSource@
1323
+ That little snippet just added a value called @user.name@ to the @copland.ApplicationDefaults@
1085
1324
  configuration point!
1086
1325
 
1326
+ - Logging:
1327
+ - >
1328
+ Copland has an integrated logging system based on a slight variation of Ruby's own
1329
+ "logger" library. In addition to the features of that library, Copland's logging system
1330
+ provides:
1331
+
1332
+
1333
+ * A logger factory for creating shared logger instances
1334
+
1335
+ * YAML-based configuration of the factory
1336
+
1337
+ * Customizable message formatting
1338
+
1339
+ - Log Factory: >
1340
+ Each registry instance has its own instance of @Copland::LogFactory@. This provides
1341
+ a way to map a name to a logger instance, and allows each service point (for example)
1342
+ to have its own logger instance. This allows various logger settings to be tweaked
1343
+ _per service-point_.
1344
+
1345
+
1346
+ For example, if I want debugging information to be logged for one service point, but
1347
+ not for another, I can specify the logging priority level for the one service point to
1348
+ include debug messages, and have such messages excluded for the other service point.
1349
+
1350
+
1351
+ The log factory allows default values to be set for the priority level, date format
1352
+ string, and message format string, which will be applied to any logger that does not
1353
+ have a specific value set for those values. The log factory also allows configuration
1354
+ of the IO device to log to, the filename to log to, and various other (Logger-specific)
1355
+ data items (see the API documentation for @Copland::LogFactory@ for more information).
1356
+
1357
+
1358
+ If you ever need to access the current log factory instance, you can get it from the
1359
+ registry as the @copland.LogFactory@ service.
1360
+
1361
+ - Configuration: >
1362
+ There are three ways to configure loggers. The first is programmatically, manually
1363
+ tweaking each log instance directly. The second is to pass configuration options to
1364
+ the registry itself when it is built, and the third is to use a configuration file.
1365
+
1366
+
1367
+ h3. Programmatic Configuration
1368
+
1369
+
1370
+ To programmatically configure a logger, just obtain a handle to a logger instance
1371
+ and then tweak it via the accessor methods of the logger:
1372
+
1373
+
1374
+ <pre>
1375
+ factory = registry.service( "copland.LogFactory" )
1376
+ log = factory.get( "some.log.name" )
1377
+
1378
+ # Standard Logger attributes
1379
+ log.level = Logger::INFO
1380
+ log.progname = "different.log.name"
1381
+ log.datetime_format = "%Y%m%d"
1382
+
1383
+ # Extended Logger attributes (provided by Copland)
1384
+ log.message_format = "[%-5p] %d %c: %m"
1385
+ </pre>
1386
+
1387
+
1388
+ _Note:_ programmatically changing the logger @progname@ does not change the name by
1389
+ which the logger is known to the factory!
1390
+
1391
+
1392
+ In general, programmatic tweaking of the logger attributes as demonstrated above is not
1393
+ going to be the best way to do it. First of all, it is tedious, and bug prone. Secondly,
1394
+ it is difficult to know where the best place to do such work is, since you need to set
1395
+ those attributes before any other service tries to access that log.
1396
+
1397
+
1398
+ h3. Configuration via @Registry.build@
1399
+
1400
+
1401
+ The second approach is to pass logger configuration options to @Registry.build@,
1402
+ when you create a registry instance:
1403
+
1404
+
1405
+ <pre>
1406
+ registry = Copland::Registry.build(
1407
+ :log_device => STDOUT,
1408
+ :log_default_level => Logger::INFO,
1409
+ ...
1410
+ )
1411
+ </pre>
1412
+
1413
+
1414
+ This gives you much greater flexibility than the previous approach, since it allows
1415
+ you to specify a greater array of options. The allowed options are:
1416
+
1417
+
1418
+ table(list).
1419
+
1420
+ |^. @:log_config_file@|This is the name of the configuration file to use to
1421
+ configure the log factory. It defaults to "logger.yml". (See the next section for
1422
+ more information.)|
1423
+
1424
+ |^. @:log_device@|This is the IO (or pseudo-IO) object to write log messages to.
1425
+ If this option is specified, @:log_filename@ must not be specified (and vice versa).
1426
+ This allows you to log messages to arbitrary IO streams.|
1427
+
1428
+ |^. @:log_filename@|This is the name of the file to write log messages to. If this
1429
+ option is specified, @:log_device@ must not be specified (and vice versa). This
1430
+ defaults to "./copland.log".|
1431
+
1432
+ |^. @:log_roll_age@|This specifies the number of days before the log should be
1433
+ rolled. (This option is only useful when used with @:log_filename@.)|
1434
+
1435
+ |^. @:log_roll_frequency@|This should be either @nil@, "daily", "weekly", or
1436
+ "monthly", and specifies how frequently the log should be rolled. This option cannot
1437
+ be used with @:log_roll_age@.|
1438
+
1439
+ |^. @:log_roll_size@|This specifies the maximum size of a log file. Once the log
1440
+ file gets larger than this value, the log will be rolled. (This option is only useful
1441
+ when used with @:log_filename@.)|
1442
+
1443
+ |^. @:log_default_date_format@|This is the default date format string to use for the
1444
+ loggers that are created. It may be any string that is understood by @Time#strftime@.
1445
+ If @nil@ (the default), then the default Logger date format string will be used.|
1446
+
1447
+ |^. @:log_default_message_format@|This is the default message format string to use
1448
+ for the loggers that are created. It is a printf-styled string with special format
1449
+ specifiers--see the API documentation for @Copland::Logger#message_format=@ for the
1450
+ available specifiers.|
1451
+
1452
+ |^. @:log_default_level@|This is the default level for each logger. Messages that
1453
+ are logged below this level (also "priority" or "severity") will not be logged. By
1454
+ default, all messages are logged.|
1455
+
1456
+ |^. @:log_levels@|This is a hash. Each key should be a string containing a regular
1457
+ expression. For every logger whose name matches one of these patterns, the corresponding
1458
+ value will be used to define specific values for that logger. The value for each key
1459
+ must either be a string (in which case it is the name of the severity level to use), or
1460
+ a hash (containing any of the keys "level", "date-format", or "message-format").|
1461
+
1462
+
1463
+ h3. Configuration via YAML
1464
+
1465
+
1466
+ The third option (and the most flexible) is to use a YAML configuration file to
1467
+ define the parameters of the log factory and its loggers. By default, this file
1468
+ is called "logger.yml", but you can specify a different logger configuration file
1469
+ via the @:log_config_file@ option to @Copland::Registry.build@. By default, the
1470
+ configuration file must reside in current working directory, but you can specify
1471
+ an explicit path in the string you give to @:log_config_file@.
1472
+
1473
+
1474
+ The file has options that correspond to the configuration parameters described above:
1475
+
1476
+
1477
+ <pre>
1478
+ ---
1479
+ filename: log/filename.log
1480
+ roll-age: 5
1481
+ default-date-format: %Y%m%d%H%M%S
1482
+ default-message-format: %p %d %t %C: %m (%l)
1483
+ default-level: DEBUG
1484
+ levels:
1485
+ copland.*: WARN
1486
+ project.*:
1487
+ level: INFO
1488
+ date-format: %Y%m%d::%H%M%S
1489
+ message-format: %p %d: %m
1490
+ </pre>
1491
+
1492
+
1087
1493
  - Service Factories:
1088
1494
  - >
1089
1495
  Sometimes it requires a little more effort (or a lot more effort) to instantiate and