contracts 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- require 'benchmark'
1
+ require "benchmark"
2
2
 
3
3
  module Wrapper
4
4
  def self.extended(klass)
@@ -26,9 +26,9 @@ module Wrapper
26
26
  end
27
27
 
28
28
  class NotWrapped
29
- def add a, b
30
- a + b
31
- end
29
+ def add a, b
30
+ a + b
31
+ end
32
32
  end
33
33
 
34
34
  class Wrapped
@@ -38,22 +38,20 @@ class Wrapped
38
38
  end
39
39
  end
40
40
 
41
-
42
41
  w = Wrapped.new
43
42
  nw = NotWrapped.new
44
- #p w.add(1, 4)
45
- #exit
43
+ # p w.add(1, 4)
44
+ # exit
46
45
  # 30 is the width of the output column
47
46
  Benchmark.bm 30 do |x|
48
- x.report 'wrapped' do
49
- 100000.times do |_|
47
+ x.report "wrapped" do
48
+ 100_000.times do |_|
50
49
  w.add(rand(1000), rand(1000))
51
50
  end
52
51
  end
53
- x.report 'not wrapped' do
54
- 100000.times do |_|
55
- nw.add(rand(1000), rand(1000))
52
+ x.report "not wrapped" do
53
+ 100_000.times do |_|
54
+ nw.add(rand(1000), rand(1000))
56
55
  end
57
56
  end
58
57
  end
59
-
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(__FILE__, '../lib/contracts/version'))
1
+ require File.expand_path(File.join(__FILE__, "../lib/contracts/version"))
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "contracts"
@@ -1,12 +1,12 @@
1
- require 'contracts/core_ext'
2
- require 'contracts/support'
3
- require 'contracts/method_reference'
4
- require 'contracts/errors'
5
- require 'contracts/decorators'
6
- require 'contracts/eigenclass'
7
- require 'contracts/builtin_contracts'
8
- require 'contracts/modules'
9
- require 'contracts/invariants'
1
+ require "contracts/builtin_contracts"
2
+ require "contracts/decorators"
3
+ require "contracts/eigenclass"
4
+ require "contracts/errors"
5
+ require "contracts/formatters"
6
+ require "contracts/invariants"
7
+ require "contracts/method_reference"
8
+ require "contracts/modules"
9
+ require "contracts/support"
10
10
 
11
11
  module Contracts
12
12
  def self.included(base)
@@ -26,7 +26,7 @@ module Contracts
26
26
 
27
27
  base.instance_eval do
28
28
  def functype(funcname)
29
- contracts = self.decorated_methods[:class_methods][funcname]
29
+ contracts = decorated_methods[:class_methods][funcname]
30
30
  if contracts.nil?
31
31
  "No contract for #{self}.#{funcname}"
32
32
  else
@@ -39,6 +39,13 @@ module Contracts
39
39
  unless base.instance_of?(Module)
40
40
  def Contract(*args)
41
41
  return if ENV["NO_CONTRACTS"]
42
+ if self.class == Module
43
+ puts %{
44
+ Warning: You have added a Contract on a module function
45
+ without including Contracts::Modules. Your Contract will
46
+ just be ignored. Please include Contracts::Modules into
47
+ your module.}
48
+ end
42
49
  self.class.Contract(*args)
43
50
  end
44
51
  end
@@ -65,28 +72,51 @@ class Contract < Contracts::Decorator
65
72
  # Default implementation of failure_callback. Provided as a block to be able
66
73
  # to monkey patch #failure_callback only temporary and then switch it back.
67
74
  # First important usage - for specs.
68
- DEFAULT_FAILURE_CALLBACK = Proc.new do |data|
69
- raise data[:contracts].failure_exception.new(failure_msg(data), data)
75
+ DEFAULT_FAILURE_CALLBACK = proc do |data|
76
+ fail data[:contracts].failure_exception.new(failure_msg(data), data)
70
77
  end
71
78
 
72
79
  attr_reader :args_contracts, :ret_contract, :klass, :method
73
- # decorator_name :contract
74
80
  def initialize(klass, method, *contracts)
