contracts 0.7 → 0.8

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.
@@ -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