ruby-contract 0.1.1

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 (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>