copland 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,1083 @@
1
+ %%========================================================================
2
+ %deffont "standard" xfont "Sans"
3
+ %deffont "standard-italic" xfont "Sans:Oblique"
4
+ %deffont "standard-bold" xfont "Sans:Bold"
5
+ %deffont "code" xfont "Courier"
6
+ %deffont "code-bold" xfont "Courier:Bold"
7
+ %%========================================================================
8
+ %page
9
+ %%========================================================================
10
+ %% h1. How Dynamic Can You Get?
11
+ %%
12
+ %% Ruby: already very dynamic.
13
+ %% This presentation will show that DI (IoC) compliments and enhances
14
+ %% that attribute of Ruby.
15
+ %%========================================================================
16
+ %back "white"
17
+
18
+
19
+ %center, fore "#F00", font "standard", hgap 60, size 6.5
20
+ Dependency Injection in Ruby
21
+ %bar "#F77" 4 20 60
22
+ %size 4, font "standard-italic", fore "#F60"
23
+ How Dynamic Can You Get?
24
+
25
+
26
+
27
+ %size 2.5, font "standard", fore "#600"
28
+ 2004 International Ruby Conference
29
+ %size 2, fore "black", font "standard-bold"
30
+ C h a n t i l l y , V i r g i n i a , U S A
31
+
32
+
33
+
34
+
35
+
36
+ %size 2, font "standard", fore "#600"
37
+ Jamis Buck (jgb3@email.byu.edu)
38
+ %fore "#006", font "standard-bold"
39
+ Brigham Young University
40
+
41
+ %page
42
+ %%========================================================================
43
+ %% h1. What is "Dependency Injection"?
44
+ %%
45
+ %% # The mirror of garbage collection, according to HLS. GC is concerned
46
+ %% with reclaiming memory from dead objects at the end of their
47
+ %% lifecycle; DI/IoC is concerned with instantiating and initializing
48
+ %% new objects at the beginning of their lifecycle.
49
+ %% # Abdicates responsibility for instantiating dependencies. Instead of
50
+ %% an object being responsible for instantiating its own dependencies,
51
+ %% each object assumes that someone else will carry that responsibility,
52
+ %% "injecting" those dependencies into the object at the time of its
53
+ %% creation.
54
+ %%
55
+ %% h1. What about "Inversion of Control"
56
+ %%
57
+ %% # "Inverts" control over some aspect of the object by relegating that
58
+ %% control to some other object.
59
+ %% # There are lots of opinions about whether "Inversion of Control" is
60
+ %% the "correct" term for what containers like Copland do. Martin Fowler
61
+ %% believes the term is too generic, while others claim that IoC
62
+ %% containers do more than just DI.
63
+ %% # DI is a form of IoC--control over dependencies is just one kind of
64
+ %% control that may be inverted. Other kinds of control include
65
+ %% configuration, logging, concurrency, authorization, etc.
66
+ %%
67
+ %% h1. is it for me?
68
+ %%
69
+ %% # Maybe. DI does introduce some overhead, so for small tasks, or
70
+ %% those that rely on milking every last ounce of performance from the
71
+ %% Ruby interpreter, DI is probably not appropriate.
72
+ %% # For larger, complex applications, DI can improve maintainability.
73
+ %%========================================================================
74
+ %fore "black", center, prefix 0, area 100 100 0 0
75
+
76
+
77
+
78
+ %rcutin, size 5, font "standard", fore "#00F"
79
+ What is "Dependency Injection"?
80
+ %size 4
81
+
82
+ %pause, rcutin, fore "black"
83
+ Mirror of garbage collection
84
+ %pause, rcutin
85
+ Abdicates responsibility for instantiating dependencies
86
+ %pause, rcutin
87
+ Loose coupling of components
88
+
89
+ %pause, rcutin, size 5, font "standard", fore "#00F"
90
+ What about "Inversion of Control"?
91
+ %size 4
92
+
93
+ %pause, rcutin, fore "black"
94
+ Depends on who you ask
95
+ %size 2
96
+
97
+ %pause, size 4, rcutin, fore "black"
98
+ %font "code"
99
+ assert DI.kind_of?( IoC )
100
+ %font "standard"
101
+ Control over dependencies is "inverted"
102
+
103
+ %pause, rcutin, size 8, fore "#F00", font "standard-bold"
104
+ Is it for me?
105
+ %size 3
106
+
107
+ %size 4, pause, lcutin, font "standard-italic", fore "black"
108
+ Maybe...
109
+
110
+ %page
111
+ %%========================================================================
112
+ %% h1. How can it help me?
113
+ %%
114
+ %% 1. Log Method Execution
115
+ %% 2. Reference Other Services
116
+ %% 3. Service Configuration
117
+ %% 4. Unit Testing
118
+ %% 5. Lifecycle Management
119
+ %%========================================================================
120
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
121
+
122
+
123
+
124
+
125
+ %size 6
126
+ How can it help me
127
+
128
+
129
+ %size 8, fore "#F00", font "standard-bold"
130
+ Right now?
131
+
132
+ %page
133
+ %%========================================================================
134
+ %% h1. How can it help me?
135
+ %%
136
+ %% 1. Log Method Execution
137
+ %%========================================================================
138
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
139
+
140
+ Log Method Execution
141
+ %bar "#F77" 4 10 80, size 3, fore "#F00", font "standard-italic"
142
+
143
+ sans
144
+ %cont, font "standard"
145
+ Copland
146
+
147
+ %font "code", prefix 15, left, size 2.5, fore "black"
148
+ def foo( arg1, arg2 )
149
+ @log.debug( "in foo with #{arg1} and #{arg2}" ) if @log.debug?
150
+ ...
151
+ result = the_result_of_the_method
152
+ @log.debug( "finishing foo with #{result}" ) if @log.debug
153
+ return result
154
+ rescue Exception => e
155
+ @log.debug( "exception #{e.message} (#{e.class})" ) if @log.debug?
156
+ raise
157
+ end
158
+
159
+ %pause, center, prefix 0, size 3, fore "#F00", font "standard"
160
+ With Copland
161
+
162
+ %font "code", prefix 15, left, size 2.5, fore "black"
163
+ def foo( arg1, arg2 )
164
+ ...
165
+ the_result_of_the_method
166
+ end
167
+
168
+ %size 2, fore "#F00", font "standard-italic"
169
+ (+2 lines of YAML)
170
+
171
+ %page
172
+ %%========================================================================
173
+ %% h1. How can it help me?
174
+ %%
175
+ %% 2. Reference another service
176
+ %%========================================================================
177
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
178
+
179
+ Reference Other Services
180
+ %bar "#F77" 4 10 80, size 3, fore "#F00", font "standard-italic"
181
+
182
+ sans
183
+ %cont, font "standard"
184
+ Copland
185
+
186
+ %font "code", prefix 15, left, fore "black"
187
+ def foo( parms )
188
+ @service ||= lookup_service
189
+ @service.do_something( parms )
190
+ end
191
+
192
+ %pause, center, prefix 0, size 3, fore "#F00", font "standard"
193
+
194
+ With Copland
195
+
196
+ %font "code", prefix 15, left, fore "black"
197
+ attr_writer :service
198
+
199
+ def foo( parms )
200
+ @service.do_something( parms )
201
+ end
202
+
203
+ %size 2, fore "#F00", font "standard-italic"
204
+ (+2 lines of YAML)
205
+
206
+ %page
207
+ %%========================================================================
208
+ %% h1. How can it help me?
209
+ %%
210
+ %% 3. Service Configuration
211
+ %%========================================================================
212
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
213
+
214
+ Service Configuration
215
+ %bar "#F77" 4 10 80, size 4, prefix 10, left
216
+
217
+ %pause, rcutin
218
+ Packages define configuration points
219
+
220
+ %pause, rcutin
221
+ Packages contribute to configuration points
222
+
223
+ %pause, rcutin
224
+ Decentralized configuration
225
+
226
+ %pause, rcutin
227
+ Services specify dependencies on configuration points
228
+
229
+ %page
230
+ %%========================================================================
231
+ %% h1. How can it help me?
232
+ %%
233
+ %% 4. Unit Testing
234
+ %%========================================================================
235
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
236
+
237
+ Unit Testing
238
+ %bar "#F77" 4 10 80, size 3, fore "#F00", font "standard-italic"
239
+
240
+ sans
241
+ %cont, font "standard"
242
+ Copland
243
+
244
+ %area 50 50 0 30
245
+ %font "code", prefix 15, left, fore "black", size 5
246
+ def foo( parms )
247
+ @dependency ||= MyDependency.new
248
+ @dependency.do_something( parms )
249
+ end
250
+
251
+ %area 50 50 50 30
252
+ %pause, left, prefix 15, font "standard", fore "#F00"
253
+ Tightly coupled
254
+ Hard to test independently
255
+
256
+ %area 100 50 0 50
257
+ %pause, center, prefix 0, size 6, fore "#F00", font "standard"
258
+ With Copland
259
+
260
+ %area 50 50 0 60
261
+ %font "code", prefix 15, left, fore "black", size 5
262
+ attr_writer :dependency
263
+
264
+ def foo( parms )
265
+ @dependency.do_something( parms )
266
+ end
267
+
268
+ %pause, area 50 50 45 60
269
+ def test_foo
270
+ @obj.dependency = MyMockDependency.new
271
+ @obj.foo( parms )
272
+ assert @obj.in_some_state?
273
+ end
274
+
275
+ %area 100 100 0 80
276
+ %pause, center, prefix 0, font "standard", fore "#F00", size 3
277
+ Mock dependencies are easily injected
278
+
279
+ %page
280
+ %%========================================================================
281
+ %% h1. How can it help me?
282
+ %%
283
+ %% 5. Lifecycle Management
284
+ %%========================================================================
285
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
286
+
287
+ Lifecycle Management
288
+ %bar "#F77" 4 10 80, size 4, left
289
+
290
+
291
+ %fore "#00F", prefix 30
292
+ * Service model
293
+ %fore "black", font "standard-italic", prefix 35
294
+ - Prototype
295
+ - Singleton
296
+ - Threaded
297
+
298
+
299
+ %fore "#00F", font "standard", prefix 30
300
+ * Instantiation
301
+ %fore "black", font "standard-italic", prefix 35
302
+ - immediate
303
+ - deferred
304
+
305
+ %page
306
+ %%========================================================================
307
+ %% h1. How can it help me, in general?
308
+ %%
309
+ %% # configurable (provides a configuration framework)
310
+ %% # reusable (encourages loose-coupling of components)
311
+ %% # extensible (easy to swap components in or out)
312
+ %% # debuggable (logging framework, including interceptors)
313
+ %% # testable (small, independent components)
314
+ %%========================================================================
315
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
316
+
317
+ %size 4
318
+ In general, then...
319
+ %lcutin, size 6, fore "#00F"
320
+ How can DI/IoC help me?
321
+ %size 4
322
+
323
+ %pause, rcutin, fore "#F00", size 5
324
+ "CREDT"
325
+ %size 4
326
+
327
+
328
+ %pause, lcutin, fore "red", font "standard-bold"
329
+ C
330
+ %cont, fore "black", font "standard"
331
+ onfigurable
332
+
333
+ %pause, rcutin, fore "red", font "standard-bold"
334
+ R
335
+ %cont, fore "black", font "standard"
336
+ eusable
337
+
338
+ %pause, lcutin, fore "red", font "standard-bold"
339
+ E
340
+ %cont, fore "black", font "standard"
341
+ xtensible
342
+
343
+ %pause, rcutin, fore "red", font "standard-bold"
344
+ D
345
+ %cont, fore "black", font "standard"
346
+ ebuggable
347
+
348
+ %pause, lcutin, fore "red", font "standard-bold"
349
+ T
350
+ %cont, fore "black", font "standard"
351
+ estable
352
+
353
+ %page
354
+ %%========================================================================
355
+ %% h1. Calculator Example
356
+ %%
357
+ %% Given: a trivial calculator
358
+ %%
359
+ %% * can't easily replace an operation with a "mock" operation
360
+ %% * third parties cannot easily add new operations
361
+ %%========================================================================
362
+ %fore "black", center, size 6, font "standard", prefix 0
363
+
364
+ Consider a Calculator...
365
+ %bar "#F77" 4 10 80
366
+ %size 3
367
+
368
+ %font "code", prefix 30, left
369
+ class Calculator
370
+ def add( a, b )
371
+ a.to_f + b.to_f
372
+ end
373
+
374
+ def subtract( a, b )
375
+ a.to_f - b.to_f
376
+ end
377
+
378
+ def multiply( a, b )
379
+ a.to_f * b.to_f
380
+ end
381
+
382
+ def divide( a, b )
383
+ a.to_f / b.to_f
384
+ end
385
+ end
386
+
387
+ %pause, font "standard-italic", size 3, prefix 0, center
388
+ %bar "#F77" 4 10 80
389
+ What are some drawbacks of this approach?
390
+
391
+ %page
392
+ %%========================================================================
393
+ %% h1. Calculator Example: Refactored
394
+ %%
395
+ %% Break the operations into their own classes. This allows each operation
396
+ %% to be unit tested individually.
397
+ %%========================================================================
398
+ %fore "black", center
399
+
400
+
401
+ %size 6, font "standard", prefix 0
402
+ Refactor the operations
403
+ into their own classes
404
+ %bar "#F77" 4 10 80
405
+ %size 3
406
+ (calc.rb)
407
+
408
+ %area 50 50 0 30
409
+ %font "code", size 6, prefix 20, left
410
+ class Adder
411
+ def compute( a, b )
412
+ a.to_f + b.to_f
413
+ end
414
+ end
415
+
416
+ class Subtracter
417
+ def compute( a, b )
418
+ a.to_f - b.to_f
419
+ end
420
+ end
421
+
422
+ %area 50 50 50 30
423
+ class Multiplier
424
+ def compute( a, b )
425
+ a.to_f * b.to_f
426
+ end
427
+ end
428
+
429
+ class Divider
430
+ def compute( a, b )
431
+ a.to_f / b.to_f
432
+ end
433
+ end
434
+
435
+ %page
436
+ %%========================================================================
437
+ %% h1. Calculator as Container
438
+ %%
439
+ %% The calculator becomes a container for holding all known operations.
440
+ %%========================================================================
441
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
442
+
443
+ Calculator as Container
444
+ %bar "#F77" 4 10 80
445
+ %size 3
446
+ (calc.rb, continued)
447
+
448
+ %font "code", size 3, prefix 15, left
449
+ class Calculator
450
+ attr_writer :adder
451
+ attr_writer :subtractor
452
+ attr_writer :multiplier
453
+ attr_writer :divider
454
+
455
+ def add( a, b ); @adder.compute( a, b ); end
456
+ def subtract( a, b ); @subtractor.compute( a, b ); end
457
+ def multiply( a, b ); @multiplier.compute( a, b ); end
458
+ def divide( a, b ); @divider.compute( a, b ); end
459
+ end
460
+
461
+ %pause, font "standard", prefix 0, center
462
+ %bar "#F77" 4 10 80
463
+ Notice: no explicit dependencies!
464
+
465
+ %page
466
+ %%========================================================================
467
+ %% h1. Manual Dependency Injection
468
+ %%
469
+ %% Manual dependency injection. Manually instantiate all of the
470
+ %% operations, manually instantiate the calculator, etc, etc.
471
+ %%========================================================================
472
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
473
+
474
+ %size 6, font "standard", prefix 0
475
+ Manual Dependency Injection
476
+ %bar "#F77" 4 10 80
477
+ %size 3
478
+ (main.rb)
479
+
480
+
481
+ %font "code", size 3, prefix 30, left
482
+ require 'calc'
483
+
484
+ \# instantiate the Calculator
485
+ calc = Calculator.new
486
+
487
+ \# inject the dependencies
488
+ calc.adder = Adder.new
489
+ calc.subtracter = Subtracter.new
490
+ calc.multiplier = Multiplier.new
491
+ calc.divider = Divider.new
492
+
493
+ \# Voil�!
494
+ p calc.add( 8, 5 )
495
+ p calc.subtract( 8, 5 )
496
+ p calc.multiply( 8, 5 )
497
+ p calc.divide( 8, 5 )
498
+
499
+ %page
500
+ %%========================================================================
501
+ %% h1. Enter Copland
502
+ %%
503
+ %% Copland removes the drudgery from dependency injection, automating it
504
+ %% based on the dependencies you specify in a _package descriptor_.
505
+ %% The dependencies in this case are trivial services, and are easily
506
+ %% defined.
507
+ %%========================================================================
508
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
509
+
510
+ Enter
511
+ %cont, fore "#F00", font "standard-bold"
512
+ Copland
513
+ %bar "#F77" 4 10 80
514
+ %fore "black", font "standard", size 4
515
+
516
+ %pause, lcutin
517
+ First, create a
518
+ %cont, font "standard-italic"
519
+ package descriptor
520
+ %cont, font "standard"
521
+ :
522
+ %size 3
523
+ (package.yml)
524
+
525
+ %pause, font "code", size 3, prefix 30, left
526
+ ---
527
+ id: calc
528
+
529
+ service-points:
530
+
531
+ Adder:
532
+ implementor: calc/Adder
533
+ Subtractor:
534
+ implementor: calc/Subtractor
535
+ Multiplier:
536
+ implementor: calc/Multiplier
537
+ Divider:
538
+ implementor: calc/Divider
539
+
540
+
541
+ %size 4, font "standard-italic", prefix 0, center, fore "#F00"
542
+ %bar "#F77" 4 10 80
543
+ continued -->
544
+
545
+ %page
546
+ %%========================================================================
547
+ %% h1. Package Descriptor (continued)
548
+ %%
549
+ %% The calculator service is more complicated, since it needs to declare
550
+ %% the other services that it is dependent upon.
551
+ %%========================================================================
552
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
553
+
554
+ The Calculator Service Point
555
+ %bar "#F77" 4 10 80
556
+ %size 3
557
+ (package.yml, continued)
558
+
559
+ %font "code", size 3, prefix 20, left
560
+ Calculator:
561
+ implementor:
562
+ factory: copland.BuilderFactory
563
+ class: calc/Calculator
564
+ properties:
565
+ adder: !!service calc.Adder
566
+ subtracter: !!service calc.Subtracter
567
+ multiplier: !!service calc.Multiplier
568
+ divider: !!service calc.Divider
569
+
570
+ %page
571
+ %%========================================================================
572
+ %% h1. Driver File
573
+ %%
574
+ %% Here we instantiate a registry, get a reference to the service, and
575
+ %% use it!
576
+ %%========================================================================
577
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
578
+
579
+ Putting it All Together
580
+ %bar "#F77" 4 10 80
581
+ %size 3
582
+ (main.rb)
583
+
584
+ %font "code", size 3, prefix 20, left
585
+ require 'copland'
586
+
587
+ registry = Copland::Registry.build
588
+
589
+ calc = registry.service( "calc.Calculator" )
590
+
591
+ p calc.add( 8, 5 )
592
+ p calc.subtract( 8, 5 )
593
+ p calc.multiply( 8, 5 )
594
+ p calc.divide( 8, 5 )
595
+
596
+
597
+ %pause, font "standard-italic", size 3, center, prefix 0
598
+ %bar "#F77" 4 10 80
599
+ Good, but can we make it better?
600
+ Can we make it so that third-parties can add new functions?
601
+
602
+ %page
603
+ %%========================================================================
604
+ %% h1. Refining
605
+ %%========================================================================
606
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
607
+
608
+ Refining the Calculator
609
+ %bar "#F77" 4 10 80
610
+ %size 3
611
+ (calc.rb)
612
+ %size 2
613
+
614
+ %font "code", size 3, prefix 20, left
615
+ class Calculator
616
+ # +operations+ must quack like a Hash
617
+ def initialize( operations )
618
+ @operations = operations
619
+ end
620
+
621
+ def method_missing( op, *args )
622
+ if @operations.has_key?( op )
623
+ return @operations[ op ].compute( *args )
624
+ else
625
+ super
626
+ end
627
+ end
628
+
629
+ def respond_to?( op )
630
+ super || @operations.has_key?( op )
631
+ end
632
+ end
633
+
634
+ %page
635
+ %%========================================================================
636
+ %% h1. Refining (continued)
637
+ %%
638
+ %% Since we now expect the operations to be specified to the constructor
639
+ %% via a hash (or hash-like), we need to change how the Calculator service
640
+ %% point is defined.
641
+ %%
642
+ %% First, we'll create a configuration point for holding the new
643
+ %% operations, and then we'll contribute the "default" operations to that
644
+ %% point.
645
+ %%========================================================================
646
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
647
+
648
+ Fix the Package Descriptor
649
+ %bar "#F77" 4 10 80
650
+ %size 3
651
+ (package.yml)
652
+
653
+
654
+ %font "code", size 3, prefix 20, left
655
+ configuration-points:
656
+
657
+ %fore "#F00", font "code-bold"
658
+ Operations
659
+ %cont, fore "black", font "code"
660
+ :
661
+ type: map
662
+
663
+ contributions:
664
+
665
+ %font "code-bold", fore "#F00"
666
+ calc.Operations
667
+ %cont, font "code", fore "black"
668
+ :
669
+ :add: !!service calc.Adder
670
+ :subtract: !!service calc.Subtracter
671
+ :multiply: !!service calc.Multiplier
672
+ :divide: !!service calc.Divider
673
+
674
+
675
+ %bar "#F77" 4 10 80
676
+ %size 2.5, center, prefix 0, font "standard-italic", fore "#F00"
677
+ (Note that the keys in this case are symbols,
678
+ hence the leading colon...)
679
+
680
+ %page
681
+ %%========================================================================
682
+ %% h1. Refining (continued)
683
+ %%
684
+ %% Lastly, we just use the configuration point to initialize the
685
+ %% Calculator service.
686
+ %%========================================================================
687
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
688
+
689
+ Fix the Package Descriptor
690
+ %bar "#F77" 4 10 80
691
+ %size 3
692
+ (package.yml, continued)
693
+
694
+
695
+ %font "code", size 3, prefix 20, left
696
+ service-points:
697
+ ...
698
+
699
+ Calculator:
700
+ implementor:
701
+ factory: copland.BuilderFactory
702
+ class: calc/Calculator
703
+ parameters:
704
+ - !!configuration
705
+ %cont, fore "#F00", font "code-bold"
706
+ calc.Operations
707
+
708
+ %page
709
+ %%========================================================================
710
+ %% h1. Refining (continued)
711
+ %%
712
+ %% Finally, we change our driver file and run it.
713
+ %%========================================================================
714
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
715
+
716
+ Driver File
717
+ %bar "#F77" 4 10 80
718
+ %size 3
719
+ (main.rb)
720
+
721
+ %font "code", size 3, prefix 20, left
722
+ require 'copland'
723
+
724
+ registry = Copland::Registry.build
725
+
726
+ calc = registry.service( "calc.Calculator" )
727
+
728
+ p calc.add( 8, 5 )
729
+ p calc.subtract( 8, 5 )
730
+ p calc.multiply( 8, 5 )
731
+ p calc.divide( 8, 5 )
732
+
733
+
734
+ %pause, font "standard-italic", size 3, center, prefix 0
735
+ %bar "#F77" 4 10 80
736
+ Note that this is unchanged!
737
+ We did not change the client interface for Calculator,
738
+ so clients of the service do not need to change.
739
+
740
+ %page
741
+ %%========================================================================
742
+ %% h1. Benefits of this approach
743
+ %%
744
+ %% * Third parties can easily add new functions to the calculator
745
+ %% * With just a little more work we could make it possible for third
746
+ %% parties to redefine the "core" operations
747
+ %% * Modular, "agile", testable
748
+ %%========================================================================
749
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
750
+
751
+ So What Did This Buy Us?
752
+ %bar "#F77" 4 10 80
753
+
754
+ %size 4, pause, prefix 20, left
755
+ * Configurable, Reusable, Extensible
756
+
757
+ %pause
758
+ * Third parties can easily add new functions
759
+ to the calculator by contributing their own
760
+ services to the calc.Operations configuration
761
+ point.
762
+
763
+ %pause
764
+ * With just a little more work we could make
765
+ it possible for third parties to redefine
766
+ existing operations.
767
+
768
+ %page
769
+ %%========================================================================
770
+ %% h1. Debuggable: logs
771
+ %%
772
+ %% You can easily obtain access to a consistent logging mechanism by
773
+ %% setting an attribute of your service to a log instance in your
774
+ %% package descriptor.
775
+ %%========================================================================
776
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
777
+
778
+ Debuggable: Consistent Logging
779
+ %bar "#F77" 4 10 80
780
+ %size 3
781
+ (package.yml)
782
+
783
+ %font "code", size 3, prefix 20, left
784
+ service-points:
785
+ Calculator:
786
+ implementor:
787
+ factory: copland.BuilderFactory
788
+ class: calc/Calculator
789
+ parameters:
790
+ - !!configuration calc.Operations
791
+ properties:
792
+ log: !!log ~
793
+
794
+
795
+ %size 4, font "standard-italic", prefix 0, center, fore "#F00"
796
+ %bar "#F77" 4 10 80
797
+ continued -->
798
+
799
+ %page
800
+ %%========================================================================
801
+ %% h1. Debuggable: logs (continued)
802
+ %%========================================================================
803
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
804
+
805
+ Debuggable (continued)
806
+ %bar "#F77" 4 10 80
807
+ %size 3
808
+ (calc.rb)
809
+
810
+ %font "code", size 3, prefix 20, left
811
+ class Calculator
812
+
813
+ attr_writer :log
814
+
815
+ ...
816
+
817
+ def method_missing( op, *args )
818
+ if @operations.has_key?( op )
819
+ %fore "#F00"
820
+ @log.debug "invoking #{op}" if @log.debug?
821
+ %fore "black"
822
+ return @operations[ op ].compute( *args )
823
+ else
824
+ super
825
+ end
826
+ end
827
+
828
+ ...
829
+ end
830
+
831
+ %page
832
+ %%========================================================================
833
+ %% h1. Debuggable: interceptors
834
+ %%========================================================================
835
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
836
+
837
+ Debuggable: Interceptors
838
+ %bar "#F77" 4 10 80
839
+ %size 3
840
+ (package.yml)
841
+
842
+ %font "code", size 3, prefix 20, left
843
+ service-points:
844
+ Calculator:
845
+ implementor:
846
+ factory: copland.BuilderFactory
847
+ class: calc/Calculator
848
+ parameters:
849
+ - !!configuration calc.Operations
850
+ interceptors:
851
+ - service: copland.LoggingInterceptor
852
+
853
+ %page
854
+ %%========================================================================
855
+ %% h1. Testable
856
+ %%
857
+ %% Each component may be tested independently of the others by substituting
858
+ %% mock objects.
859
+ %%========================================================================
860
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
861
+
862
+ Testable
863
+ %bar "#F77" 4 10 80
864
+ %size 3
865
+ (test.rb)
866
+
867
+ %font "code", size 2.5, prefix 15, left
868
+ class TC_Calculator < Test::Unit::TestCase
869
+ class MockOperation; def compute( a, b ); "#{a}:#{b}"; end; end
870
+
871
+ def setup; @calc = Calculator.new( :mock => MockOperation.new ); end
872
+
873
+ def test_operation
874
+ assert_equal "hello:world", @calc.mock( "hello", "world" )
875
+ end
876
+
877
+ def test_missing
878
+ assert_raised( NoMethodError ) { @calc.bogus( 1, 2 ) }
879
+ end
880
+ end
881
+
882
+ class TC_Adder < Test::Unit::TestCase
883
+ def test_add
884
+ assert_equal -5, Adder.new.compute( 1, -6 )
885
+ end
886
+ end
887
+
888
+ %bar "#F77" 4 10 80
889
+ %size 2.5, center, prefix 0, font "standard-italic", fore "#F00"
890
+ Each component can be tested independently
891
+
892
+ %page
893
+ %%========================================================================
894
+ %% h1. A "real" example
895
+ %%
896
+ %%========================================================================
897
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
898
+
899
+ A Real Example
900
+ %bar "#F77" 4 10 80
901
+
902
+ %size 4, prefix 20, left
903
+ *
904
+ %cont, fore "#F00"
905
+ Packrat
906
+ %cont, fore "black"
907
+ : package documentation extractor
908
+ for Copland
909
+
910
+ example output:
911
+ %fore "#00F"
912
+ http://copland.rubyforge.org/packrat
913
+ %fore "black"
914
+
915
+ * Looks at all available package descriptors
916
+ and formats them according to a specified
917
+ template.
918
+
919
+ * Implemented using Copland!
920
+
921
+ %page
922
+ %%========================================================================
923
+ %% h1. Other uses...
924
+ %%
925
+ %% * Database abstraction layer
926
+ %% * object-relational mapping tool
927
+ %% * web application framework
928
+ %% * tying all three above together!
929
+ %% * personal finance manager
930
+ %% * text editor
931
+ %%========================================================================
932
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
933
+
934
+ Copland: Other Uses
935
+ %bar "#F77" 4 10 80
936
+
937
+ %size 4, pause, lcutin
938
+ Database abstraction layer
939
+
940
+ %pause, rcutin
941
+ Object-relational mapping layer
942
+
943
+ %pause, lcutin
944
+ Web application framework
945
+
946
+ %pause, rcutin
947
+ All-In-One: "
948
+ %fore "#F00", cont
949
+ Framework Glue
950
+ %fore "black", cont
951
+ "
952
+
953
+ %pause, lcutin
954
+ Text editor, IDE, Mail client, etc...
955
+
956
+ %page
957
+ %%========================================================================
958
+ %% h1. Other features
959
+ %%
960
+ %% service models, substitution symbols, etc.
961
+ %%========================================================================
962
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
963
+
964
+ Other Features of Copland
965
+ %bar "#F77" 4 10 80, size 2
966
+
967
+ %size 3, prefix 10, font "standard-bold", rcutin, left
968
+ Service Models
969
+
970
+ %prefix 20, font "standard", pause
971
+ prototype, prototype-deferred, singleton, singleton-deferred,
972
+ threaded, roll-your-own
973
+
974
+ %pause, rcutin, prefix 10, font "standard-bold"
975
+ Substitution Symbols
976
+
977
+ %prefix 20, font "code", pause
978
+ properties:
979
+ user: ${user.name}
980
+ ...
981
+ contributions:
982
+ copland.ApplicationDefaults:
983
+ user.name: minam
984
+
985
+ %pause, rcutin, prefix 10, font "standard-bold"
986
+ Other Features
987
+
988
+ %prefix 20, font "standard", pause
989
+ customizable logging, listener/producer systems,
990
+ interceptor ordering, distributing packages
991
+
992
+ %page
993
+ %%========================================================================
994
+ %% h1. Other cool things to try...
995
+ %%
996
+ %% copland-lib, copland-remote, copland-webrick
997
+ %%========================================================================
998
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
999
+
1000
+ Other Cool Things to Try
1001
+ %bar "#F77" 4 10 80
1002
+
1003
+ %prefix 10, size 3, font "standard-bold", left
1004
+ copland-lib
1005
+
1006
+ %prefix 20, font "standard", pause
1007
+ * multicast services
1008
+ %pause
1009
+ * interceptors for redirecting, blocking, and synchronizing
1010
+ messages
1011
+
1012
+ %prefix 10, font "standard-bold", pause
1013
+ copland-remote
1014
+
1015
+ %prefix 20, font "standard", pause
1016
+ * bridge remote registries via DRb, SOAP, XML-RPC
1017
+ %pause
1018
+ * import web services transparently as Copland services
1019
+ %pause
1020
+ * easily export any Copland service as a web service
1021
+
1022
+
1023
+ %prefix 10, font "standard-bold", pause
1024
+ copland-webrick
1025
+
1026
+ %prefix 20, font "standard", pause
1027
+ * easily configure and operate WEBrick servers
1028
+ %pause
1029
+ * make any service invokable via HTTP using WEBrick
1030
+
1031
+ %page
1032
+ %%========================================================================
1033
+ %% h1. Future Directions
1034
+ %%========================================================================
1035
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
1036
+
1037
+ Future Directions
1038
+ %bar "#F77" 4 10 80
1039
+
1040
+ %size 4, prefix 20, left
1041
+ * Type 1 IoC (Interface Injection)
1042
+
1043
+ * Simplified API for package/service creation
1044
+
1045
+ * Define dependencies in code
1046
+ "ActiveCopland"
1047
+ %cont, font "standard-italic", size 3
1048
+ (sorry, David...)
1049
+ %size 4, font "standard"
1050
+
1051
+ * "Ruby-ize". Might require a new project...
1052
+
1053
+ * Educate, educate, educate!
1054
+
1055
+ %page
1056
+ %%========================================================================
1057
+ %% h1. Getting Copland
1058
+ %%========================================================================
1059
+ %fore "black", center, area 100 100 0 0, size 6, font "standard", prefix 0
1060
+
1061
+ Getting Copland
1062
+ %bar "#F77" 4 10 80
1063
+
1064
+ %size 4, prefix 20, left
1065
+ * RubyGems:
1066
+ %font "code", cont
1067
+ gem install copland
1068
+ %font "standard"
1069
+
1070
+ * RPA:
1071
+ %font "code", cont
1072
+ rpa install copland
1073
+ %font "standard"
1074
+
1075
+ * tar.bz2, tar.gz, zip:
1076
+ %fore "#00F"
1077
+ http://rubyforge.org/projects/copland
1078
+ %fore "black"
1079
+
1080
+ * User's Manual:
1081
+ %fore "#00F"
1082
+ http://copland.rubyforge.org
1083
+ %fore "black"