75
81
  if contracts[-1].is_a? Hash
76
82
  # internally we just convert that return value syntax back to an array
77
83
  @args_contracts = contracts[0, contracts.size - 1] + contracts[-1].keys
78
84
  @ret_contract = contracts[-1].values[0]
79
- @args_validators = @args_contracts.map do |contract|
80
- Contract.make_validator(contract)
81
- end
82
- @ret_validator = Contract.make_validator(@ret_contract)
83
85
  else
84
- fail "It looks like your contract for #{method} doesn't have a return value. A contract should be written as `Contract arg1, arg2 => return_value`."
86
+ fail %{
87
+ It looks like your contract for #{method} doesn't have a return value.
88
+ A contract should be written as `Contract arg1, arg2 => return_value`.
89
+ }.strip
90
+ end
91
+
92
+ @args_validators = args_contracts.map do |contract|
93
+ Contract.make_validator(contract)
85
94
  end
86
- @klass, @method= klass, method
87
- @has_func_contracts = args_contracts.index do |contract|
88
- contract.is_a? Contracts::Func
95
+
96
+ @args_contract_index = args_contracts.index do |contract|
97
+ contract.is_a? Contracts::Args
89
98
  end
99
+
100
+ @ret_validator = Contract.make_validator(ret_contract)
101
+
102
+ # == @has_proc_contract
103
+ last_contract = args_contracts.last
104
+ is_a_proc = last_contract.is_a?(Class) && (last_contract <= Proc || last_contract <= Method)
105
+
106
+ @has_proc_contract = is_a_proc || last_contract.is_a?(Contracts::Func)
107
+ # ====
108
+
109
+ # == @has_options_contract
110
+ last_contract = args_contracts.last
111
+ penultimate_contract = args_contracts[-2]
112
+ @has_options_contract = if @has_proc_contract
113
+ penultimate_contract.is_a?(Hash)
114
+ else
115
+ last_contract.is_a?(Hash)
116
+ end
117
+ # ===
118
+
119
+ @klass, @method = klass, method
90
120
  end
91
121
 
92
122
  def pretty_contract c
@@ -94,8 +124,8 @@ class Contract < Contracts::Decorator
94
124
  end
95
125
 
96
126
  def to_s
97
- args = @args_contracts.map { |c| pretty_contract(c) }.join(", ")
98
- ret = pretty_contract(@ret_contract)
127
+ args = args_contracts.map { |c| pretty_contract(c) }.join(", ")
128
+ ret = pretty_contract(ret_contract)
99
129
  ("#{args} => #{ret}").gsub("Contracts::", "")
100
130
  end
101
131
 
@@ -103,27 +133,22 @@ class Contract < Contracts::Decorator
103
133
  # This function is used by the default #failure_callback method
104
134
  # and uses the hash passed into the failure_callback method.
105
135
  def self.failure_msg(data)
