contracts 0.0.1 → 0.0.2
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/lib/contracts.rb +41 -3
- data/lib/foo.rb +6 -0
- data/lib/test.rb +41 -0
- metadata +5 -3
data/lib/contracts.rb
CHANGED
@@ -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: #{
|
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
|
data/lib/foo.rb
ADDED
data/lib/test.rb
ADDED
@@ -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:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
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: []
|