ruby-contract 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/COPYING +56 -0
  2. data/Manifest +85 -0
  3. data/README +32 -0
  4. data/TODO +83 -0
  5. data/doc/classes/Contract.html +599 -0
  6. data/doc/classes/Contract/Check.html +229 -0
  7. data/doc/classes/Contract/Check/All.html +172 -0
  8. data/doc/classes/Contract/Check/Any.html +172 -0
  9. data/doc/classes/Contract/Check/Block.html +172 -0
  10. data/doc/classes/Contract/Check/None.html +173 -0
  11. data/doc/classes/Contract/Check/Quack.html +172 -0
  12. data/doc/classes/Contract/ContractError.html +151 -0
  13. data/doc/classes/Contract/ContractException.html +162 -0
  14. data/doc/classes/Contract/ContractMismatch.html +134 -0
  15. data/doc/classes/Kernel.html +256 -0
  16. data/doc/classes/Method.html +135 -0
  17. data/doc/classes/MethodSignatureMixin.html +208 -0
  18. data/doc/classes/Module.html +526 -0
  19. data/doc/created.rid +1 -0
  20. data/doc/dot/f_0.dot +14 -0
  21. data/doc/dot/f_0.png +0 -0
  22. data/doc/dot/f_1.dot +14 -0
  23. data/doc/dot/f_1.png +0 -0
  24. data/doc/dot/f_2.dot +14 -0
  25. data/doc/dot/f_2.png +0 -0
  26. data/doc/dot/f_3.dot +112 -0
  27. data/doc/dot/f_3.png +0 -0
  28. data/doc/dot/f_4.dot +62 -0
  29. data/doc/dot/f_4.png +0 -0
  30. data/doc/dot/f_5.dot +62 -0
  31. data/doc/dot/f_5.png +0 -0
  32. data/doc/dot/f_6.dot +224 -0
  33. data/doc/dot/f_6.png +0 -0
  34. data/doc/dot/f_6_0.dot +24 -0
  35. data/doc/dot/f_6_0.png +0 -0
  36. data/doc/dot/f_6_1.dot +24 -0
  37. data/doc/dot/f_6_1.png +0 -0
  38. data/doc/dot/f_7.dot +62 -0
  39. data/doc/dot/f_7.png +0 -0
  40. data/doc/files/COPYING.html +168 -0
  41. data/doc/files/README.html +146 -0
  42. data/doc/files/TODO.html +240 -0
  43. data/doc/files/lib/contract/assertions_rb.html +118 -0
  44. data/doc/files/lib/contract/exception_rb.html +125 -0
  45. data/doc/files/lib/contract/integration_rb.html +130 -0
  46. data/doc/files/lib/contract/overrides_rb.html +118 -0
  47. data/doc/files/lib/contract_rb.html +127 -0
  48. data/doc/fr_class_index.html +40 -0
  49. data/doc/fr_file_index.html +34 -0
  50. data/doc/fr_method_index.html +45 -0
  51. data/doc/index.html +24 -0
  52. data/doc/rdoc-style.css +208 -0
  53. data/lib/contract.rb +146 -0
  54. data/lib/contract/assertions.rb +42 -0
  55. data/lib/contract/exception.rb +95 -0
  56. data/lib/contract/integration.rb +664 -0
  57. data/lib/contract/overrides.rb +41 -0
  58. data/setup.rb +1360 -0
  59. data/test/coverage/_-lib-contract-assertions_rb.html +526 -0
  60. data/test/coverage/_-lib-contract-exception_rb.html +632 -0
  61. data/test/coverage/_-lib-contract-integration_rb.html +1450 -0
  62. data/test/coverage/_-lib-contract-overrides_rb.html +524 -0
  63. data/test/coverage/_-lib-contract_rb.html +724 -0
  64. data/test/coverage/__-lib-contract-assertions_rb.html +484 -0
  65. data/test/coverage/__-lib-contract-exception_rb.html +537 -0
  66. data/test/coverage/__-lib-contract-integration_rb.html +946 -0
  67. data/test/coverage/__-lib-contract-overrides_rb.html +483 -0
  68. data/test/coverage/__-lib-contract_rb.html +583 -0
  69. data/test/coverage/index.html +93 -0
  70. data/test/tc_all.rb +8 -0
  71. data/test/tc_contract.rb +109 -0
  72. data/test/tc_exception.rb +43 -0
  73. data/test/tc_integration.rb +357 -0
  74. metadata +136 -0
