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
@@ -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"