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.
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: []