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.
- data/COPYING +56 -0
- data/Manifest +85 -0
- data/README +32 -0
- data/TODO +83 -0
- data/doc/classes/Contract.html +599 -0
- data/doc/classes/Contract/Check.html +229 -0
- data/doc/classes/Contract/Check/All.html +172 -0
- data/doc/classes/Contract/Check/Any.html +172 -0
- data/doc/classes/Contract/Check/Block.html +172 -0
- data/doc/classes/Contract/Check/None.html +173 -0
- data/doc/classes/Contract/Check/Quack.html +172 -0
- data/doc/classes/Contract/ContractError.html +151 -0
- data/doc/classes/Contract/ContractException.html +162 -0
- data/doc/classes/Contract/ContractMismatch.html +134 -0
- data/doc/classes/Kernel.html +256 -0
- data/doc/classes/Method.html +135 -0
- data/doc/classes/MethodSignatureMixin.html +208 -0
- data/doc/classes/Module.html +526 -0
- data/doc/created.rid +1 -0
- data/doc/dot/f_0.dot +14 -0
- data/doc/dot/f_0.png +0 -0
- data/doc/dot/f_1.dot +14 -0
- data/doc/dot/f_1.png +0 -0
- data/doc/dot/f_2.dot +14 -0
- data/doc/dot/f_2.png +0 -0
- data/doc/dot/f_3.dot +112 -0
- data/doc/dot/f_3.png +0 -0
- data/doc/dot/f_4.dot +62 -0
- data/doc/dot/f_4.png +0 -0
- data/doc/dot/f_5.dot +62 -0
- data/doc/dot/f_5.png +0 -0
- data/doc/dot/f_6.dot +224 -0
- data/doc/dot/f_6.png +0 -0
- data/doc/dot/f_6_0.dot +24 -0
- data/doc/dot/f_6_0.png +0 -0
- data/doc/dot/f_6_1.dot +24 -0
- data/doc/dot/f_6_1.png +0 -0
- data/doc/dot/f_7.dot +62 -0
- data/doc/dot/f_7.png +0 -0
- data/doc/files/COPYING.html +168 -0
- data/doc/files/README.html +146 -0
- data/doc/files/TODO.html +240 -0
- data/doc/files/lib/contract/assertions_rb.html +118 -0
- data/doc/files/lib/contract/exception_rb.html +125 -0
- data/doc/files/lib/contract/integration_rb.html +130 -0
- data/doc/files/lib/contract/overrides_rb.html +118 -0
- data/doc/files/lib/contract_rb.html +127 -0
- data/doc/fr_class_index.html +40 -0
- data/doc/fr_file_index.html +34 -0
- data/doc/fr_method_index.html +45 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/contract.rb +146 -0
- data/lib/contract/assertions.rb +42 -0
- data/lib/contract/exception.rb +95 -0
- data/lib/contract/integration.rb +664 -0
- data/lib/contract/overrides.rb +41 -0
- data/setup.rb +1360 -0
- data/test/coverage/_-lib-contract-assertions_rb.html +526 -0
- data/test/coverage/_-lib-contract-exception_rb.html +632 -0
- data/test/coverage/_-lib-contract-integration_rb.html +1450 -0
- data/test/coverage/_-lib-contract-overrides_rb.html +524 -0
- data/test/coverage/_-lib-contract_rb.html +724 -0
- data/test/coverage/__-lib-contract-assertions_rb.html +484 -0
- data/test/coverage/__-lib-contract-exception_rb.html +537 -0
- data/test/coverage/__-lib-contract-integration_rb.html +946 -0
- data/test/coverage/__-lib-contract-overrides_rb.html +483 -0
- data/test/coverage/__-lib-contract_rb.html +583 -0
- data/test/coverage/index.html +93 -0
- data/test/tc_all.rb +8 -0
- data/test/tc_contract.rb +109 -0
- data/test/tc_exception.rb +43 -0
- data/test/tc_integration.rb +357 -0
- metadata +136 -0
@@ -0,0 +1,724 @@
|
|
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.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.rb</tt></td></tr>
|
425
|
+
<tr><td>total coverage</td><td>48.9</td></tr>
|
426
|
+
<tr><td>code coverage</td><td>47.5</td></tr>
|
427
|
+
</table>
|
428
|
+
</div>
|
429
|
+
<pre><span class="inferred"> 1 # Contains the main implementation of the Contract class.
|
430
|
+
2 # :main:Contract
|
431
|
+
3
|
432
|
+
</span><span class="marked"> 4 require 'test/unit/testcase'
|
433
|
+
5 require 'test/unit/testresult'
|
434
|
+
6 require 'test/unit/testsuite'
|
435
|
+
</span><span class="inferred"> 7
|
436
|
+
</span><span class="marked"> 8 require 'contract/exception'
|
437
|
+
9 require 'contract/overrides'
|
438
|
+
10 require 'contract/assertions'
|
439
|
+
11 require 'contract/integration'
|
440
|
+
</span><span class="inferred"> 12
|
441
|
+
13 # Represents a contract between Objects as a collection of test cases.
|
442
|
+
14 # Objects are said to fulfill a contract if all test cases suceed. This
|
443
|
+
15 # is useful for ensuring that Objects your code is getting behave in a
|
444
|
+
16 # way that you expect them to behave so you can fail early or execute
|
445
|
+
17 # different logic for Objects with different interfaces.
|
446
|
+
18 #
|
447
|
+
19 # The tests of the test suite will be run on a copy of the tested Object
|
448
|
+
20 # so you can safely test its behavior without having to fear data loss.
|
449
|
+
21 # By default Contracts obtain deep copies of Objects by serializing and
|
450
|
+
22 # unserializing them with Ruby's +Marshal+ functionality. This will work
|
451
|
+
23 # in most cases but can fail for Objects containing unserializable parts
|
452
|
+
24 # like Procs, Files or Sockets. In those cases it is currently of your
|
453
|
+
25 # responsibility to provide a fitting implementation by overwriting the
|
454
|
+
26 # Contract.deep_copy method. In the future the contract library might
|
455
|
+
27 # provide different implementations of it via Ruby's mixin mechanism.
|
456
|
+
</span><span class="marked"> 28 class Contract < Test::Unit::TestCase
|
457
|
+
29 id = %q$Id: contract.rb 110 2005-02-05 22:33:56Z flgr $
|
458
|
+
</span><span class="inferred"> 30 # The Version of the contract library you are using.
|
459
|
+
</span><span class="marked"> 31 Version = id.split(" ")[2].to_i unless defined?(Version)
|
460
|
+
</span><span class="inferred"> 32
|
461
|
+
33 # Returns true if the given object fulfills this contract.
|
462
|
+
34 # This is useful for implementing dispatching mechanisms where you
|
463
|
+
35 # want to hit different code branches based on whether an Object has
|
464
|
+
36 # one or another interface.
|
465
|
+
</span><span class="marked"> 37 def self.fulfilled_by?(object)
|
466
|
+
38 self.test(object).nil?
|
467
|
+
</span><span class="inferred"> 39 end
|
468
|
+
40
|
469
|
+
</span><span class="marked"> 41 class << self
|
470
|
+
</span><span class="inferred"> 42 # You can use contracts in +case+ ... +when+ statements or in
|
471
|
+
43 # Module#signature checks. For example:
|
472
|
+
44 # case obj
|
473
|
+
45 # when Numeric then obj + 1
|
474
|
+
46 # when ListContract then obj + [1]
|
475
|
+
47 # end
|
476
|
+
</span><span class="marked"> 48 alias :=== :fulfilled_by?
|
477
|
+
</span><span class="inferred"> 49 end
|
478
|
+
50
|
479
|
+
51 # Enforces that object implements this contract. If it does not an
|
480
|
+
52 # Exception will be raised. This is useful for example useful when you
|
481
|
+
53 # need to ensure that the arguments given to a method fulfill a given
|
482
|
+
54 # contract.
|
483
|
+
55 #
|
484
|
+
56 # Note that using Module#enforce is a higher-level way of checking
|
485
|
+
57 # arguments and return values for the conformance of a given type. You
|
486
|
+
58 # might however still want to use Contract.enforce directly when you
|
487
|
+
59 # need more flexibility.
|
488
|
+
</span><span class="marked"> 60 def self.enforce(object)
|
489
|
+
61 reason = self.test(object)
|
490
|
+
62 raise reason if reason
|
491
|
+
</span><span class="inferred"> 63 end
|
492
|
+
64
|
493
|
+
65 # Tests whether the given Object fulfils this contract.
|
494
|
+
66 #
|
495
|
+
67 # Note: This will return the first reason for the Object not fulfilling
|
496
|
+
68 # the contract or +nil+ in case it fulfills it.
|
497
|
+
</span><span class="marked"> 69 def self.test(object, return_all = false)
|
498
|
+
70 reasons = []
|
499
|
+
</span><span class="inferred"> 71
|
500
|
+
</span><span class="marked"> 72 result = Test::Unit::TestResult.new
|
501
|
+
73 result.add_listener(Test::Unit::TestResult::FAULT) do |fault|
|
502
|
+
74 reason = Contract.fault_to_exception(fault, object, self)
|
503
|
+
75 return reason unless return_all
|
504
|
+
76 reasons << reason
|
505
|
+
</span><span class="inferred"> 77 end
|
506
|
+
78
|
507
|
+
</span><span class="marked"> 79 self.suite.run(result, deep_copy(object))
|
508
|
+
</span><span class="inferred"> 80
|
509
|
+
</span><span class="marked"> 81 return reasons unless result.passed?
|
510
|
+
</span><span class="inferred"> 82 end
|
511
|
+
83
|
512
|
+
84 # Same as Contract.test, but will return all reasons for the Object not
|
513
|
+
85 # fulfilling the contract in an Array or nil in case of fulfillment.
|
514
|
+
86 # (as an Array of Exceptions) or +nil+ in the case it does fulfill it.
|
515
|
+
</span><span class="marked"> 87 def self.test_all(object)
|
516
|
+
88 test(object, true)
|
517
|
+
</span><span class="inferred"> 89 end
|
518
|
+
90
|
519
|
+
91 # This method is used internally for getting a copy of Objects that
|
520
|
+
92 # the contract is checked against. By default it uses Ruby's +Marshal+
|
521
|
+
93 # functionality for obtaining a copy, but this can fail if the Object
|
522
|
+
94 # contains unserializable parts like Procs, Files or Sockets. It is
|
523
|
+
95 # currently your responsibility to provide a fitting implementation
|
524
|
+
96 # of this by overwriting the method in case the default implementation
|
525
|
+
97 # does not work for you. In the future the contract library might offer
|
526
|
+
98 # different implementations for this via Ruby's mixin mechanism.
|
527
|
+
</span><span class="marked"> 99 def self.deep_copy(object)
|
528
|
+
100 Marshal.load(Marshal.dump(object))
|
529
|
+
</span><span class="inferred">101 end
|
530
|
+
102
|
531
|
+
103 # Fulfilling this Contract (via Module#fulfills) implies that the Object
|
532
|
+
104 # is automatically compatible with the specified mixins which will then
|
533
|
+
105 # be included automatically. For example the Enumerable relationship
|
534
|
+
106 # could be expressed like this:
|
535
|
+
107 #
|
536
|
+
108 # class EnumerableContract < Contract
|
537
|
+
109 # provides :each
|
538
|
+
110 # implies Enumerable
|
539
|
+
111 # end
|
540
|
+
</span><span class="marked">112 def self.implies(*mixins)
|
541
|
+
113 mixins.each do |mixin|
|
542
|
+
114 if not mixin.is_a?(Module) then
|
543
|
+
115 raise(TypeError, "wrong argument type #{mixin.class} for " +
|
544
|
+
</span><span class="inferred">116 "#{mixin.inspect} (expected Module)")
|
545
|
+
117 end
|
546
|
+
118 end
|
547
|
+
119
|
548
|
+
</span><span class="marked">120 @implications ||= Array.new
|
549
|
+
121 @implications += mixins
|
550
|
+
</span><span class="inferred">122 end
|
551
|
+
123
|
552
|
+
</span><span class="marked">124 class << self
|
553
|
+
</span><span class="inferred">125 # Returns all implications of a given contract that were stated via
|
554
|
+
126 # calling Contract.implies.
|
555
|
+
</span><span class="marked">127 attr_reader :implications
|
556
|
+
</span><span class="inferred">128 end
|
557
|
+
129
|
558
|
+
</span><span class="marked">130 def self.implications() # :nodoc:
|
559
|
+
131 @implications ||= Array.new
|
560
|
+
</span><span class="inferred">132
|
561
|
+
</span><span class="marked">133 ancestors[1 .. -1].inject(@implications) do |result, ancestor|
|
562
|
+
134 if ancestor.respond_to?(:implications) then
|
563
|
+
135 ancestor.implications + result
|
564
|
+
</span><span class="inferred">136 else
|
565
|
+
</span><span class="marked">137 result
|
566
|
+
</span><span class="inferred">138 end
|
567
|
+
</span><span class="false">139 end.uniq
|
568
|
+
140 end
|
569
|
+
141 end
|
570
|
+
142 # Contains the main implementation of the Contract class.
|
571
|
+
143 # :main:Contract
|
572
|
+
144
|
573
|
+
145 require 'test/unit/testcase'
|
574
|
+
146 require 'test/unit/testresult'
|
575
|
+
147 require 'test/unit/testsuite'
|
576
|
+
148
|
577
|
+
149 require 'contract/exception'
|
578
|
+
150 require 'contract/overrides'
|
579
|
+
151 require 'contract/assertions'
|
580
|
+
152 require 'contract/integration'
|
581
|
+
153
|
582
|
+
154 # Represents a contract between Objects as a collection of test cases.
|
583
|
+
155 # Objects are said to fulfill a contract if all test cases suceed. This
|
584
|
+
156 # is useful for ensuring that Objects your code is getting behave in a
|
585
|
+
157 # way that you expect them to behave so you can fail early or execute
|
586
|
+
158 # different logic for Objects with different interfaces.
|
587
|
+
159 #
|
588
|
+
160 # The tests of the test suite will be run on a copy of the tested Object
|
589
|
+
161 # so you can safely test its behavior without having to fear data loss.
|
590
|
+
162 # By default Contracts obtain deep copies of Objects by serializing and
|
591
|
+
163 # unserializing them with Ruby's +Marshal+ functionality. This will work
|
592
|
+
164 # in most cases but can fail for Objects containing unserializable parts
|
593
|
+
165 # like Procs, Files or Sockets. In those cases it is currently of your
|
594
|
+
166 # responsibility to provide a fitting implementation by overwriting the
|
595
|
+
167 # Contract.deep_copy method. In the future the contract library might
|
596
|
+
168 # provide different implementations of it via Ruby's mixin mechanism.
|
597
|
+
169 class Contract < Test::Unit::TestCase
|
598
|
+
170 id = %q$Id: contract.rb 110 2005-02-05 22:33:56Z flgr $
|
599
|
+
171 # The Version of the contract library you are using.
|
600
|
+
172 Version = id.split(" ")[2].to_i unless defined?(Version)
|
601
|
+
173
|
602
|
+
174 # Returns true if the given object fulfills this contract.
|
603
|
+
175 # This is useful for implementing dispatching mechanisms where you
|
604
|
+
176 # want to hit different code branches based on whether an Object has
|
605
|
+
177 # one or another interface.
|
606
|
+
178 def self.fulfilled_by?(object)
|
607
|
+
179 self.test(object).nil?
|
608
|
+
180 end
|
609
|
+
181
|
610
|
+
182 class << self
|
611
|
+
183 # You can use contracts in +case+ ... +when+ statements or in
|
612
|
+
184 # Module#signature checks. For example:
|
613
|
+
185 # case obj
|
614
|
+
186 # when Numeric then obj + 1
|
615
|
+
187 # when ListContract then obj + [1]
|
616
|
+
188 # end
|
617
|
+
189 alias :=== :fulfilled_by?
|
618
|
+
190 end
|
619
|
+
191
|
620
|
+
192 # Enforces that object implements this contract. If it does not an
|
621
|
+
193 # Exception will be raised. This is useful for example useful when you
|
622
|
+
194 # need to ensure that the arguments given to a method fulfill a given
|
623
|
+
195 # contract.
|
624
|
+
196 #
|
625
|
+
197 # Note that using Module#enforce is a higher-level way of checking
|
626
|
+
198 # arguments and return values for the conformance of a given type. You
|
627
|
+
199 # might however still want to use Contract.enforce directly when you
|
628
|
+
200 # need more flexibility.
|
629
|
+
201 def self.enforce(object)
|
630
|
+
202 reason = self.test(object)
|
631
|
+
203 raise reason if reason
|
632
|
+
204 end
|
633
|
+
205
|
634
|
+
206 # Tests whether the given Object fulfils this contract.
|
635
|
+
207 #
|
636
|
+
208 # Note: This will return the first reason for the Object not fulfilling
|
637
|
+
209 # the contract or +nil+ in case it fulfills it.
|
638
|
+
210 def self.test(object, return_all = false)
|
639
|
+
211 reasons = []
|
640
|
+
212
|
641
|
+
213 result = Test::Unit::TestResult.new
|
642
|
+
214 result.add_listener(Test::Unit::TestResult::FAULT) do |fault|
|
643
|
+
215 reason = Contract.fault_to_exception(fault, object, self)
|
644
|
+
216 return reason unless return_all
|
645
|
+
217 reasons << reason
|
646
|
+
218 end
|
647
|
+
219
|
648
|
+
220 self.suite.run(result, deep_copy(object))
|
649
|
+
221
|
650
|
+
222 return reasons unless result.passed?
|
651
|
+
223 end
|
652
|
+
224
|
653
|
+
225 # Same as Contract.test, but will return all reasons for the Object not
|
654
|
+
226 # fulfilling the contract in an Array or nil in case of fulfillment.
|
655
|
+
227 # (as an Array of Exceptions) or +nil+ in the case it does fulfill it.
|
656
|
+
228 def self.test_all(object)
|
657
|
+
229 test(object, true)
|
658
|
+
230 end
|
659
|
+
231
|
660
|
+
232 # This method is used internally for getting a copy of Objects that
|
661
|
+
233 # the contract is checked against. By default it uses Ruby's +Marshal+
|
662
|
+
234 # functionality for obtaining a copy, but this can fail if the Object
|
663
|
+
235 # contains unserializable parts like Procs, Files or Sockets. It is
|
664
|
+
236 # currently your responsibility to provide a fitting implementation
|
665
|
+
237 # of this by overwriting the method in case the default implementation
|
666
|
+
238 # does not work for you. In the future the contract library might offer
|
667
|
+
239 # different implementations for this via Ruby's mixin mechanism.
|
668
|
+
240 def self.deep_copy(object)
|
669
|
+
241 Marshal.load(Marshal.dump(object))
|
670
|
+
242 end
|
671
|
+
243
|
672
|
+
244 # Fulfilling this Contract (via Module#fulfills) implies that the Object
|
673
|
+
245 # is automatically compatible with the specified mixins which will then
|
674
|
+
246 # be included automatically. For example the Enumerable relationship
|
675
|
+
247 # could be expressed like this:
|
676
|
+
248 #
|
677
|
+
249 # class EnumerableContract < Contract
|
678
|
+
250 # provides :each
|
679
|
+
251 # implies Enumerable
|
680
|
+
252 # end
|
681
|
+
253 def self.implies(*mixins)
|
682
|
+
254 mixins.each do |mixin|
|
683
|
+
255 if not mixin.is_a?(Module) then
|
684
|
+
256 raise(TypeError, "wrong argument type #{mixin.class} for " +
|
685
|
+
257 "#{mixin.inspect} (expected Module)")
|
686
|
+
258 end
|
687
|
+
259 end
|
688
|
+
260
|
689
|
+
261 @implications ||= Array.new
|
690
|
+
262 @implications += mixins
|
691
|
+
263 end
|
692
|
+
264
|
693
|
+
265 class << self
|
694
|
+
266 # Returns all implications of a given contract that were stated via
|
695
|
+
267 # calling Contract.implies.
|
696
|
+
268 attr_reader :implications
|
697
|
+
269 end
|
698
|
+
270
|
699
|
+
271 def self.implications() # :nodoc:
|
700
|
+
272 @implications ||= Array.new
|
701
|
+
273
|
702
|
+
274 ancestors[1 .. -1].inject(@implications) do |result, ancestor|
|
703
|
+
275 if ancestor.respond_to?(:implications) then
|
704
|
+
276 ancestor.implications + result
|
705
|
+
277 else
|
706
|
+
278 result
|
707
|
+
279 end
|
708
|
+
280 end.uniq
|
709
|
+
281 end
|
710
|
+
282 end
|
711
|
+
</span></pre>
|
712
|
+
<hr />
|
713
|
+
<p>
|
714
|
+
<a href="http://validator.w3.org/check/referer">
|
715
|
+
<img src="http://www.w3.org/Icons/valid-xhtml11"
|
716
|
+
alt="Valid XHTML 1.1!" height="31" width="88" />
|
717
|
+
</a>
|
718
|
+
<a href="http://jigsaw.w3.org/css-validator/">
|
719
|
+
<img style="border:0;width:88px;height:31px"
|
720
|
+
src="http://jigsaw.w3.org/css-validator/images/vcss"
|
721
|
+
alt="Valid CSS!" />
|
722
|
+
</a>
|
723
|
+
</p>
|
724
|
+
</body></html>
|