contracts 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/lib/contracts.rb +41 -3
  2. data/lib/foo.rb +6 -0
  3. data/lib/test.rb +41 -0
  4. metadata +5 -3
@@ -5,6 +5,7 @@ class Class
5
5
  include MethodDecorators
6
6
  end
7
7
 
8
+
8
9
  class Contract < Decorator
9
10
  attr_accessor :contracts, :klass, :method
10
11
  decorator_name :contract
@@ -23,8 +24,13 @@ class Contract < Decorator
23
24
  def self.failure_msg(data)
24
25
  # TODO __file__ and __line__ won't work in Ruby 1.9.
25
26
  # It provides a source_location method instead.
27
+ expected = if data[:contract].to_s == ""
28
+ data[:contract].inspect
29
+ else
30
+ data[:contract].to_s
31
+ end
26
32
  %{Contract violation:
27
- Expected: #{data[:contract]},
33
+ Expected: #{expected},
28
34
  Actual: #{data[:arg].inspect}
29
35
  Value guarded in: #{data[:class]}::#{data[:method].name}
30
36
  With Contract: #{data[:contracts].map { |t| t.is_a?(Class) ? t.name : t.class.name }.join(", ") }
@@ -58,6 +64,21 @@ class Contract < Decorator
58
64
  end
59
65
 
60
66
  def self.validate_all(args, contracts, klass, method)
67
+ if args.size > contracts.size - 1
68
+ # *args
69
+ if contracts[-2].is_a? Args
70
+ while contracts.size < args.size + 1
71
+ contracts.insert(-2, contracts[-2].dup)
72
+ end
73
+ else
74
+ raise %{The number of arguments doesn't match the number of contracts.
75
+ Did you forget to write a contract for the return value of the function?
76
+ Or if you want a variable number of arguments using *args, use the Args contract.
77
+ Args: #{args.inspect}
78
+ Contracts: #{contracts.map { |t| t.is_a?(Class) ? t.name : t.class.name }.join(", ")}}
79
+ end
80
+ end
81
+
61
82
  args.zip(contracts).each do |arg, contract|
62
83
  validate(arg, contract, klass, method, contracts)
63
84
  end
@@ -76,16 +97,22 @@ class Contract < Decorator
76
97
  def self.valid?(arg, contract)
77
98
  case contract
78
99
  when Class
100
+ # e.g. Fixnum
79
101
  validate_class arg, contract
80
102
  when Proc
103
+ # e.g. lambda {true}
81
104
  validate_proc arg, contract
82
105
  when Array
106
+ # e.g. [Num, String]
83
107
  # TODO account for these errors too
84
108
  return mkerror(false, arg, contract) unless arg.is_a?(Array)
85
109
  validate_all(arg, contract)
86
110
  when Hash
111
+ # e.g. { :a => Num, :b => String }
87
112
  return mkerror(false, arg, contract) unless arg.is_a?(Hash)
88
113
  validate_hash(arg, contract)
114
+ when Args
115
+ valid? arg, contract.contract
89
116
  else
90
117
  if contract.respond_to? :valid?
91
118
  mkerror(contract.valid?(arg), arg, contract)
@@ -95,12 +122,23 @@ class Contract < Decorator
95
122
  end
96
123
  end
97
124
 
98
- def call(this, *args)
125
+ def call(this, *args, &blk)
99
126
  Contract.validate_all(args, @contracts, @klass, @method)
100
- result = @method.bind(this).call(*args)
127
+ result = @method.bind(this).call(*args, &blk)
101
128
  if args.size == @contracts.size - 1
102
129
  Contract.validate(result, @contracts[-1], @klass, @method, @contracts)
103
130
  end
104
131
  result
105
132
  end
106
133
  end
134
+
135
+ class Args < Contracts::CallableClass
136
+ attr_reader :contract
137
+ def initialize(contract)
138
+ @contract = contract
139
+ end
140
+
141
+ def to_s
142
+ "Args[#{@contract}]"
143
+ end
144
+ end
@@ -0,0 +1,6 @@
1
+ def foo(*args, kwargs)
2
+ p args
3
+ p kwargs
4
+ end
5
+
6
+ foo(1, 2, 3, :a => 1, :b => 2)
@@ -0,0 +1,41 @@
1
+ require 'contracts'
2
+ include Contracts
3
+
4
+ class Object
5
+ Contract Num, Num
6
+ def double(x)
7
+ x * 2
8
+ end
9
+
10
+ # bug: the `b` here doesn't get typechecked and throws an error.
11
+ Contract Num, Num, Num
12
+ def add(a, b="hello!")
13
+ a + b
14
+ end
15
+
16
+ Contract Proc, nil
17
+ def run(&blk)
18
+ puts "running:"
19
+ blk.call
20
+ end
21
+
22
+ Contract Method, Num
23
+ def call(func)
24
+ func.call
25
+ end
26
+
27
+ # thinks there are too many args, throws error
28
+ # sidenote: there should be a check to make sure the # of args and contracts match up.
29
+ Contract Args[Num], Num
30
+ def sum(*vals)
31
+ vals.inject(0) do |acc, v|
32
+ acc + v
33
+ end
34
+ end
35
+ end
36
+
37
+ run {
38
+ puts "hi!"
39
+ }
40
+
41
+ puts add(1, 2)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contracts
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Aditya Bhargava
@@ -31,6 +31,8 @@ files:
31
31
  - lib/builtin_contracts.rb
32
32
  - lib/contracts.rb
33
33
  - lib/decorators.rb
34
+ - lib/foo.rb
35
+ - lib/test.rb
34
36
  has_rdoc: true
35
37
  homepage: http://github.com/egonSchiele/contracts.ruby
36
38
  licenses: []