106
- expected = if data[:contract].to_s == "" || data[:contract].is_a?(Hash)
107
- data[:contract].inspect
108
- else
109
- data[:contract].to_s
110
- end
111
-
112
- position = Contracts::Support.method_position(data[:method])
113
- method_name = Contracts::Support.method_name(data[:method])
114
-
115
- header = if data[:return_value]
116
- "Contract violation for return value:"
117
- else
118
- "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:"
119
- end
120
-
121
- %{#{header}
122
- Expected: #{expected},
123
- Actual: #{data[:arg].inspect}
124
- Value guarded in: #{data[:class]}::#{method_name}
125
- With Contract: #{data[:contracts]}
126
- At: #{position} }
136
+ expected = Contracts::Formatters::Expected.new(data[:contract]).contract
137
+ position = Contracts::Support.method_position(data[:method])
138
+ method_name = Contracts::Support.method_name(data[:method])
139
+
140
+ header = if data[:return_value]
141
+ "Contract violation for return value:"
142
+ else
143
+ "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:"
144
+ end
145
+
146
+ %{#{header}
147
+ Expected: #{expected},
148
+ Actual: #{data[:arg].inspect}
149
+ Value guarded in: #{data[:class]}::#{method_name}
150
+ With Contract: #{data[:contracts]}
151
+ At: #{position} }
127
152
  end
128
153
 
129
154
  # Callback for when a contract fails. By default it raises
@@ -139,7 +164,7 @@ class Contract < Contracts::Decorator
139
164
  # puts failure_msg(data)
140
165
  # exit
141
166
  # end
142
- def self.failure_callback(data, use_pattern_matching=true)
167
+ def self.failure_callback(data, use_pattern_matching = true)
143
168
  if data[:contracts].pattern_match? && use_pattern_matching
144
169
  return DEFAULT_FAILURE_CALLBACK.call(data)
145
170
  end
@@ -194,29 +219,29 @@ class Contract < Contracts::Decorator
194
219
  contract
195
220
  elsif klass == Array
196
221
  # e.g. [Num, String]
197
- # TODO account for these errors too
198
- lambda { |arg|
222
+ # TODO: account for these errors too
223
+ lambda do |arg|
199
224
  return false unless arg.is_a?(Array) && arg.length == contract.length
200
225
  arg.zip(contract).all? do |_arg, _contract|
201
226
  Contract.valid?(_arg, _contract)
202
227
  end
203
- }
228
+ end
204
229
  elsif klass == Hash
205
230
  # e.g. { :a => Num, :b => String }
206
- lambda { |arg|
231
+ lambda do |arg|
207
232
  return false unless arg.is_a?(Hash)
208
233
  contract.keys.all? do |k|
209
234
  Contract.valid?(arg[k], contract[k])
210
235
  end
211
- }
236
+ end
212
237
  elsif klass == Contracts::Args
213
- lambda { |arg|
238
+ lambda do |arg|
214
239
  Contract.valid?(arg, contract.contract)
215
- }
240
+ end
216
241
  elsif klass == Contracts::Func
217
- lambda { |arg|
242
+ lambda do |arg|
218
243
  arg.is_a?(Method) || arg.is_a?(Proc)
219
- }
244
+ end
220
245
  else
221
246
  # classes and everything else
222
247
  # e.g. Fixnum, Num
@@ -238,78 +263,111 @@ class Contract < Contracts::Decorator
238
263
  call_with(nil, *args, &blk)
239
264
  end
240
265
 
241
- def call_with(this, *args, &blk)
242
- _args = blk ? args + [blk] : args
243
-
244
- size = @args_contracts.size
266
+ # if we specified a proc in the contract but didn't pass one in,
267
+ # it's possible we are going to pass in a block instead. So lets
268
+ # append a nil to the list of args just so it doesn't fail.
245
269
 
246
- last_contract = @args_contracts.last
247
- proc_present = (Contracts::Func === last_contract ||
248
- (Class === last_contract && (last_contract <= Proc || last_contract <= Method)))
249
-
250
- _splat_index = proc_present ? -2 : -1
251
- splat_present = Contracts::Args === @args_contracts[_splat_index]
252
- splat_index = size + _splat_index
253
- splat_index += 1 unless splat_present
270
+ # a better way to handle this might be to take this into account
271
+ # before throwing a "mismatched # of args" error.
272
+ def maybe_append_block! args, blk
273
+ return unless @has_proc_contract && !blk &&
274
+ (@args_contract_index || args.size < args_contracts.size)
275
+ args << nil
276
+ end
254
277
 
255
- # Explicitly append blk=nil if nil != Proc contract violation
256
- # anticipated
257
- if proc_present && !blk && (splat_present || _args.size < size)
258
- _args << nil
278
+ # Same thing for when we have named params but didn't pass any in.
279
+ def maybe_append_options! args, blk
280
+ return unless @has_options_contract
281
+ if @has_proc_contract && args_contracts[-2].is_a?(Hash) && !args[-2].is_a?(Hash)
282
+ args.insert(-2, {})
283
+ elsif args_contracts[-1].is_a?(Hash) && !args[-1].is_a?(Hash)
284
+ args << {}
259
285
  end
286
+ end
260
287
 
261
- # Size of our iteration is either count of arguments or count of
262
- # contracts. Without splat - count of arguments, with splat -
263
- # min(count of contracts, count of arguments)
264
- _size = _args.size
265
- iteration_size = _size
266
- iteration_size = size if !splat_present && size < _size
267
-
268
- # check contracts on arguments
269
- # fun fact! This is significantly faster than .zip (3.7 secs vs 4.7 secs). Why??
270
-
271
- # times is faster than (0..args.size).each
272
- iteration_size.times do |i|
273
- # this is done to account for extra args (for *args)
274
- j = i > splat_index ? splat_index : i
275
- j = size - 1 if i == _size - 1 && proc_present
276
- #unless true #@args_contracts[i].valid?(args[i])
277
- unless @args_validators[j][_args[i]]
278
- call_function = Contract.failure_callback({:arg => _args[i], :contract => @args_contracts[j], :class => @klass, :method => @method, :contracts => self, :arg_pos => i+1, :total_args => _size})
279
- return unless call_function
288
+ def call_with(this, *args, &blk)
289
+ args << blk if blk
290
+
291
+ # Explicitly append blk=nil if nil != Proc contract violation anticipated
292
+ maybe_append_block!(args, blk)
293
+
294
+ # Explicitly append options={} if Hash contract is present
295
+ maybe_append_options!(args, blk)
296
+
297
+ # Loop forward validating the arguments up to the splat (if there is one)
298
+ (@args_contract_index || args.size).times do |i|
299
+ contract = args_contracts[i]
300
+ arg = args[i]
301
+ validator = @args_validators[i]
302
+
303
+ unless validator && validator[arg]
304
+ return unless Contract.failure_callback(:arg => arg,
305
+ :contract => contract,
306
+ :class => klass,
307
+ :method => method,
308
+ :contracts => self,
309
+ :arg_pos => i+1,
310
+ :total_args => args.size)
311
+ end
312
+
313
+ if contract.is_a?(Contracts::Func)
314
+ args[i] = Contract.new(klass, arg, *contract.contracts)
280
315
  end
281
316
  end
282
317
 
283
- if @has_func_contracts
284
- # contracts on methods
285
- contracts_size = @args_contracts.size
286
- @args_contracts.each_with_index do |contract, i|
287
- next if contracts_size - 1 == i && proc_present && blk
318
+ # If there is a splat loop backwards to the lower index of the splat
319
+ # Once we hit the splat in this direction set its upper index
320
+ # Keep validating but use this upper index to get the splat validator.
321
+ if @args_contract_index
322
+ splat_upper_index = @args_contract_index
323
+ (args.size - @args_contract_index).times do |i|
324
+ arg = args[args.size - 1 - i]
288
325
 
289
- if contract.is_a?(Contracts::Func)
290
- args[i] = Contract.new(@klass, args[i], *contract.contracts)
326
+ if args_contracts[args_contracts.size - 1 - i].is_a?(Contracts::Args)
327
+ splat_upper_index = i
328
+ end
329
+
330
+ # Each arg after the spat is found must use the splat validator
331
+ j = i < splat_upper_index ? i : splat_upper_index
332
+ contract = args_contracts[args_contracts.size - 1 - j]
333
+ validator = @args_validators[args_contracts.size - 1 - j]
334
+
335
+ unless validator && validator[arg]
336
+ return unless Contract.failure_callback(:arg => arg,
337
+ :contract => contract,
338
+ :class => klass,
339
+ :method => method,
340
+ :contracts => self,
341
+ :arg_pos => i-1,
342
+ :total_args => args.size)
291
343
  end
292
- end
293
344
 
294
- if proc_present && blk && last_contract.is_a?(Contracts::Func)
295
- blk_contract = Contract.new(@klass, blk, *last_contract.contracts)
296
- blk = Proc.new { |*args, &blk| blk_contract.call(*args, &blk) }
345
+ if contract.is_a?(Contracts::Func)
346
+ args[args.size - 1 - i] = Contract.new(klass, arg, *contract.contracts)
347
+ end
297
348
  end
298
349
  end
299
350
 
300
- result = if @method.respond_to?(:call)
301
- # proc, block, lambda, etc
302
- @method.call(*args, &blk)
303
- else
304
- # original method name referrence
305
- @method.send_to(this, *args, &blk)
306
- end
351
+ # If we put the block into args for validating, restore the args
352
+ args.slice!(-1) if blk
353
+ result = if method.respond_to?(:call)
354
+ # proc, block, lambda, etc
355
+ method.call(*args, &blk)
356
+ else
357
+ # original method name referrence
358
+ method.send_to(this, *args, &blk)
359
+ end
307
360
 
308
361
  unless @ret_validator[result]
309
- Contract.failure_callback({:arg => result, :contract => @ret_contract, :class => @klass, :method => @method, :contracts => self, :return_value => true})
362
+ Contract.failure_callback(:arg => result,
363
+ :contract => ret_contract,
364
+ :class => klass,
365
+ :method => method,
366
+ :contracts => self,
367
+ :return_value => true)
310
368
  end
311
369
 
312
- this.verify_invariants!(@method) if this.respond_to?(:verify_invariants!)
370
+ this.verify_invariants!(method) if this.respond_to?(:verify_invariants!)
313
371
 
314
372
  result
315
373
  end
@@ -1,22 +1,23 @@
1
- require 'contracts/testable'
2
-
3
- =begin rdoc
4
- This module contains all the builtin contracts.
5
- If you want to use them, first:
6
-
7
- import Contracts
8
-
9
- And then use these or write your own!
10
-
11
- A simple example:
12
-
13
- Contract Num, Num => Num
14
- def add(a, b)
15
- a + b
16
- end
17
-
18
- The contract is <tt>Contract Num, Num, Num</tt>. That says that the +add+ function takes two numbers and returns a number.
19
- =end
1
+ require "contracts/testable"
2
+ require "contracts/formatters"
3
+
4
+ # rdoc
5
+ # This module contains all the builtin contracts.
6
+ # If you want to use them, first:
7
+ #
8
+ # import Contracts
9
+ #
10
+ # And then use these or write your own!
11
+ #
12
+ # A simple example:
13
+ #
14
+ # Contract Num, Num => Num
15
+ # def add(a, b)
16
+ # a + b
17
+ # end
18
+ #
19
+ # The contract is <tt>Contract Num, Num, Num</tt>.
20
+ # That says that the +add+ function takes two numbers and returns a number.
20
21
  module Contracts
21
22
  # Check that an argument is +Numeric+.
22
23
  class Num
@@ -29,7 +30,7 @@ module Contracts
29
30
  end
30
31
 
31
32
  def self.test_data
32
- [-1, 0, 1, 1.5, 50000]
33
+ [-1, 0, 1, 1.5, 50_000]
33
34
  end
34
35
  end
35
36
 
@@ -63,6 +64,21 @@ module Contracts
63
64
  end
64
65
  end
65
66
 
67
+ # Check that an argument is a natural number.
68
+ class Nat
69
+ def self.valid? val
70
+ val >= 0 && val.integer?
71
+ end
72
+
73
+ def testable?
74
+ true
75
+ end
76
+
77
+ def self.test_data
78
+ (0..5).map { |n| n * rand(999) }
79
+ end
80
+ end
81
+
66
82
  # Passes for any argument.
67
83
  class Any
68
84
  def self.valid? val
@@ -86,8 +102,9 @@ module Contracts
86
102
  #
87
103
  # Of course, <tt>.new</tt> still works.
88
104
  class CallableClass
105
+ include ::Contracts::Formatters
89
106
  def self.[](*vals)
90
- self.new(*vals)
107
+ new(*vals)
91
108
  end
92
109
  end
93
110
 
@@ -107,20 +124,22 @@ module Contracts
107
124
  end
108
125
 
109
126
  def to_s
110
- @vals[0, @vals.size-1].join(", ") + " or " + @vals[-1].to_s
127
+ @vals[0, @vals.size-1].map do |x|
128
+ InspectWrapper.create(x)
129
+ end.join(", ") + " or " + InspectWrapper.create(@vals[-1]).to_s
111
130
  end
112
131
 
113
132
  # this can only be tested IF all the sub-contracts have a test_data method
114
133
  def testable?
115
134
  @vals.all? do |val|
116
135
  Testable.testable?(val)
117
- end
136
+ end
118
137
  end
119
138
 
120
139
  def test_data
121
- @vals.map { |val|
140
+ @vals.map do |val|
122
141
  Testable.test_data(val)
123
- }.flatten
142
+ end.flatten
124
143
  end
125
144
  end
126
145
 
@@ -141,25 +160,27 @@ module Contracts
141
160
  end
142
161
 
143
162
  def to_s
144
- @vals[0, @vals.size-1].join(", ") + " xor " + @vals[-1].to_s
163
+ @vals[0, @vals.size-1].map do |x|
164
+ InspectWrapper.create(x)
165
+ end.join(", ") + " xor " + InspectWrapper.create(@vals[-1]).to_s
145
166
  end
146
167
 
147
168
  def testable?
148
169
  @vals.all? do |val|
149
170
  Testable.testable? val
150
- end
171
+ end
151
172
  end
152
173
 
153
174
  def test_data
154
- @vals.map { |val|
175
+ @vals.map do |val|
155
176
  Testable.test_data val
156
- }.flatten
157
- end
158
- end
177
+ end.flatten
178
+ end
179
+ end
159
180
 
160
181
  # Takes a variable number of contracts.
161
182
  # The contract passes if all contracts pass.
162
- # Example: <tt>And[Fixnum, Float]</tt>
183
+ # Example: <tt>And[Fixnum, Float]</tt>
163
184
  class And < CallableClass
164
185
  def initialize(*vals)
165
186
  @vals = vals
@@ -173,7 +194,9 @@ module Contracts
173
194
  end
174
195
 
175
196
  def to_s
176
- @vals[0, @vals.size-1].join(", ") + " and " + @vals[-1].to_s
197
+ @vals[0, @vals.size-1].map do |x|
198
+ InspectWrapper.create(x)
199
+ end.join(", ") + " and " + InspectWrapper.create(@vals[-1]).to_s
177
200
  end
178
201
  end
179
202
 
@@ -215,10 +238,10 @@ module Contracts
215
238
 
216
239
  def to_s
217
240
  "a value that returns true for all of #{@meths.inspect}"
218
- end
241
+ end
219
242
  end
220
243
 
221
- # Takes a class +A+. If argument is an object of type +A+, the contract passes.
244
+ # Takes a class +A+. If argument is object of type +A+, the contract passes.
222
245
  # If it is a subclass of A (or not related to A in any way), it fails.
223
246
  # Example: <tt>Exactly[Numeric]</tt>
224
247
  class Exactly < CallableClass
@@ -234,7 +257,24 @@ module Contracts
234
257
  "exactly #{@cls.inspect}"
235
258
  end
236
259
  end
237
-
260
+
261
+ # Takes a value +v+. If the argument is +.equal+ to +v+, the contract passes,
262
+ # otherwise the contract fails.
263
+ # Example: <tt>Eq[Class]</tt>
264
+ class Eq < CallableClass
265
+ def initialize(value)
266
+ @value = value
267
+ end
268
+
269
+ def valid?(val)
270
+ @value.equal?(val)
271
+ end
272
+
273
+ def to_s
274
+ "to be equal to #{@value.inspect}"
275
+ end
276
+ end
277
+
238
278
  # Takes a variable number of contracts. The contract
239
279
  # passes if all of those contracts fail for the given argument.
240
280
  # Example: <tt>Not[nil]</tt>
@@ -281,8 +321,12 @@ module Contracts
281
321
  end
282
322
 
283
323
  def test_data
284
- [[], [Testable.test_data(@contract)], [Testable.test_data(@contract), Testable.test_data(@contract)]]
285
- end
324
+ [
325
+ [],
326
+ [Testable.test_data(@contract)],
327
+ [Testable.test_data(@contract), Testable.test_data(@contract)]
328
+ ]
329
+ end
286
330
  end
287
331
 
288
332
  # Used for <tt>*args</tt> (variadic functions). Takes a contract
@@ -304,8 +348,12 @@ module Contracts
304
348
  end
305
349
 
306
350
  def test_data
307
- [[], [Testable.test_data(@contract)], [Testable.test_data(@contract), Testable.test_data(@contract)]]
308
- end
351
+ [
352
+ [],
353
+ [Testable.test_data(@contract)],
354
+ [Testable.test_data(@contract), Testable.test_data(@contract)]
355
+ ]
356
+ end
309
357
  end
310
358
 
311
359
  class Bool
@@ -324,14 +372,14 @@ module Contracts
324
372
  end
325
373
 
326
374
  def valid?(hash)
327
- keys_match = hash.keys.map {|k| Contract.valid?(k, @key) }.all?
328
- vals_match = hash.values.map {|v| Contract.valid?(v, @value) }.all?
375
+ keys_match = hash.keys.map { |k| Contract.valid?(k, @key) }.all?
376
+ vals_match = hash.values.map { |v| Contract.valid?(v, @value) }.all?
329
377
 
330
378
  [keys_match, vals_match].all?
331
379
  end
332
380
 
333
381
  def to_s
334
- "Hash<#{@key.to_s}, #{@value.to_s}>"
382
+ "Hash<#{@key}, #{@value}>"
335
383
  end
336
384
  end
337
385
 
@@ -344,51 +392,51 @@ module Contracts
344
392
  end
345
393
  end
346
394
 
347
- class ::Hash
348
- def testable?
349
- self.values.all? do |val|
350
- Testable.testable?(val)
351
- end
352
- end
353
-
354
- def test_data
355
- keys = self.keys
356
- _vals = keys.map do |key|
357
- ret = Testable.test_data(self[key])
358
- if ret.is_a? Array
359
- ret
360
- else
361
- [ret]
362
- end
363
- end
364
- all_vals = Testable.product(_vals)
365
- hashes = []
366
- all_vals.each do |vals|
367
- hash = {}
368
- keys.zip(vals).each do |key, val|
369
- hash[key] = val
370
- end
371
- hashes << hash
372
- end
373
- hashes
374
- end
375
- end
376
-
377
- class ::String
378
- def self.testable?
379
- true
380
- end
381
-
382
- def self.test_data
383
- # send a random string
384
- ('a'..'z').to_a.shuffle[0, 10].join
385
- end
386
- end
395
+ # class ::Hash
396
+ # def testable?
397
+ # values.all? do |val|
398
+ # Testable.testable?(val)
399
+ # end
400
+ # end
401
+
402
+ # def test_data
403
+ # keys = self.keys
404
+ # _vals = keys.map do |key|
405
+ # ret = Testable.test_data(self[key])
406
+ # if ret.is_a? Array
407
+ # ret
408
+ # else
409
+ # [ret]
410
+ # end
411
+ # end
412
+ # all_vals = Testable.product(_vals)
413
+ # hashes = []
414
+ # all_vals.each do |vals|
415
+ # hash = {}
416
+ # keys.zip(vals).each do |key, val|
417
+ # hash[key] = val
418
+ # end
419
+ # hashes << hash
420
+ # end
421
+ # hashes
422
+ # end
423
+ # end
424
+
425
+ # class ::String
426
+ # def self.testable?
427
+ # true
428
+ # end
429
+
430
+ # def self.test_data
431
+ # # send a random string
432
+ # ("a".."z").to_a.shuffle[0, 10].join
433
+ # end
434
+ # end
387
435
 
388
436
  # Used to define contracts on functions passed in as arguments.
389
437
  # Example: <tt>Func[Num => Num] # the function should take a number and return a number</tt>
390
438
  class Func < CallableClass
391
- attr_reader :contracts
439
+ attr_reader :contracts
392
440
  def initialize(*contracts)
393
441
  @contracts = contracts
394
442
  end