@@ -0,0 +1,946 @@
1
+ <?xml version="1.0" encoding="ISO-8859-15"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
3
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml">
5
+ <head><title>../lib/contract/integration.rb - coverage</title>
6
+ <style type="text/css">body {
7
+ background-color: rgb(180, 180, 180);
8
+ }
9
+ span.marked {
10
+ background-color: rgb(185, 200, 200);
11
+ display: block;
12
+ }
13
+ span.inferred {
14
+ background-color: rgb(180, 195, 195);
15
+ display: block;
16
+ }
17
+ span.run0 {
18
+ background-color: rgb(178, 204, 255);
19
+ display: block;
20
+ }
21
+ span.run1 {
22
+ background-color: rgb(178, 206, 255);
23
+ display: block;
24
+ }
25
+ span.run2 {
26
+ background-color: rgb(178, 209, 255);
27
+ display: block;
28
+ }
29
+ span.run3 {
30
+ background-color: rgb(178, 211, 255);
31
+ display: block;
32
+ }
33
+ span.run4 {
34
+ background-color: rgb(178, 214, 255);
35
+ display: block;
36
+ }
37
+ span.run5 {
38
+ background-color: rgb(178, 218, 255);
39
+ display: block;
40
+ }
41
+ span.run6 {
42
+ background-color: rgb(178, 220, 255);
43
+ display: block;
44
+ }
45
+ span.run7 {
46
+ background-color: rgb(178, 223, 255);
47
+ display: block;
48
+ }
49
+ span.run8 {
50
+ background-color: rgb(178, 225, 255);
51
+ display: block;
52
+ }
53
+ span.run9 {
54
+ background-color: rgb(178, 228, 255);
55
+ display: block;
56
+ }
57
+ span.run10 {
58
+ background-color: rgb(178, 232, 255);
59
+ display: block;
60
+ }
61
+ span.run11 {
62
+ background-color: rgb(178, 234, 255);
63
+ display: block;
64
+ }
65
+ span.run12 {
66
+ background-color: rgb(178, 237, 255);
67
+ display: block;
68
+ }
69
+ span.run13 {
70
+ background-color: rgb(178, 239, 255);
71
+ display: block;
72
+ }
73
+ span.run14 {
74
+ background-color: rgb(178, 242, 255);
75
+ display: block;
76
+ }
77
+ span.run15 {
78
+ background-color: rgb(178, 246, 255);
79
+ display: block;
80
+ }
81
+ span.run16 {
82
+ background-color: rgb(178, 248, 255);
83
+ display: block;
84
+ }
85
+ span.run17 {
86
+ background-color: rgb(178, 251, 255);
87
+ display: block;
88
+ }
89
+ span.run18 {
90
+ background-color: rgb(178, 253, 255);
91
+ display: block;
92
+ }
93
+ span.run19 {
94
+ background-color: rgb(178, 255, 253);
95
+ display: block;
96
+ }
97
+ span.run20 {
98
+ background-color: rgb(178, 255, 249);
99
+ display: block;
100
+ }
101
+ span.run21 {
102
+ background-color: rgb(178, 255, 247);
103
+ display: block;
104
+ }
105
+ span.run22 {
106
+ background-color: rgb(178, 255, 244);
107
+ display: block;
108
+ }
109
+ span.run23 {
110
+ background-color: rgb(178, 255, 242);
111
+ display: block;
112
+ }
113
+ span.run24 {
114
+ background-color: rgb(178, 255, 239);
115
+ display: block;
116
+ }
117
+ span.run25 {
118
+ background-color: rgb(178, 255, 235);
119
+ display: block;
120
+ }
121
+ span.run26 {
122
+ background-color: rgb(178, 255, 233);
123
+ display: block;
124
+ }
125
+ span.run27 {
126
+ background-color: rgb(178, 255, 230);
127
+ display: block;
128
+ }
129
+ span.run28 {
130
+ background-color: rgb(178, 255, 228);
131
+ display: block;
132
+ }
133
+ span.run29 {
134
+ background-color: rgb(178, 255, 225);
135
+ display: block;
136
+ }
137
+ span.run30 {
138
+ background-color: rgb(178, 255, 221);
139
+ display: block;
140
+ }
141
+ span.run31 {
142
+ background-color: rgb(178, 255, 219);
143
+ display: block;
144
+ }
145
+ span.run32 {
146
+ background-color: rgb(178, 255, 216);
147
+ display: block;
148
+ }
149
+ span.run33 {
150
+ background-color: rgb(178, 255, 214);
151
+ display: block;
152
+ }
153
+ span.run34 {
154
+ background-color: rgb(178, 255, 211);
155
+ display: block;
156
+ }
157
+ span.run35 {
158
+ background-color: rgb(178, 255, 207);
159
+ display: block;
160
+ }
161
+ span.run36 {
162
+ background-color: rgb(178, 255, 205);
163
+ display: block;
164
+ }
165
+ span.run37 {
166
+ background-color: rgb(178, 255, 202);
167
+ display: block;
168
+ }
169
+ span.run38 {
170
+ background-color: rgb(178, 255, 200);
171
+ display: block;
172
+ }
173
+ span.run39 {
174
+ background-color: rgb(178, 255, 197);
175
+ display: block;
176
+ }
177
+ span.run40 {
178
+ background-color: rgb(178, 255, 193);
179
+ display: block;
180
+ }
181
+ span.run41 {
182
+ background-color: rgb(178, 255, 191);
183
+ display: block;
184
+ }
185
+ span.run42 {
186
+ background-color: rgb(178, 255, 188);
187
+ display: block;
188
+ }
189
+ span.run43 {
190
+ background-color: rgb(178, 255, 186);
191
+ display: block;
192
+ }
193
+ span.run44 {
194
+ background-color: rgb(178, 255, 183);
195
+ display: block;
196
+ }
197
+ span.run45 {
198
+ background-color: rgb(178, 255, 179);
199
+ display: block;
200
+ }
201
+ span.run46 {
202
+ background-color: rgb(179, 255, 178);
203
+ display: block;
204
+ }
205
+ span.run47 {
206
+ background-color: rgb(182, 255, 178);
207
+ display: block;
208
+ }
209
+ span.run48 {
210
+ background-color: rgb(184, 255, 178);
211
+ display: block;
212
+ }
213
+ span.run49 {
214
+ background-color: rgb(187, 255, 178);
215
+ display: block;
216
+ }
217
+ span.run50 {
218
+ background-color: rgb(191, 255, 178);
219
+ display: block;
220
+ }
221
+ span.run51 {
222
+ background-color: rgb(193, 255, 178);
223
+ display: block;
224
+ }
225
+ span.run52 {
226
+ background-color: rgb(196, 255, 178);
227
+ display: block;
228
+ }
229
+ span.run53 {
230
+ background-color: rgb(198, 255, 178);
231
+ display: block;
232
+ }
233
+ span.run54 {
234
+ background-color: rgb(201, 255, 178);
235
+ display: block;
236
+ }
237
+ span.run55 {
238
+ background-color: rgb(205, 255, 178);
239
+ display: block;
240
+ }
241
+ span.run56 {
242
+ background-color: rgb(207, 255, 178);
243
+ display: block;
244
+ }
245
+ span.run57 {
246
+ background-color: rgb(210, 255, 178);
247
+ display: block;
248
+ }
249
+ span.run58 {
250
+ background-color: rgb(212, 255, 178);
251
+ display: block;
252
+ }
253
+ span.run59 {
254
+ background-color: rgb(215, 255, 178);
255
+ display: block;
256
+ }
257
+ span.run60 {
258
+ background-color: rgb(219, 255, 178);
259
+ display: block;
260
+ }
261
+ span.run61 {
262
+ background-color: rgb(221, 255, 178);
263
+ display: block;
264
+ }
265
+ span.run62 {
266
+ background-color: rgb(224, 255, 178);
267
+ display: block;
268
+ }
269
+ span.run63 {
270
+ background-color: rgb(226, 255, 178);
271
+ display: block;
272
+ }
273
+ span.run64 {
274
+ background-color: rgb(229, 255, 178);
275
+ display: block;
276
+ }
277
+ span.run65 {
278
+ background-color: rgb(233, 255, 178);
279
+ display: block;
280
+ }
281
+ span.run66 {
282
+ background-color: rgb(235, 255, 178);
283
+ display: block;
284
+ }
285
+ span.run67 {
286
+ background-color: rgb(238, 255, 178);
287
+ display: block;
288
+ }
289
+ span.run68 {
290
+ background-color: rgb(240, 255, 178);
291
+ display: block;
292
+ }
293
+ span.run69 {
294
+ background-color: rgb(243, 255, 178);
295
+ display: block;
296
+ }
297
+ span.run70 {
298
+ background-color: rgb(247, 255, 178);
299
+ display: block;
300
+ }
301
+ span.run71 {
302
+ background-color: rgb(249, 255, 178);
303
+ display: block;
304
+ }
305
+ span.run72 {
306
+ background-color: rgb(252, 255, 178);
307
+ display: block;
308
+ }
309
+ span.run73 {
310
+ background-color: rgb(255, 255, 178);
311
+ display: block;
312
+ }
313
+ span.run74 {
314
+ background-color: rgb(255, 252, 178);
315
+ display: block;
316
+ }
317
+ span.run75 {
318
+ background-color: rgb(255, 248, 178);
319
+ display: block;
320
+ }
321
+ span.run76 {
322
+ background-color: rgb(255, 246, 178);
323
+ display: block;
324
+ }
325
+ span.run77 {
326
+ background-color: rgb(255, 243, 178);
327
+ display: block;
328
+ }
329
+ span.run78 {
330
+ background-color: rgb(255, 240, 178);
331
+ display: block;
332
+ }
333
+ span.run79 {
334
+ background-color: rgb(255, 238, 178);
335
+ display: block;
336
+ }
337
+ span.run80 {
338
+ background-color: rgb(255, 234, 178);
339
+ display: block;
340
+ }
341
+ span.run81 {
342
+ background-color: rgb(255, 232, 178);
343
+ display: block;
344
+ }
345
+ span.run82 {
346
+ background-color: rgb(255, 229, 178);
347
+ display: block;
348
+ }
349
+ span.run83 {
350
+ background-color: rgb(255, 226, 178);
351
+ display: block;
352
+ }
353
+ span.run84 {
354
+ background-color: rgb(255, 224, 178);
355
+ display: block;
356
+ }
357
+ span.run85 {
358
+ background-color: rgb(255, 220, 178);
359
+ display: block;
360
+ }
361
+ span.run86 {
362
+ background-color: rgb(255, 218, 178);
363
+ display: block;
364
+ }
365
+ span.run87 {
366
+ background-color: rgb(255, 215, 178);
367
+ display: block;
368
+ }
369
+ span.run88 {
370
+ background-color: rgb(255, 212, 178);
371
+ display: block;
372
+ }
373
+ span.run89 {
374
+ background-color: rgb(255, 210, 178);
375
+ display: block;
376
+ }
377
+ span.run90 {
378
+ background-color: rgb(255, 206, 178);
379
+ display: block;
380
+ }
381
+ span.run91 {
382
+ background-color: rgb(255, 204, 178);
383
+ display: block;
384
+ }
385
+ span.run92 {
386
+ background-color: rgb(255, 201, 178);
387
+ display: block;
388
+ }
389
+ span.run93 {
390
+ background-color: rgb(255, 198, 178);
391
+ display: block;
392
+ }
393
+ span.run94 {
394
+ background-color: rgb(255, 196, 178);
395
+ display: block;
396
+ }
397
+ span.run95 {
398
+ background-color: rgb(255, 192, 178);
399
+ display: block;
400
+ }
401
+ span.run96 {
402
+ background-color: rgb(255, 189, 178);
403
+ display: block;
404
+ }
405
+ span.run97 {
406
+ background-color: rgb(255, 187, 178);
407
+ display: block;
408
+ }
409
+ span.run98 {
410
+ background-color: rgb(255, 184, 178);
411
+ display: block;
412
+ }
413
+ span.run99 {
414
+ background-color: rgb(255, 182, 178);
415
+ display: block;
416
+ }
417
+
418
+ div.overview {
419
+ border-bottom: 8px solid black;
420
+ }
421
+ </style></head>
422
+ <body><div class="overview">
423
+ <table>
424
+ <tr><td>filename</td><td><tt>../lib/contract/integration.rb</tt></td></tr>
425
+ <tr><td>total coverage</td><td>93.3</td></tr>
426
+ <tr><td>code coverage</td><td>87.9</td></tr>
427
+ </table>
428
+ </div>
429
+ <pre><span class="inferred"> 1 # This file contains code for integrating the contract library with built-in
430
+ 2 # classes and methods.
431
+ 3 #
432
+ 4 # See Contract::Check, Module#signature and Module#fulfills.
433
+ 5
434
+ 6
435
+ </span><span class="marked"> 7 class Contract &lt; Test::Unit::TestCase
436
+ </span><span class="inferred"> 8 # Implements checks that can for example be used in Module#signature
437
+ 9 # specifications. They are implemented simply by overriding the === case
438
+ 10 # equality operator. They can also be nested like this:
439
+ 11 # # Matches something that is an Enumerable and that responds to
440
+ 12 # # either :to_ary or :to_a.
441
+ 13 # signature :x, Contract::Check::All[
442
+ 14 # Enumerable,
443
+ 15 # Contract::Check::Any[
444
+ 16 # Contract::Check::Quack[:to_a],
445
+ 17 # Contract::Check::Quack[:to_ary]
446
+ 18 # ]
447
+ 19 # ]
448
+ </span><span class="marked"> 20 module Check
449
+ </span><span class="inferred"> 21 # An abstract Base class for Contract::Check classes.
450
+ 22 # Contains logic for instantation.
451
+ </span><span class="marked"> 23 class Base # :nodoc:
452
+ 24 class &lt;&lt; self
453
+ 25 alias :[] :new
454
+ </span><span class="inferred"> 26 end
455
+ 27
456
+ </span><span class="marked"> 28 def initialize(*args, &amp;block)
457
+ 29 @args, @block = args, block
458
+ </span><span class="inferred"> 30 end
459
+ 31 end
460
+ 32
461
+ 33 # Checks that the specified block matches.
462
+ 34 # Example:
463
+ 35 # signature :x, Contract::Check.block { |arg| arg &gt; 0 }
464
+ </span><span class="marked"> 36 class Block &lt; Base
465
+ 37 def ===(other)
466
+ 38 @block.call(other)
467
+ </span><span class="inferred"> 39 end
468
+ 40 end
469
+ 41 # Short-cut for creating a Contract::Check::Block.
470
+ </span><span class="marked"> 42 def self.block(&amp;block) # :yields: arg
471
+ 43 Block.new(&amp;block)
472
+ </span><span class="inferred"> 44 end
473
+ 45
474
+ 46 # Checks that all the specified methods are answered.
475
+ 47 # Example:
476
+ 48 # signature :x, Contract::Check::Quack[:to_sym]
477
+ </span><span class="marked"> 49 class Quack &lt; Base
478
+ 50 def ===(other)
479
+ 51 @args.all? { |arg| other.respond_to?(arg) }
480
+ </span><span class="inferred"> 52 end
481
+ 53 end
482
+ 54
483
+ 55 # Checks that all the specified conditions match.
484
+ 56 # Example:
485
+ 57 # signature :x, Contract::Check::All[Array, Enumerable]
486
+ </span><span class="marked"> 58 class All &lt; Base
487
+ 59 def ===(other)
488
+ 60 @args.all? { |arg| arg === other }
489
+ </span><span class="inferred"> 61 end
490
+ 62 end
491
+ 63 # Alias for Contract::Check::All
492
+ </span><span class="marked"> 64 And = All
493
+ </span><span class="inferred"> 65
494
+ 66 # Checks that at least one of the specified conditions match.
495
+ 67 # Example:
496
+ 68 # signature :x, Contract::Check::Any[String, Symbol]
497
+ </span><span class="marked"> 69 class Any &lt; Base
498
+ 70 def ===(other)
499
+ 71 @args.any? { |arg| arg === other }
500
+ </span><span class="inferred"> 72 end
501
+ 73 end
502
+ 74 # Alias for Contract::Check::Any
503
+ </span><span class="marked"> 75 Or = Any
504
+ </span><span class="inferred"> 76
505
+ 77 # Checks that none of the specified conditions match.
506
+ 78 # Example:
507
+ 79 # signature :x, Contract::Check::None[Numeric, Symbol]
508
+ 80 # signature :x, Contract::Check::Not[Comparable]
509
+ </span><span class="marked"> 81 class None &lt; Base
510
+ 82 def ===(other)
511
+ 83 not @args.any? { |arg| arg === other }
512
+ </span><span class="inferred"> 84 end
513
+ 85 end
514
+ 86 # Alias for Contract::Check::None
515
+ </span><span class="marked"> 87 Not = None
516
+ </span><span class="inferred"> 88 end
517
+ 89
518
+ </span><span class="marked"> 90 class &lt;&lt; self
519
+ </span><span class="inferred"> 91 # Whether signatures should be checked. By default signatures are checked
520
+ 92 # only when the application is run in $DEBUG mode. (By specifying the -d
521
+ 93 # switch on the invocation of Ruby.)
522
+ 94 #
523
+ 95 # Note: If you want to change this you need to do so before doing any
524
+ 96 # Module#signature calls or it will not be applied. It's probably best
525
+ 97 # set right after requiring the contract library.
526
+ </span><span class="marked"> 98 attr_accessor :check_signatures
527
+ 99 alias :check_signatures? :check_signatures
528
+ </span><span class="inferred">100
529
+ 101 # Whether fulfills should be checked. This is enabled by default.
530
+ 102 #
531
+ 103 # Note: If you want to change this you need to do so before doing any
532
+ 104 # Module#fulfills calls or it will not be applied. It's probably best
533
+ 105 # set right after requiring the contract library.
534
+ </span><span class="marked">106 attr_accessor :check_fulfills
535
+ 107 alias :check_fulfills? :check_fulfills
536
+ </span><span class="inferred">108
537
+ 109 # All adaption routes.
538
+ </span><span class="marked">110 attr_accessor :adaptions # :nodoc:
539
+ </span><span class="inferred">111 end
540
+ </span><span class="marked">112 self.check_signatures = $DEBUG if self.check_signatures.nil?
541
+ 113 self.check_fulfills = true if self.check_fulfills.nil?
542
+ 114 if self.adaptions.nil? then
543
+ 115 self.adaptions = Hash.new { |hash, key| hash[key] = Array.new }
544
+ </span><span class="inferred">116 end
545
+ 117
546
+ 118 # Tries to adapt the specified object to the specified type.
547
+ 119 # Returns the old object if no suitable adaption route was found or if
548
+ 120 # it already is of the specified type.
549
+ 121 #
550
+ 122 # This will only use adaptions where the :to part is equal to the specified
551
+ 123 # type. No multi-step conversion will be performed.
552
+ </span><span class="marked">124 def self.adapt(object, type)
553
+ 125 return object if type === object
554
+ </span><span class="inferred">126
555
+ </span><span class="marked">127 @adaptions[type].each do |adaption|
556
+ </span><span class="false">128 if adaption[:from] === object and
557
+ </span><span class="marked">129 (adaption[:if].nil? or adaption[:if] === object)
558
+ </span><span class="false">130 then
559
+ </span><span class="marked">131 result = adaption[:via].call(object)
560
+ 132 return result if type === result
561
+ </span><span class="inferred">133 end
562
+ 134 end
563
+ 135
564
+ </span><span class="marked">136 return object
565
+ </span><span class="inferred">137 end
566
+ 138 end
567
+ 139
568
+ 140
569
+ </span><span class="marked">141 class Module
570
+ </span><span class="inferred">142 # Checks that the arguments and return value of a method match the specified
571
+ 143 # signature. Checks are only actually done when Contract.check_signatures is
572
+ 144 # set to true or if the &lt;code&gt;:no_adaption&lt;/code&gt; option is +false+. The
573
+ 145 # method will return +true+ in case it actually inserted the signature check
574
+ 146 # logic and +nil+ in case it didn't.
575
+ 147 #
576
+ 148 # You will usually specify one type specifier (&lt;code&gt;:any&lt;/code&gt; which will
577
+ 149 # allow anything to appear at that position of the argument list or something
578
+ 150 # that implements the === case equality operator -- samples are Contracts,
579
+ 151 # Ranges, Classes, Modules, Regexps, Contract::Checks and so on) per argument.
580
+ 152 # You can also use objects that implement the +call+ method as type specifiers
581
+ 153 # which includes Methods and Procs.
582
+ 154 #
583
+ 155 # If you don't use the &lt;code&gt;:repeated&lt;/code&gt; or &lt;code&gt;:allow_trailing&lt;/code&gt;
584
+ 156 # options the method will take exactly as many arguments as there are type
585
+ 157 # specifiers which means that &lt;code&gt;signature :a_method&lt;/code&gt; enforces
586
+ 158 # +a_method+ having exactly zero arguments.
587
+ 159 #
588
+ 160 # The checks are done by wrapping the type checks around the method.
589
+ 161 # ArgumentError exceptions will be raised in case the signature contract is
590
+ 162 # not adhered to by your caller.
591
+ 163 #
592
+ 164 # An ArgumentError exception will be raised in case the methods natural
593
+ 165 # argument list size and the signature you specified via Module.signature are
594
+ 166 # incompatible. (Note that they don't have to be completely equivalent, you
595
+ 167 # can still have a method taking zero or more arguments and apply a signature
596
+ 168 # that limits the actual argument count to three arguments.)
597
+ 169 #
598
+ 170 # This method can take quite a few options. Here's a complete list:
599
+ 171 #
600
+ 172 # &lt;code&gt;:return&lt;/code&gt;::
601
+ 173 # A return type that the method must comply to. Note that this check (if
602
+ 174 # failed) will actually raise a StandardError instead of an ArgumentError
603
+ 175 # because the failure likely lies in the method itself and not in what the
604
+ 176 # caller did.
605
+ 177 #
606
+ 178 # &lt;code&gt;:block&lt;/code&gt;::
607
+ 179 # +true+ or +false+ -- whether the method must take a block or not. So
608
+ 180 # specifying &lt;code&gt;:block =&gt; false&lt;/code&gt; enforces that the method is not
609
+ 181 # allowed to have a block supplied.
610
+ 182 #
611
+ 183 # &lt;code&gt;:allow_trailing&lt;/code&gt;::
612
+ 184 # +true+ or +false+ -- whether the argument list may contain trailing,
613
+ 185 # unchecked arguments.
614
+ 186 #
615
+ 187 # &lt;code&gt;:repeated&lt;/code&gt;::
616
+ 188 # An Array that specifies arguments of a method that will be repeated over
617
+ 189 # and over again at the end of the argument list.
618
+ 190 #
619
+ 191 # A good sample of this are Array#values_at which takes zero or or more
620
+ 192 # Numeric arguments and Enumerable#zip which takes zero or more other
621
+ 193 # Enumerable arguments.
622
+ 194 #
623
+ 195 # Note that the Array that was associated with the &lt;code&gt;:repeated&lt;/code&gt;
624
+ 196 # option must not be empty or an ArgumentError exception will be raised.
625
+ 197 # If there's just one repeated type you can omit the Array and directly
626
+ 198 # specify the type identifier.
627
+ 199 #
628
+ 200 # &lt;code&gt;:no_adaption&lt;/code&gt;::
629
+ 201 # +true+ or +false+ -- whether no type adaption should be performed.
630
+ 202 #
631
+ 203 # Usage:
632
+ 204 # signature(:to_s) # no arguments
633
+ 205 # signature(:+, :any) # one argument, type unchecked
634
+ 206 # signature(:+, Fixnum) # one argument, type Fixnum
635
+ 207 # signature(:+, NumericContract)
636
+ 208 # signature(:+, 1 .. 10)
637
+ 209 # signature(:sqrt, lambda { |arg| arg &gt; 0 })
638
+ 210 #
639
+ 211 # signature(:each, :block =&gt; true) # has to have block
640
+ 212 # signature(:to_i, :block =&gt; false) # not allowed to have block
641
+ 213 # signature(:to_i, :result =&gt; Fixnum) # return value must be Fixnum
642
+ 214 # signature(:zip, :allow_trailing =&gt; true) # unchecked trailing args
643
+ 215 # signature(:zip, :repeated =&gt; [Enumerable]) # repeated trailing args
644
+ 216 # signature(:zip, :repeated =&gt; Enumerable)
645
+ 217 # # foo(3, 6, 4, 7) works; foo(5), foo(3, 2) etc. don't
646
+ 218 # signature(:foo, :repeated =&gt; [1..4, 5..9])
647
+ </span><span class="marked">219 def signature(method, *args)
648
+ 220 options = {}
649
+ 221 signature = args.dup
650
+ 222 options.update(signature.pop) if signature.last.is_a?(Hash)
651
+ </span><span class="inferred">223
652
+ </span><span class="marked">224 return if not Contract.check_signatures? and options[:no_adaption]
653
+ </span><span class="inferred">225
654
+ </span><span class="marked">226 old_method = instance_method(method)
655
+ 227 remove_method(method) if instance_methods(false).include?(method.to_s)
656
+ </span><span class="inferred">228
657
+ </span><span class="marked">229 arity = old_method.arity
658
+ </span><span class="false">230 if arity != signature.size and
659
+ </span><span class="marked">231 (arity &gt;= 0 or signature.size &lt; ~arity) then
660
+ 232 raise(ArgumentError, &quot;signature isn't compatible with arity&quot;)
661
+ </span><span class="inferred">233 end
662
+ 234
663
+ 235 # Normalizes specifiers to Objects that respond to === so that the run-time
664
+ 236 # checks only have to deal with that case. Also checks that a specifier is
665
+ 237 # actually valid.
666
+ </span><span class="marked">238 convert_specifier = lambda do |item|
667
+ </span><span class="inferred">239 # Procs, Methods etc.
668
+ </span><span class="marked">240 if item.respond_to?(:call) then
669
+ 241 Contract::Check.block { |arg| item.call(arg) }
670
+ </span><span class="inferred">242 # Already okay
671
+ </span><span class="marked">243 elsif item.respond_to?(:===) or item == :any then
672
+ 244 item
673
+ </span><span class="inferred">245 # Unknown specifier
674
+ 246 else
675
+ </span><span class="marked">247 raise(ArgumentError, &quot;unsupported argument specifier #{item.inspect}&quot;)
676
+ </span><span class="inferred">248 end
677
+ 249 end
678
+ 250
679
+ </span><span class="marked">251 signature.map!(&amp;convert_specifier)
680
+ </span><span class="inferred">252
681
+ </span><span class="marked">253 if options.include?(:repeated) then
682
+ 254 options[:repeated] = Array(options[:repeated])
683
+ 255 if options[:repeated].size == 0 then
684
+ 256 raise(ArgumentError, &quot;repeated arguments may not be an empty Array&quot;)
685
+ </span><span class="inferred">257 else
686
+ </span><span class="marked">258 options[:repeated].map!(&amp;convert_specifier)
687
+ </span><span class="inferred">259 end
688
+ 260 end
689
+ 261
690
+ </span><span class="marked">262 if options.include?(:return) then
691
+ 263 options[:return] = convert_specifier.call(options[:return])
692
+ </span><span class="inferred">264 end
693
+ 265
694
+ 266 # We need to keep around references to our arguments because we will
695
+ 267 # need to access them via ObjectSpace._id2ref so that they do not
696
+ 268 # get garbage collected.
697
+ </span><span class="marked">269 @signatures ||= Hash.new { |hash, key| hash[key] = Array.new }
698
+ 270 @signatures[method] &lt;&lt; [signature, options, old_method]
699
+ </span><span class="inferred">271
700
+ </span><span class="marked">272 adapted = Proc.new do |obj, type, assign_to|
701
+ 273 if options[:no_adaption] then
702
+ 274 obj
703
+ 275 elsif assign_to then
704
+ 276 %{(#{assign_to} = Contract.adapt(#{obj}, #{type}))}
705
+ </span><span class="inferred">277 else
706
+ </span><span class="marked">278 %{Contract.adapt(#{obj}, #{type})}
707
+ </span><span class="inferred">279 end
708
+ 280 end
709
+ 281
710
+ 282 # We have to use class_eval so that signatures can be specified for
711
+ 283 # methods taking blocks in Ruby 1.8. (This will be obsolete in 1.9)
712
+ 284 # We also make the checks as efficient as we can.
713
+ </span><span class="marked">285 code = %{
714
+ </span><span class="inferred">286 def #{method}(*args, &amp;block)
715
+ </span><span class="false">287 old_args = args.dup
716
+ </span><span class="inferred">288
717
+ </span><span class="marked">289 #{if options.include?(:block) then
718
+ 290 if options[:block] then
719
+ 291 %{raise(ArgumentError, &quot;no block given&quot;) unless block}
720
+ </span><span class="inferred">292 else
721
+ </span><span class="marked">293 %{raise(ArgumentError, &quot;block given&quot;) if block}
722
+ </span><span class="inferred">294 end
723
+ 295 end
724
+ 296 }
725
+ 297
726
+ </span><span class="marked">298 #{if not(options[:allow_trailing] or options.include?(:repeated))
727
+ 299 msg = &quot;wrong number of arguments (\#{args.size} for &quot; +
728
+ </span><span class="inferred">300 &quot;#{signature.size})&quot;
729
+ </span><span class="marked">301 %{if args.size != #{signature.size} then
730
+ </span><span class="inferred">302 raise(ArgumentError, &quot;#{msg}&quot;)
731
+ 303 end
732
+ 304 }
733
+ </span><span class="marked">305 elsif signature.size &gt; 0
734
+ 306 msg = &quot;wrong number of arguments (\#{args.size} for &quot; +
735
+ </span><span class="inferred">307 &quot;at least #{signature.size}&quot;
736
+ </span><span class="marked">308 %{if args.size &lt; #{signature.size} then
737
+ </span><span class="inferred">309 raise(ArgumentError, &quot;#{msg}&quot;)
738
+ 310 end
739
+ 311 }
740
+ 312 end
741
+ 313 }
742
+ 314
743
+ </span><span class="marked">315 #{index = 0
744
+ 316 signature.map do |part|
745
+ 317 next if part == :any
746
+ 318 index += 1
747
+ 319 msg = &quot;argument #{index} (\#{arg.inspect}) does not match &quot; +
748
+ </span><span class="inferred">320 &quot;#{part.inspect}&quot;
749
+ </span><span class="marked">321 %{type = ObjectSpace._id2ref(#{part.object_id})
750
+ </span><span class="inferred">322 arg = args.shift
751
+ </span><span class="false">323 unless type === #{adapted[%{arg}, %{type}, %{old_args[#{index - 1}]}]}
752
+ 324 raise(ArgumentError, &quot;#{msg}&quot;)
753
+ 325 end
754
+ 326 }
755
+ 327 end
756
+ 328 }
757
+ </span><span class="inferred">329
758
+ </span><span class="marked">330 #{if repeated = options[:repeated] then
759
+ 331 msg = &quot;argument \#{idx + #{signature.size}}&quot; +
760
+ </span><span class="inferred">332 &quot;(\#{arg.inspect}) does not match \#{part.inspect}&quot;
761
+ </span><span class="marked">333 %{parts = ObjectSpace._id2ref(#{repeated.object_id})
762
+ </span><span class="inferred">334 args.each_with_index do |arg, idx|
763
+ </span><span class="false">335 part = parts[idx % #{repeated.size}]
764
+ 336 if part != :any and
765
+ 337 not part === (#{adapted[%{arg}, %{part}, %{old_args[idx]}]})
766
+ 338 then
767
+ 339 raise(ArgumentError, &quot;#{msg}&quot;)
768
+ 340 end
769
+ 341 end
770
+ 342 }
771
+ 343 end
772
+ 344 }
773
+ 345
774
+ 346 result = ObjectSpace._id2ref(#{old_method.object_id}).bind(self).
775
+ 347 call(*old_args, &amp;block)
776
+ </span><span class="marked">348 #{if rt = options[:return] and rt != :any then
777
+ 349 msg = &quot;return value (\#{result.inspect}) does not match #{rt.inspect}&quot;
778
+ 350 %{type = ObjectSpace._id2ref(#{rt.object_id})
779
+ </span><span class="inferred">351 unless type === #{adapted[%{result}, %{type}]}
780
+ 352 raise(StandardError, &quot;#{msg}&quot;)
781
+ 353 end
782
+ 354 }
783
+ 355 end
784
+ 356 }
785
+ 357 end
786
+ 358 }
787
+ </span><span class="marked">359 class_eval code, &quot;(signature check for #{old_method.inspect[/: (.+?)&gt;\Z/, 1]})&quot;
788
+ </span><span class="inferred">360
789
+ </span><span class="marked">361 return true
790
+ </span><span class="inferred">362 end
791
+ 363
792
+ 364 # Specifies that this Module/Class fulfills one or more contracts. The contracts
793
+ 365 # will automatically be verified after an instance has been successfully created.
794
+ 366 # This only actually does the checks when Contract.check_fulfills is enabled.
795
+ 367 # The method will return +true+ in case it actually inserted the check logic and
796
+ 368 # +nil+ in case it didn't.
797
+ 369 #
798
+ 370 # Note that this works by overriding the #initialize method which means that you
799
+ 371 # should either add the fulfills statements after your initialize method or call
800
+ 372 # the previously defined initialize method from your new one.
801
+ </span><span class="marked">373 def fulfills(*contracts)
802
+ 374 return unless Contract.check_fulfills?
803
+ </span><span class="inferred">375
804
+ </span><span class="marked">376 contracts.each do |contract|
805
+ 377 contract.implications.each do |implication|
806
+ 378 include implication
807
+ </span><span class="inferred">379 end
808
+ 380 end
809
+ 381
810
+ </span><span class="marked">382 old_method = instance_method(:initialize)
811
+ 383 remove_method(:initialize) if instance_methods(false).include?(&quot;initialize&quot;)
812
+ </span><span class="inferred">384
813
+ 385 # Keep visible references around so that the GC will not eat these up.
814
+ </span><span class="marked">386 @fulfills ||= Array.new
815
+ 387 @fulfills &lt;&lt; [contracts, old_method]
816
+ </span><span class="false">388
817
+ 389 # Have to use class_eval because define_method does not allow methods to take
818
+ 390 # blocks. This can be cleaned up when Ruby 1.9 has become current.
819
+ 391 class_eval %{
820
+ 392 def initialize(*args, &amp;block)
821
+ 393 ObjectSpace._id2ref(#{old_method.object_id}).bind(self).call(*args, &amp;block)
822
+ 394 ObjectSpace._id2ref(#{contracts.object_id}).each do |contract|
823
+ 395 contract.enforce self
824
+ 396 end
825
+ 397 end
826
+ </span><span class="marked">398 }, &quot;(post initialization contract check for #{self.inspect})&quot;
827
+ </span><span class="inferred">399
828
+ </span><span class="marked">400 return true
829
+ </span><span class="inferred">401 end
830
+ 402 end
831
+ 403
832
+ 404
833
+ </span><span class="marked">405 module Kernel
834
+ </span><span class="inferred">406 # Adds an adaption route from the specified type to the specified type.
835
+ 407 # Basic usage looks like this:
836
+ 408 # adaption :from =&gt; StringIO, :to =&gt; String, :via =&gt; :read
837
+ 409 #
838
+ 410 # This method takes various options. Here's a complete list:
839
+ 411 #
840
+ 412 # &lt;code&gt;:from&lt;/code&gt;::
841
+ 413 # The type that can be converted from. Defaults to +self+ meaning you
842
+ 414 # can safely omit it in Class, Module or Contract context.
843
+ 415 #
844
+ 416 # &lt;code&gt;:to&lt;/code&gt;::
845
+ 417 # The type that can be converted to. Defaults to +self+ meaning you
846
+ 418 # can safely omit it in Class, Module or Contract context.
847
+ 419 #
848
+ 420 # Note that you need to specify either &lt;code&gt;:from&lt;/code&gt; or
849
+ 421 # &lt;code&gt;:to&lt;/code&gt;.
850
+ 422 #
851
+ 423 # &lt;code&gt;:via&lt;/code&gt;::
852
+ 424 # How the &lt;code&gt;:from&lt;/code&gt; type will be converted to the
853
+ 425 # &lt;code&gt;:to&lt;/code&gt; type. If this is a Symbol the conversion will be
854
+ 426 # done by invoking the method identified by that Symbol on the
855
+ 427 # source object. Otherwise this should be something that responds to
856
+ 428 # the +call+ method (for example Methods and Procs) which will get
857
+ 429 # the source object as its argument and which should return the
858
+ 430 # target object.
859
+ 431 #
860
+ 432 # &lt;code&gt;:if&lt;/code&gt;::
861
+ 433 # The conversion can only be performed if this condition is met.
862
+ 434 # This can either be something that implements the === case
863
+ 435 # equivalence operator or something that implements the +call+
864
+ 436 # method. So Methods, Procs, Modules, Classes and Contracts all
865
+ 437 # make sense in this context. You can also specify a Symbol in
866
+ 438 # which case the conversion can only be performed if the source
867
+ 439 # object responds to the method identified by that Symbol.
868
+ 440 #
869
+ 441 # Note that the &lt;code&gt;:if&lt;/code&gt; option will default to the same
870
+ 442 # value as the &lt;code&gt;:via&lt;/code&gt; option if the &lt;code&gt;:via&lt;/code&gt;
871
+ 443 # option is a Symbol.
872
+ 444 #
873
+ 445 # If you invoke this method with a block it will be used instead of
874
+ 446 # the &lt;code&gt;:via&lt;/code&gt; option.
875
+ 447 #
876
+ 448 # See Contract.adapt for how conversion look-ups are performed.
877
+ </span><span class="marked">449 def adaption(options = {}, &amp;block) # :yield: source_object
878
+ 450 options = {
879
+ </span><span class="inferred">451 :from =&gt; self,
880
+ 452 :to =&gt; self
881
+ </span><span class="false">453 }.merge(options)
882
+ </span><span class="inferred">454
883
+ </span><span class="marked">455 if block then
884
+ 456 if options.include?(:via) then
885
+ 457 raise(ArgumentError, &quot;Can't use both block and :via&quot;)
886
+ </span><span class="inferred">458 else
887
+ </span><span class="marked">459 options[:via] = block
888
+ </span><span class="inferred">460 end
889
+ 461 end
890
+ 462
891
+ </span><span class="marked">463 if options[:via].respond_to?(:to_sym) then
892
+ 464 options[:via] = options[:via].to_sym
893
+ </span><span class="inferred">465 end
894
+ 466
895
+ </span><span class="marked">467 options[:if] ||= options[:via] if options[:via].is_a?(Symbol)
896
+ </span><span class="inferred">468
897
+ </span><span class="marked">469 if options[:via].is_a?(Symbol) then
898
+ 470 symbol = options[:via]
899
+ 471 options[:via] = lambda { |obj| obj.send(symbol) }
900
+ </span><span class="inferred">472 end
901
+ 473
902
+ </span><span class="marked">474 if options[:if].respond_to?(:to_sym) then
903
+ 475 options[:if] = options[:if].to_sym
904
+ </span><span class="inferred">476 end
905
+ 477
906
+ </span><span class="marked">478 if options[:if].is_a?(Symbol) then
907
+ 479 options[:if] = Contract::Check::Quack[options[:if]]
908
+ 480 elsif options[:if].respond_to?(:call) then
909
+ 481 callable = options[:if]
910
+ 482 options[:if] = Contract::Check.block { |obj| callable.call(obj) }
911
+ </span><span class="inferred">483 end
912
+ 484
913
+ </span><span class="marked">485 if options[:from] == self and options[:to] == self then
914
+ 486 raise(ArgumentError, &quot;Need to specify either :from or :to&quot;)
915
+ 487 elsif options[:from] == options[:to] then
916
+ 488 raise(ArgumentError, &quot;Self-adaption: :from and :to both are &quot; +
917
+ </span><span class="inferred">489 options[:to].inspect)
918
+ 490 end
919
+ 491
920
+ </span><span class="marked">492 unless options[:via]
921
+ 493 raise(ArgumentError, &quot;Need to specify how to adapt (use :via or block)&quot;)
922
+ </span><span class="inferred">494 end
923
+ 495
924
+ </span><span class="marked">496 Contract.adaptions[options[:to]] &lt;&lt; options
925
+ </span><span class="inferred">497 end
926
+ 498
927
+ 499 # Built-in adaption routes that Ruby already uses in its C code.
928
+ </span><span class="marked">500 adaption :to =&gt; Symbol, :via =&gt; :to_sym
929
+ 501 adaption :to =&gt; String, :via =&gt; :to_str
930
+ 502 adaption :to =&gt; Array, :via =&gt; :to_ary
931
+ 503 adaption :to =&gt; Integer, :via =&gt; :to_int
932
+ </span><span class="inferred">504 end
933
+ </span></pre>
934
+ <hr />
935
+ <p>
936
+ <a href="http://validator.w3.org/check/referer">
937
+ <img src="http://www.w3.org/Icons/valid-xhtml11"
938
+ alt="Valid XHTML 1.1!" height="31" width="88" />
939
+ </a>
940
+ <a href="http://jigsaw.w3.org/css-validator/">
941
+ <img style="border:0;width:88px;height:31px"
942
+ src="http://jigsaw.w3.org/css-validator/images/vcss"
943
+ alt="Valid CSS!" />
944
+ </a>
945
+ </p>
946
+ </body></html>