handshake 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ # Copyright (c) 2004-2006 David Heinemeier Hansson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
23
+ # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
24
+ # to, for example, an array without those additions being shared with either their parent, siblings, or
25
+ # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
26
+ class Class # :nodoc:
27
+ def class_inheritable_reader(*syms)
28
+ syms.each do |sym|
29
+ class_eval <<-EOS
30
+ def self.#{sym}
31
+ read_inheritable_attribute(:#{sym})
32
+ end
33
+
34
+ def #{sym}
35
+ self.class.#{sym}
36
+ end
37
+ EOS
38
+ end
39
+ end
40
+
41
+ def class_inheritable_writer(*syms)
42
+ syms.each do |sym|
43
+ class_eval <<-EOS
44
+ def self.#{sym}=(obj)
45
+ write_inheritable_attribute(:#{sym}, obj)
46
+ end
47
+
48
+ def #{sym}=(obj)
49
+ self.class.#{sym} = obj
50
+ end
51
+ EOS
52
+ end
53
+ end
54
+
55
+ def class_inheritable_array_writer(*syms)
56
+ syms.each do |sym|
57
+ class_eval <<-EOS
58
+ def self.#{sym}=(obj)
59
+ write_inheritable_array(:#{sym}, obj)
60
+ end
61
+
62
+ def #{sym}=(obj)
63
+ self.class.#{sym} = obj
64
+ end
65
+ EOS
66
+ end
67
+ end
68
+
69
+ def class_inheritable_hash_writer(*syms)
70
+ syms.each do |sym|
71
+ class_eval <<-EOS
72
+ def self.#{sym}=(obj)
73
+ write_inheritable_hash(:#{sym}, obj)
74
+ end
75
+
76
+ def #{sym}=(obj)
77
+ self.class.#{sym} = obj
78
+ end
79
+ EOS
80
+ end
81
+ end
82
+
83
+ def class_inheritable_accessor(*syms)
84
+ class_inheritable_reader(*syms)
85
+ class_inheritable_writer(*syms)
86
+ end
87
+
88
+ def class_inheritable_array(*syms)
89
+ class_inheritable_reader(*syms)
90
+ class_inheritable_array_writer(*syms)
91
+ end
92
+
93
+ def class_inheritable_hash(*syms)
94
+ class_inheritable_reader(*syms)
95
+ class_inheritable_hash_writer(*syms)
96
+ end
97
+
98
+ def inheritable_attributes
99
+ @inheritable_attributes ||= {}
100
+ end
101
+
102
+ def write_inheritable_attribute(key, value)
103
+ inheritable_attributes[key] = value
104
+ end
105
+
106
+ def write_inheritable_array(key, elements)
107
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
108
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
109
+ end
110
+
111
+ def write_inheritable_hash(key, hash)
112
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
113
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
114
+ end
115
+
116
+ def read_inheritable_attribute(key)
117
+ inheritable_attributes[key]
118
+ end
119
+
120
+ def reset_inheritable_attributes
121
+ inheritable_attributes.clear
122
+ end
123
+
124
+ private
125
+ def inherited_with_inheritable_attributes(child)
126
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
127
+ child.instance_variable_set('@inheritable_attributes', inheritable_attributes.dup)
128
+ end
129
+
130
+ alias inherited_without_inheritable_attributes inherited
131
+ alias inherited inherited_with_inheritable_attributes
132
+ end
@@ -0,0 +1,8 @@
1
+ module Handshake # :nodoc:
2
+ module VERSION # :nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+ STRING = [MAJOR, MINOR, TINY].join('.')
7
+ end
8
+ end
data/lib/handshake.rb ADDED
@@ -0,0 +1 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'handshake/**/*.rb')].sort.each { |lib| require lib }
@@ -0,0 +1,494 @@
1
+ # test_handshake.rb
2
+ # Copyright (c) 2007 Brian Guthrie
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'test/unit'
24
+ require 'handshake'
25
+
26
+ class TestContract < Test::Unit::TestCase
27
+
28
+ class InvariantDeclarations
29
+ include Handshake
30
+ invariant { true }
31
+ end
32
+
33
+ class ExtendsInvariantDeclarations < InvariantDeclarations
34
+ invariant { true }
35
+ end
36
+
37
+ def test_invariant_declarations
38
+ assert_equal 1, InvariantDeclarations.invariants.length
39
+ assert_equal 2, ExtendsInvariantDeclarations.invariants.length
40
+ end
41
+
42
+ class NonFunctionalArray < Array
43
+ include Handshake
44
+ invariant { false }
45
+ end
46
+
47
+ def test_basic_invariant
48
+ assert_violation { NonFunctionalArray.new }
49
+ end
50
+
51
+ class NonEmptyArray < Array
52
+ include Handshake
53
+ invariant { not empty? }
54
+ end
55
+ class ExtendsNonEmptyArray < NonEmptyArray; end
56
+
57
+ class PositiveBalance
58
+ include Handshake
59
+ invariant { @balance > 0 }
60
+ attr_accessor :balance
61
+ def initialize(balance); @balance = balance; end
62
+ end
63
+
64
+ def test_invariants
65
+ assert_violation { NonEmptyArray.new }
66
+ assert_passes { NonEmptyArray.new [1] }
67
+ assert_violation { ExtendsNonEmptyArray.new }
68
+ assert_passes { ExtendsNonEmptyArray.new [1] }
69
+
70
+ assert_violation { NonEmptyArray.new([1]).pop }
71
+
72
+ assert_violation { PositiveBalance.new -10 }
73
+ assert_violation { PositiveBalance.new 0 }
74
+ assert_passes { PositiveBalance.new 10 }
75
+ assert_violation {
76
+ pb = PositiveBalance.new(10); pb.balance = -10
77
+ }
78
+ end
79
+
80
+ class MethodDeclarations
81
+ include Handshake
82
+ contract :accepts_str, String => anything
83
+ contract :accepts_int, Integer => anything
84
+ def accepts_str(str); str; end
85
+ def accepts_int(int); int; end
86
+ end
87
+ class ExtendsMethodDeclarations < MethodDeclarations; end
88
+
89
+ def test_method_declarations
90
+ assert MethodDeclarations.method_contracts.has_key?(:accepts_str)
91
+ assert MethodDeclarations.method_contracts.has_key?(:accepts_int)
92
+ assert ExtendsMethodDeclarations.method_contracts.has_key?(:accepts_str)
93
+ assert ExtendsMethodDeclarations.method_contracts.has_key?(:accepts_int)
94
+ end
95
+
96
+ class AcceptsString
97
+ include Handshake
98
+ contract :initialize, String => anything
99
+ def initialize(str); @str = str; end
100
+ contract String => anything
101
+ def str=(str); @str = str; end
102
+ end
103
+ class ExtendsAcceptsString < AcceptsString; end
104
+ class AcceptsIntegerInstead < AcceptsString
105
+ contract :initialize, Integer => anything
106
+ end
107
+ class AcceptsSymbolInstead < AcceptsString
108
+ contract :initialize, Symbol => anything
109
+ end
110
+
111
+ def test_method_accepts
112
+ assert_violation { AcceptsString.new 3 }
113
+ assert_violation { AcceptsString.new :foo }
114
+ assert_passes { AcceptsString.new "string" }
115
+ assert_violation { AcceptsString.new("foo").str = 3 }
116
+ assert_violation { ExtendsAcceptsString.new 3 }
117
+ assert_violation { ExtendsAcceptsString.new :foo }
118
+ assert_passes { ExtendsAcceptsString.new "string" }
119
+ assert_violation { ExtendsAcceptsString.new("foo").str = 3 }
120
+ assert_violation { AcceptsIntegerInstead.new("foo") }
121
+ assert_passes { AcceptsIntegerInstead.new 3 }
122
+ assert_violation { AcceptsSymbolInstead.new "foo" }
123
+ assert_violation { AcceptsSymbolInstead.new 3 }
124
+ assert_passes { AcceptsSymbolInstead.new :foo }
125
+ end
126
+
127
+ class ReturnsString
128
+ include Handshake
129
+ contract String => anything
130
+ def call(val); val; end
131
+ end
132
+ class ExtendsReturnsString < ReturnsString; end
133
+
134
+ def test_method_returns
135
+ assert_violation { ReturnsString.new.call(1) }
136
+ assert_violation { ReturnsString.new.call(true) }
137
+ assert_passes { ReturnsString.new.call("foo") }
138
+ assert_violation { ExtendsReturnsString.new.call(1) }
139
+ assert_violation { ExtendsReturnsString.new.call(true) }
140
+ assert_passes { ExtendsReturnsString.new.call("foo") }
141
+ end
142
+
143
+ class ReturnsMultiple
144
+ include Handshake
145
+ contract [ String, Integer ] => anything
146
+ def call(arg1, arg2); return arg1, arg2; end
147
+ end
148
+
149
+ def test_method_returns_multiple
150
+ assert_violation { ReturnsMultiple.new.call("foo", "foo") }
151
+ assert_violation { ReturnsMultiple.new.call(3, 3) }
152
+ assert_passes { ReturnsMultiple.new.call("foo", 3) }
153
+ end
154
+
155
+ class AcceptsVarargs
156
+ include Handshake
157
+ contract [[ String ]] => anything
158
+ def initialize(*strs); @strs = strs; end
159
+ end
160
+
161
+ def test_method_accepts_varargs
162
+ assert_passes { AcceptsVarargs.new }
163
+ assert_violation { AcceptsVarargs.new(1, 2, 3) }
164
+ assert_violation { AcceptsVarargs.new("foo", 1, 2) }
165
+ assert_violation { AcceptsVarargs.new(:foo, "foo") }
166
+ assert_passes { AcceptsVarargs.new("foo") }
167
+ assert_passes { AcceptsVarargs.new("foo1", "foo2") }
168
+ end
169
+
170
+ class AcceptsBlock
171
+ include Handshake
172
+ contract Block => anything
173
+ def call1; end
174
+ contract Block => anything
175
+ def call2(&block); end
176
+ end
177
+
178
+ def test_method_accepts_block
179
+ assert_violation { AcceptsBlock.new.call1 }
180
+ assert_violation { AcceptsBlock.new.call2 }
181
+ assert_passes { AcceptsBlock.new.call1 { true } }
182
+ assert_passes { AcceptsBlock.new.call2 { true } }
183
+ assert_passes { AcceptsBlock.new.call1 { "foo" } }
184
+ assert_violation { AcceptsBlock.new.call1("foo") }
185
+ assert_violation { AcceptsBlock.new.call2("foo") }
186
+ end
187
+
188
+ class AcceptsWriter
189
+ include Handshake
190
+ contract String => anything
191
+ def val=(str); @str = str; end
192
+ end
193
+
194
+ def test_writer_method_accepts_str
195
+ assert_violation { AcceptsWriter.new.val = 3 }
196
+ assert_violation { AcceptsWriter.new.val = :foo }
197
+ assert_passes { AcceptsWriter.new.val = "foo" }
198
+ end
199
+
200
+ # EXCELSIOR!
201
+ class AcceptsMixed
202
+ include Handshake
203
+ contract [ String, String, [ Integer ], Block ] => String
204
+ def call(str1, str2, *ints, &block); "foo"; end
205
+ end
206
+
207
+ def test_method_mixed
208
+ assert_violation { AcceptsMixed.new.call }
209
+ assert_violation { AcceptsMixed.new.call 3 }
210
+ assert_violation { AcceptsMixed.new.call "foo" }
211
+ assert_violation { AcceptsMixed.new.call "foo", 3 }
212
+ assert_violation { AcceptsMixed.new.call "foo", "bar" }
213
+ assert_passes { AcceptsMixed.new.call("foo", "bar") { true } }
214
+ assert_passes { AcceptsMixed.new.call("foo", "bar", 3) { true } }
215
+ assert_passes { AcceptsMixed.new.call("foo", "bar", 3, 4, 5) { true } }
216
+ end
217
+
218
+ class AcceptsSimpleAssertion
219
+ include Handshake
220
+ equals_foo = clause {|o| o == "foo"}
221
+ contract [ equals_foo ] => anything
222
+ def call(foo)
223
+ return foo
224
+ end
225
+ end
226
+
227
+ def test_method_simple_assertion
228
+ assert_violation { AcceptsSimpleAssertion.new.call }
229
+ assert_violation { AcceptsSimpleAssertion.new.call 3 }
230
+ assert_violation { AcceptsSimpleAssertion.new.call "bar", "bar" }
231
+ assert_passes { AcceptsSimpleAssertion.new.call "foo" }
232
+ end
233
+
234
+ class AcceptsAll
235
+ include Handshake
236
+ equals_five = clause {|o| o == 5}
237
+ contract all?(Integer, equals_five) => anything
238
+ def initialize(n); end
239
+ end
240
+
241
+ def test_accepts_all_of
242
+ assert_violation { AcceptsAll.new "foo" }
243
+ assert_violation { AcceptsAll.new 3 }
244
+ assert_violation { AcceptsAll.new 5.0 }
245
+ assert_passes { AcceptsAll.new 5 }
246
+ end
247
+
248
+ class AcceptsAny
249
+ include Handshake
250
+ equals_five = clause {|o| o == 5}
251
+ equals_three = clause {|o| o == 3}
252
+ contract any?(equals_five, equals_three) => anything
253
+ def three_or_five(n); end
254
+ contract any?(String, Integer, Symbol) => anything
255
+ def str_int_sym(o); end
256
+ end
257
+
258
+ def test_accepts_any_of
259
+ assert_violation { AcceptsAny.new.three_or_five "foo" }
260
+ assert_violation { AcceptsAny.new.three_or_five 7 }
261
+ assert_violation { AcceptsAny.new.three_or_five 8, 9 }
262
+ assert_passes { AcceptsAny.new.three_or_five 3 }
263
+ assert_passes { AcceptsAny.new.three_or_five 5 }
264
+
265
+ assert_violation { AcceptsAny.new.str_int_sym 5.3 }
266
+ assert_raises(ArgumentError) { AcceptsAny.new.str_int_sym "str", 3, :sym }
267
+ assert_passes { AcceptsAny.new.str_int_sym "str" }
268
+ assert_passes { AcceptsAny.new.str_int_sym 3 }
269
+ assert_passes { AcceptsAny.new.str_int_sym :foo }
270
+ end
271
+
272
+ class AcceptsNot
273
+ include Handshake
274
+ contract not?(String) => anything
275
+ def initialize(not_str); end
276
+ end
277
+
278
+ def test_accepts_not_string
279
+ assert_violation { AcceptsNot.new "string" }
280
+ assert_passes { AcceptsNot.new 3 }
281
+ assert_passes { AcceptsNot.new :symbol }
282
+ end
283
+
284
+ class AcceptsBoolean
285
+ include Handshake
286
+ contract boolean? => anything
287
+ def initialize(bool); end
288
+ end
289
+
290
+ def test_accepts_boolean
291
+ assert_violation { AcceptsBoolean.new "foo" }
292
+ assert_violation { AcceptsBoolean.new :foo }
293
+ assert_passes { AcceptsBoolean.new true }
294
+ assert_passes { AcceptsBoolean.new false }
295
+ end
296
+
297
+ class AcceptsNonzero
298
+ include Handshake
299
+ contract nonzero? => anything
300
+ def initialize(nonzero); end
301
+ end
302
+
303
+ def test_accepts_nonzero
304
+ assert_violation { AcceptsNonzero.new :foo }
305
+ assert_violation { AcceptsNonzero.new 0 }
306
+ assert_passes { AcceptsNonzero.new 3 }
307
+ end
308
+
309
+ class AcceptsHashOf
310
+ include Handshake
311
+ contract hash_of?(Symbol, String) => anything
312
+ def initialize(arg={}); end
313
+ end
314
+
315
+ def test_hash_of_sym_string
316
+ assert_passes { AcceptsHashOf.new({}) }
317
+ assert_passes { AcceptsHashOf.new({ :symbol => "String" }) }
318
+ assert_violation { AcceptsHashOf.new({ :another => :symbol }) }
319
+ assert_violation { AcceptsHashOf.new({ "two" => "strings" }) }
320
+ assert_violation { AcceptsHashOf.new({ false => true }) }
321
+ end
322
+
323
+ class AcceptsHashWithKeys
324
+ include Handshake
325
+ contract hash_with_keys(:foo, :bar) => anything
326
+ def initialize(options={}); end
327
+ end
328
+
329
+ def test_hash_with_keys_foo_bar
330
+ assert_passes { AcceptsHashWithKeys.new({}) }
331
+ assert_passes { AcceptsHashWithKeys.new({ :foo => "anything" }) }
332
+ assert_passes { AcceptsHashWithKeys.new({ :bar => "anything" }) }
333
+ assert_passes { AcceptsHashWithKeys.new({ :foo => "anything", :bar => "goes" }) }
334
+ assert_violation { AcceptsHashWithKeys.new({ :arbitrary => "key" }) }
335
+ end
336
+
337
+ class AcceptsHashContract
338
+ include Handshake
339
+ contract hash_contract({ :foo => String, :bar => Integer, :baz => Symbol }) => anything
340
+ def initialize(options={}); end
341
+ end
342
+
343
+ def test_hash_contract
344
+ assert_passes { AcceptsHashContract.new({}) }
345
+ assert_passes { AcceptsHashContract.new({ :foo => "bar"}) }
346
+ assert_violation { AcceptsHashContract.new({ :foo => :bar}) }
347
+ assert_passes { AcceptsHashContract.new({ :bar => 3 }) }
348
+ assert_violation { AcceptsHashContract.new({ :bar => "foo" }) }
349
+ assert_passes { AcceptsHashContract.new({ :baz => :foo }) }
350
+ assert_violation { AcceptsHashContract.new({ :baz => "baz" }) }
351
+ assert_passes { AcceptsHashContract.new({ :foo => "bar", :bar => 3, :baz => :qux }) }
352
+ end
353
+
354
+ class AcceptsRespondsTo
355
+ include Handshake
356
+ contract responds_to?(:each, :first) => anything
357
+ def initialize(duck_array); end
358
+ end
359
+
360
+ def test_responds_to_each_first
361
+ assert_violation { AcceptsRespondsTo.new({}) }
362
+ assert_violation { AcceptsRespondsTo.new "foo" }
363
+ assert_violation { AcceptsRespondsTo.new 3 }
364
+ assert_passes { AcceptsRespondsTo.new([]) }
365
+ end
366
+
367
+ class AcceptsIsA
368
+ include Handshake
369
+ contract is?(:String) => is?(:Symbol)
370
+ def call_is_a(str); return str.intern; end
371
+ end
372
+
373
+ def test_accepts_is_string_symbol
374
+ assert_violation { AcceptsIsA.new.call_is_a(3) }
375
+ assert_violation { AcceptsIsA.new.call_is_a(:foo) }
376
+ assert_passes { AcceptsIsA.new.call_is_a("foo") }
377
+ end
378
+
379
+ class SimpleBeforeCondition
380
+ include Handshake
381
+ before { assert false }
382
+ def call_fails; end
383
+ def call_passes; end
384
+ end
385
+ class ExtendsSimpleBeforeCondition < SimpleBeforeCondition; end
386
+
387
+ def test_simple_before_condition
388
+ assert_equal(1, SimpleBeforeCondition.method_contracts.length)
389
+ assert_not_nil(SimpleBeforeCondition.method_contracts[:call_fails])
390
+ assert_violation { SimpleBeforeCondition.new.call_fails }
391
+ assert_passes { SimpleBeforeCondition.new.call_passes }
392
+ assert_equal(1, ExtendsSimpleBeforeCondition.method_contracts.length)
393
+ assert_not_nil(ExtendsSimpleBeforeCondition.method_contracts[:call_fails])
394
+ assert_violation { ExtendsSimpleBeforeCondition.new.call_fails }
395
+ assert_passes { ExtendsSimpleBeforeCondition.new.call_passes }
396
+ end
397
+
398
+ class SimpleAfterCondition
399
+ include Handshake
400
+ after { |accepted, returned| assert returned }
401
+ def call(bool); bool; end
402
+ end
403
+
404
+ def test_simple_after_condition
405
+ assert_equal(1, SimpleAfterCondition.method_contracts.length)
406
+ assert_not_nil(SimpleAfterCondition.method_contracts[:call])
407
+ assert_violation { SimpleAfterCondition.new.call(false) }
408
+ assert_violation { SimpleAfterCondition.new.call(nil) }
409
+ assert_passes { SimpleAfterCondition.new.call(true) }
410
+ assert_passes { SimpleAfterCondition.new.call("foo") }
411
+ end
412
+
413
+ class SimpleAroundCondition
414
+ include Handshake
415
+ around {|arg| assert(!arg) }
416
+ def call(bool); bool; end
417
+ end
418
+
419
+ def test_simple_around_condition
420
+ [ 1, :foo, true, false, "bar", 8.3, nil ].each do |val|
421
+ assert_violation { SimpleAroundCondition.new.call(val) }
422
+ end
423
+ end
424
+
425
+ class ScopedBeforeCondition
426
+ include Handshake
427
+ def initialize(bool); @bool = bool; end
428
+ before { assert @bool }
429
+ def call; end
430
+ end
431
+
432
+ def test_scoped_before_condition
433
+ assert_violation { ScopedBeforeCondition.new(false).call }
434
+ assert_passes { ScopedBeforeCondition.new(true).call }
435
+ end
436
+
437
+ class ContractAccessor
438
+ include Handshake
439
+ contract_reader :foo => String
440
+ contract_writer :bar => Integer
441
+ contract_accessor :baz => Symbol, :qux => Float
442
+ def initialize(foo=nil); @foo = foo; end
443
+ end
444
+
445
+ def test_contract_accessor
446
+ assert_equal(6, ContractAccessor.method_contracts.length)
447
+ assert_violation { ContractAccessor.new.foo }
448
+ assert_violation { ContractAccessor.new(3).foo }
449
+ assert_passes { ContractAccessor.new("foo").foo }
450
+ assert_violation { ContractAccessor.new.bar = "bar" }
451
+ assert_passes { ContractAccessor.new.bar = 3 }
452
+ assert_violation { ContractAccessor.new.baz = "3" }
453
+ assert_violation { ContractAccessor.new.qux = 3 }
454
+ assert_passes { ContractAccessor.new.baz = :baz }
455
+ assert_passes { ContractAccessor.new.qux = 3.3 }
456
+ end
457
+
458
+ class BeforeClauseAssert
459
+ include Handshake
460
+
461
+ before do |arg|
462
+ assert_equal("foo", arg, "arg must equal foo")
463
+ end; def call(arg)
464
+ arg
465
+ end
466
+ end
467
+
468
+ def test_before_clause_assert
469
+ assert_violation { BeforeClauseAssert.new.call 3 }
470
+ assert_violation { BeforeClauseAssert.new.call "bar" }
471
+ assert_passes { BeforeClauseAssert.new.call "foo" }
472
+ end
473
+
474
+ class Superclass
475
+ include Handshake
476
+ contract Superclass => boolean?
477
+ def ==(other); self.class === other; end
478
+ end
479
+
480
+ class Subclass < Superclass; end
481
+
482
+ class AcceptsSuperAndSub
483
+ include Handshake
484
+ contract Superclass => anything
485
+ def call(cls); cls; end
486
+ end
487
+
488
+ def test_accepts_super_and_sub
489
+ assert_violation { AcceptsSuperAndSub.new.call 3 }
490
+ assert_passes { AcceptsSuperAndSub.new.call Superclass.new }
491
+ assert_passes { AcceptsSuperAndSub.new.call Subclass.new }
492
+ assert_passes { Superclass.new == Subclass.new }
493
+ end
494
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: handshake
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-03-26 00:00:00 -04:00
8
+ summary: Handshake is a simple design-by-contract system for Ruby.
9
+ require_paths:
10
+ - lib
11
+ email: btguthrie@gmail.com
12
+ homepage: http://handshake.rubyforge.org
13
+ rubyforge_project: handshake
14
+ description: Handshake is a simple design-by-contract system for Ruby.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Brian Guthrie
31
+ files:
32
+ - Manifest.txt
33
+ - README
34
+ - MIT-LICENSE
35
+ - Rakefile
36
+ - lib/handshake.rb
37
+ - lib/handshake/handshake.rb
38
+ - lib/handshake/inheritable_attributes.rb
39
+ - lib/handshake/version.rb
40
+ - test/tc_handshake.rb
41
+ test_files:
42
+ - test/tc_handshake.rb
43
+ rdoc_options: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ requirements: []
52
+
53
+ dependencies: []
54
+