contracts 0.12.0 → 0.13.0
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.
- checksums.yaml +5 -13
- data/CHANGELOG.markdown +6 -0
- data/TUTORIAL.md +27 -25
- data/features/builtin_contracts/args.feature +80 -1
- data/features/builtin_contracts/int.feature +93 -0
- data/features/builtin_contracts/nat_pos.feature +119 -0
- data/lib/contracts/builtin_contracts.rb +15 -1
- data/lib/contracts/decorators.rb +4 -0
- data/lib/contracts/engine/eigenclass.rb +4 -0
- data/lib/contracts/engine/target.rb +2 -0
- data/lib/contracts/version.rb +1 -1
- data/spec/contracts_spec.rb +8 -26
- data/spec/fixtures/fixtures.rb +6 -0
- data/spec/override_validators_spec.rb +1 -1
- data/spec/validators_spec.rb +1 -1
- metadata +11 -9
checksums.yaml
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
|
|
5
|
-
data.tar.gz: !binary |-
|
|
6
|
-
NDFhYTJmODVkY2FlNWE3ZGI2ZjcxM2JiODMyODBlZjM4MmRjZDkwZQ==
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: e31d0dc3c6a107d0255ab5af8229749e6ce825e6
|
|
4
|
+
data.tar.gz: 915617473470b5450ee855605380d7d6552d49a8
|
|
7
5
|
SHA512:
|
|
8
|
-
metadata.gz:
|
|
9
|
-
|
|
10
|
-
ZDAwMmNhZWVkMTMxMDZkZTUwOGMwN2VhYjBlOTg2MGFhNmEzNjM1N2Q0NTJi
|
|
11
|
-
YzMzN2Y1ZTBiMWIwZDgyYWM0MmM5N2IyMjQ3ZWVmZGMwYzQxZDE=
|
|
12
|
-
data.tar.gz: !binary |-
|
|
13
|
-
ZTI2OWM5ZTNmYjFmMTI1NjU5ODUwNzM4MTg3NDBjYjkxM2RkZDJiYTBjNTcy
|
|
14
|
-
ZGY4NzYzZWU2NmM3Njc2ZmFlZjAzYzBkZDdhYTQ3ZmViNDYyMDY5Yzc2N2M3
|
|
15
|
-
Y2U5NTczYjdiODZjZjAxMzNiOGVjYTkyNzlhY2UyYmM3NDQzOWQ=
|
|
6
|
+
metadata.gz: 73c20ffc1467c52de7a44f91cf1711049c2db2f47aaf3b8faf517a0ba05030aa891c3748a0287ed6d5be799f96d3eb9b92eb8ea950041b0ff459e63262388a56
|
|
7
|
+
data.tar.gz: 0343d43d8437dcb11255392d53cb57e06119eb0dbd7f20880c0e0646d40b1abf9888e6b1fd5450464eed6ec4635444f7817b87228b1560eca81f0e4997a79eee
|
data/CHANGELOG.markdown
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## v0.13.0
|
|
2
|
+
|
|
3
|
+
- Enhancement: Add support for Ruby 2.3 - [Oleksii Fedorov](https://github.com/waterlink) [#216](https://github.com/egonSchiele/contracts.ruby/pull/216)
|
|
4
|
+
- Enhancement: Added Int, Nat and NatPos builtin contracts - [Simon George](https://github.com/sfcgeorge) [#212](https://github.com/egonSchiele/contracts.ruby/pull/212)
|
|
5
|
+
- Bugfix: Allow contracts on singleton of subclass - [Oleksii Federov](https://github.com/waterlink) [#211](https://github.com/egonSchiele/contracts.ruby/pull/211)
|
|
6
|
+
|
|
1
7
|
## v0.12.0
|
|
2
8
|
|
|
3
9
|
- Feature: add `Regexp` validator - [Gert Goet](https://github.com/eval) [#196](https://github.com/egonSchiele/contracts.ruby/pull/196)
|
data/TUTORIAL.md
CHANGED
|
@@ -68,42 +68,44 @@ This can be useful if you're in a REPL and want to figure out how a function sho
|
|
|
68
68
|
contracts.ruby comes with a lot of built-in contracts, including the following:
|
|
69
69
|
|
|
70
70
|
* Basic types
|
|
71
|
-
* [`Num`](http://www.rubydoc.info/gems/contracts/Contracts/Num) – checks that the argument is `Numeric`
|
|
72
|
-
* [`Pos`](http://www.rubydoc.info/gems/contracts/Contracts/Pos) – checks that the argument is a positive number
|
|
73
|
-
* [`Neg`](http://www.rubydoc.info/gems/contracts/Contracts/Neg) – checks that the argument is a negative number
|
|
74
|
-
* [`
|
|
75
|
-
* [`
|
|
76
|
-
* [`
|
|
77
|
-
* [`
|
|
71
|
+
* [`Num`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Num) – checks that the argument is `Numeric`
|
|
72
|
+
* [`Pos`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Pos) – checks that the argument is a positive number
|
|
73
|
+
* [`Neg`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Neg) – checks that the argument is a negative number
|
|
74
|
+
* [`Int`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Int) – checks that the argument is an integer
|
|
75
|
+
* [`Nat`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Nat) – checks that the argument is a natural number (>= 0)
|
|
76
|
+
* [`NatPos`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/NatPos) – checks that the argument is a positive natural number (> 0)
|
|
77
|
+
* [`Bool`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Bool) – checks that the argument is `true` or `false`
|
|
78
|
+
* [`Any`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Any) – Passes for any argument. Use when the argument has no constraints.
|
|
79
|
+
* [`None`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/None) – Fails for any argument. Use when the method takes no arguments.
|
|
78
80
|
|
|
79
81
|
* Logical combinations
|
|
80
|
-
* [`Maybe`](http://www.rubydoc.info/gems/contracts/Contracts/Maybe) – specifies that a value _may be_ nil, e.g. `Maybe[String]` (equivalent to `Or[String,nil]`)
|
|
81
|
-
* [`Or`](http://www.rubydoc.info/gems/contracts/Contracts/Or) – passes if any of the given contracts pass, e.g. `Or[Fixnum, Float]`
|
|
82
|
-
* [`Xor`](http://www.rubydoc.info/gems/contracts/Contracts/Xor) – passes if exactly one of the given contracts pass, e.g. `Xor[Fixnum, Float]`
|
|
83
|
-
* [`And`](http://www.rubydoc.info/gems/contracts/Contracts/And) – passes if all contracts pass, e.g. `And[Nat, -> (n) { n.even? }]`
|
|
84
|
-
* [`Not`](http://www.rubydoc.info/gems/contracts/Contracts/Not) – passes if all contracts fail for the given argument, e.g. `Not[nil]`
|
|
82
|
+
* [`Maybe`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Maybe) – specifies that a value _may be_ nil, e.g. `Maybe[String]` (equivalent to `Or[String,nil]`)
|
|
83
|
+
* [`Or`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Or) – passes if any of the given contracts pass, e.g. `Or[Fixnum, Float]`
|
|
84
|
+
* [`Xor`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Xor) – passes if exactly one of the given contracts pass, e.g. `Xor[Fixnum, Float]`
|
|
85
|
+
* [`And`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/And) – passes if all contracts pass, e.g. `And[Nat, -> (n) { n.even? }]`
|
|
86
|
+
* [`Not`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Not) – passes if all contracts fail for the given argument, e.g. `Not[nil]`
|
|
85
87
|
|
|
86
88
|
* Collections
|
|
87
|
-
* [`ArrayOf`](http://www.rubydoc.info/gems/contracts/Contracts/ArrayOf) – checks that the argument is an array, and all elements pass the given contract, e.g. `ArrayOf[Num]`
|
|
88
|
-
* [`SetOf`](http://www.rubydoc.info/gems/contracts/Contracts/SetOf) – checks that the argument is a set, and all elements pass the given contract, e.g. `SetOf[Num]`
|
|
89
|
-
* [`HashOf`](http://www.rubydoc.info/gems/contracts/Contracts/HashOf) – checks that the argument is a hash, and all keys and values pass the given contract, e.g. `HashOf[Symbol => String]` or `HashOf[Symbol,String]`
|
|
90
|
-
* [`RangeOf`](http://www.rubydoc.info/gems/contracts/Contracts/RangeOf) – checks that the argument is a range whose elements (#first and #last) pass the given contract, e.g. `RangeOf[Date]`
|
|
91
|
-
* [`Enum`](http://www.rubydoc.info/gems/contracts/Contracts/Enum) – checks that the argument is part of a given collection of objects, e.g. `Enum[:a, :b, :c]`
|
|
89
|
+
* [`ArrayOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/ArrayOf) – checks that the argument is an array, and all elements pass the given contract, e.g. `ArrayOf[Num]`
|
|
90
|
+
* [`SetOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/SetOf) – checks that the argument is a set, and all elements pass the given contract, e.g. `SetOf[Num]`
|
|
91
|
+
* [`HashOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/HashOf) – checks that the argument is a hash, and all keys and values pass the given contract, e.g. `HashOf[Symbol => String]` or `HashOf[Symbol,String]`
|
|
92
|
+
* [`RangeOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/RangeOf) – checks that the argument is a range whose elements (#first and #last) pass the given contract, e.g. `RangeOf[Date]`
|
|
93
|
+
* [`Enum`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Enum) – checks that the argument is part of a given collection of objects, e.g. `Enum[:a, :b, :c]`
|
|
92
94
|
|
|
93
95
|
* Keyword arguments
|
|
94
|
-
* [`KeywordArgs`](http://www.rubydoc.info/gems/contracts/Contracts/KeywordArgs) – checks that the argument is an options hash, and all required keyword arguments are present, and all values pass their respective contracts, e.g. `KeywordArgs[:number => Num, :description => Optional[String]]`
|
|
95
|
-
* [`Optional`](http://www.rubydoc.info/gems/contracts/Contracts/Optional) – checks that the keyword argument is either not present or pass the given contract, can not be used outside of `KeywordArgs` contract, e.g. `Optional[Num]`
|
|
96
|
+
* [`KeywordArgs`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/KeywordArgs) – checks that the argument is an options hash, and all required keyword arguments are present, and all values pass their respective contracts, e.g. `KeywordArgs[:number => Num, :description => Optional[String]]`
|
|
97
|
+
* [`Optional`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Optional) – checks that the keyword argument is either not present or pass the given contract, can not be used outside of `KeywordArgs` contract, e.g. `Optional[Num]`
|
|
96
98
|
|
|
97
99
|
* Duck typing
|
|
98
|
-
* [`RespondTo`](http://www.rubydoc.info/gems/contracts/Contracts/RespondTo) – checks that the argument responds to all of the given methods, e.g. `RespondTo[:password, :credit_card]`
|
|
99
|
-
* [`Send`](http://www.rubydoc.info/gems/contracts/Contracts/Send) – checks that all named methods return a truthy value, e.g. `Send[:valid?]`
|
|
100
|
+
* [`RespondTo`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/RespondTo) – checks that the argument responds to all of the given methods, e.g. `RespondTo[:password, :credit_card]`
|
|
101
|
+
* [`Send`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Send) – checks that all named methods return a truthy value, e.g. `Send[:valid?]`
|
|
100
102
|
|
|
101
103
|
* Miscellaneous
|
|
102
|
-
* [`Exactly`](http://www.rubydoc.info/gems/contracts/Contracts/Exactly) – checks that the argument has the given type, not accepting sub-classes, e.g. `Exactly[Numeric]`.
|
|
103
|
-
* [`Eq`](http://www.rubydoc.info/gems/contracts/Contracts/Eq) – checks that the argument is precisely equal to the given value, e.g. `Eq[String]` matches the class `String` and not a string instance.
|
|
104
|
-
* [`Func`](http://www.rubydoc.info/gems/contracts/Contracts/Func) – specifies the contract for a proc/lambda e.g. `Contract ArrayOf[Num], Func[Num => Num] => ArrayOf[Num]`. See section "Contracts On Functions".
|
|
104
|
+
* [`Exactly`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Exactly) – checks that the argument has the given type, not accepting sub-classes, e.g. `Exactly[Numeric]`.
|
|
105
|
+
* [`Eq`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Eq) – checks that the argument is precisely equal to the given value, e.g. `Eq[String]` matches the class `String` and not a string instance.
|
|
106
|
+
* [`Func`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Func) – specifies the contract for a proc/lambda e.g. `Contract ArrayOf[Num], Func[Num => Num] => ArrayOf[Num]`. See section "Contracts On Functions".
|
|
105
107
|
|
|
106
|
-
To see all the built-in contracts and their full descriptions, check out the [RDoc](http://rubydoc.info/gems/contracts/Contracts).
|
|
108
|
+
To see all the built-in contracts and their full descriptions, check out the [RDoc](http://rubydoc.info/gems/contracts/Contracts/Builtin).
|
|
107
109
|
|
|
108
110
|
It is recommended to use shortcut for referring builtin contracts:
|
|
109
111
|
|
|
@@ -1 +1,80 @@
|
|
|
1
|
-
Feature: Args
|
|
1
|
+
Feature: Args
|
|
2
|
+
|
|
3
|
+
Used for `*args` (variadic functions). Takes contract and uses it to validate
|
|
4
|
+
every element passed in through `*args`.
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
Contract C::Args[C::Num] => C::Bool
|
|
8
|
+
def example(*args)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This example contract will validate all arguments passed through `*args` to
|
|
12
|
+
accept only numbers.
|
|
13
|
+
|
|
14
|
+
Background:
|
|
15
|
+
Given a file named "args_usage.rb" with:
|
|
16
|
+
"""ruby
|
|
17
|
+
require "contracts"
|
|
18
|
+
C = Contracts
|
|
19
|
+
|
|
20
|
+
class Example
|
|
21
|
+
include Contracts::Core
|
|
22
|
+
|
|
23
|
+
Contract C::Args[C::Num] => C::Bool
|
|
24
|
+
def only_nums(*args)
|
|
25
|
+
args.inspect
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
Scenario: Accepts no arguments
|
|
31
|
+
Given a file named "accepts_no_arguments.rb" with:
|
|
32
|
+
"""ruby
|
|
33
|
+
require "./args_usage"
|
|
34
|
+
puts Example.new.only_nums
|
|
35
|
+
"""
|
|
36
|
+
When I run `ruby accepts_no_arguments.rb`
|
|
37
|
+
Then the output should contain:
|
|
38
|
+
"""
|
|
39
|
+
[]
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
Scenario: Accepts one valid argument
|
|
43
|
+
Given a file named "accepts_one_argument.rb" with:
|
|
44
|
+
"""ruby
|
|
45
|
+
require "./args_usage"
|
|
46
|
+
puts Example.new.only_nums(42)
|
|
47
|
+
"""
|
|
48
|
+
When I run `ruby accepts_one_argument.rb`
|
|
49
|
+
Then the output should contain:
|
|
50
|
+
"""
|
|
51
|
+
[42]
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
Scenario: Accepts many valid arguments
|
|
55
|
+
Given a file named "accepts_many_arguments.rb" with:
|
|
56
|
+
"""ruby
|
|
57
|
+
require "./args_usage"
|
|
58
|
+
puts Example.new.only_nums(42, 45, 17, 24)
|
|
59
|
+
"""
|
|
60
|
+
When I run `ruby accepts_many_arguments.rb`
|
|
61
|
+
Then the output should contain:
|
|
62
|
+
"""
|
|
63
|
+
[42, 45, 17, 24]
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
Scenario: Rejects invalid argument
|
|
67
|
+
Given a file named "rejects_invalid_argument.rb" with:
|
|
68
|
+
"""ruby
|
|
69
|
+
require "./args_usage"
|
|
70
|
+
puts Example.new.only_nums(42, "foo", 17, 24)
|
|
71
|
+
"""
|
|
72
|
+
When I run `ruby rejects_invalid_argument.rb`
|
|
73
|
+
Then the output should contain:
|
|
74
|
+
"""
|
|
75
|
+
: Contract violation for argument 1 of 4: (ParamContractError)
|
|
76
|
+
Expected: (Args[Contracts::Builtin::Num]),
|
|
77
|
+
Actual: "foo"
|
|
78
|
+
Value guarded in: Example::only_nums
|
|
79
|
+
With Contract: Args => Bool
|
|
80
|
+
"""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Feature: Int
|
|
2
|
+
|
|
3
|
+
Checks that an argument is an integer.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
Contract C::Int => C::Int
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Background:
|
|
10
|
+
Given a file named "int_usage.rb" with:
|
|
11
|
+
"""ruby
|
|
12
|
+
require "contracts"
|
|
13
|
+
C = Contracts
|
|
14
|
+
|
|
15
|
+
class Integr
|
|
16
|
+
include Contracts::Core
|
|
17
|
+
|
|
18
|
+
Contract C::Int => C::Int
|
|
19
|
+
def prev(number)
|
|
20
|
+
number - 1
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
Scenario: Accepts positive integers
|
|
26
|
+
Given a file named "accepts_positive_integers.rb" with:
|
|
27
|
+
"""ruby
|
|
28
|
+
require "./int_usage"
|
|
29
|
+
puts Integr.new.prev(7)
|
|
30
|
+
"""
|
|
31
|
+
When I run `ruby accepts_positive_integers.rb`
|
|
32
|
+
Then output should contain:
|
|
33
|
+
"""
|
|
34
|
+
6
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
Scenario: Accepts zero
|
|
38
|
+
Given a file named "accepts_zero.rb" with:
|
|
39
|
+
"""ruby
|
|
40
|
+
require "./int_usage"
|
|
41
|
+
puts Integr.new.prev(1)
|
|
42
|
+
"""
|
|
43
|
+
When I run `ruby accepts_zero.rb`
|
|
44
|
+
Then output should contain:
|
|
45
|
+
"""
|
|
46
|
+
0
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
Scenario: Accepts negative integers
|
|
50
|
+
Given a file named "accepts_negative_integers.rb" with:
|
|
51
|
+
"""ruby
|
|
52
|
+
require "./int_usage"
|
|
53
|
+
puts Integr.new.prev(-1)
|
|
54
|
+
"""
|
|
55
|
+
When I run `ruby accepts_negative_integers.rb`
|
|
56
|
+
Then output should contain:
|
|
57
|
+
"""
|
|
58
|
+
-2
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
Scenario: Rejects floats
|
|
62
|
+
Given a file named "rejects_floats.rb" with:
|
|
63
|
+
"""ruby
|
|
64
|
+
require "./int_usage"
|
|
65
|
+
puts Integr.new.prev(3.43)
|
|
66
|
+
"""
|
|
67
|
+
When I run `ruby rejects_floats.rb`
|
|
68
|
+
Then output should contain:
|
|
69
|
+
"""
|
|
70
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
71
|
+
Expected: Int,
|
|
72
|
+
Actual: 3.43
|
|
73
|
+
Value guarded in: Integr::prev
|
|
74
|
+
With Contract: Int => Int
|
|
75
|
+
"""
|
|
76
|
+
And output should contain "int_usage.rb:8"
|
|
77
|
+
|
|
78
|
+
Scenario: Rejects other values
|
|
79
|
+
Given a file named "rejects_others.rb" with:
|
|
80
|
+
"""ruby
|
|
81
|
+
require "./int_usage"
|
|
82
|
+
puts Integr.new.prev("foo")
|
|
83
|
+
"""
|
|
84
|
+
When I run `ruby rejects_others.rb`
|
|
85
|
+
Then output should contain:
|
|
86
|
+
"""
|
|
87
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
88
|
+
Expected: Int,
|
|
89
|
+
Actual: "foo"
|
|
90
|
+
Value guarded in: Integr::prev
|
|
91
|
+
With Contract: Int => Int
|
|
92
|
+
"""
|
|
93
|
+
And output should contain "int_usage.rb:8"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Feature: NatPos
|
|
2
|
+
|
|
3
|
+
Checks that an argument is a positive natural number.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
Contract C::NatPos => C::NatPos
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Background:
|
|
10
|
+
Given a file named "nat_pos_usage.rb" with:
|
|
11
|
+
"""ruby
|
|
12
|
+
require "contracts"
|
|
13
|
+
C = Contracts
|
|
14
|
+
|
|
15
|
+
class NaturalPositive
|
|
16
|
+
include Contracts::Core
|
|
17
|
+
|
|
18
|
+
Contract C::NatPos => C::NatPos
|
|
19
|
+
def prev(number)
|
|
20
|
+
number - 1
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
Scenario: Accepts positive integers
|
|
26
|
+
Given a file named "accepts_positive_integers.rb" with:
|
|
27
|
+
"""ruby
|
|
28
|
+
require "./nat_pos_usage"
|
|
29
|
+
puts NaturalPositive.new.prev(7)
|
|
30
|
+
"""
|
|
31
|
+
When I run `ruby accepts_positive_integers.rb`
|
|
32
|
+
Then output should contain:
|
|
33
|
+
"""
|
|
34
|
+
6
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
Scenario: Rejects zero
|
|
38
|
+
Given a file named "rejects_zero.rb" with:
|
|
39
|
+
"""ruby
|
|
40
|
+
require "./nat_pos_usage"
|
|
41
|
+
puts NaturalPositive.new.prev(0)
|
|
42
|
+
"""
|
|
43
|
+
When I run `ruby rejects_zero.rb`
|
|
44
|
+
Then output should contain:
|
|
45
|
+
"""
|
|
46
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
47
|
+
Expected: NatPos,
|
|
48
|
+
Actual: 0
|
|
49
|
+
Value guarded in: NaturalPositive::prev
|
|
50
|
+
With Contract: NatPos => NatPos
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
Scenario: Rejects negative integers
|
|
54
|
+
Given a file named "rejects_negative_integers.rb" with:
|
|
55
|
+
"""ruby
|
|
56
|
+
require "./nat_pos_usage"
|
|
57
|
+
puts NaturalPositive.new.prev(-1)
|
|
58
|
+
"""
|
|
59
|
+
When I run `ruby rejects_negative_integers.rb`
|
|
60
|
+
Then output should contain:
|
|
61
|
+
"""
|
|
62
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
63
|
+
Expected: NatPos,
|
|
64
|
+
Actual: -1
|
|
65
|
+
Value guarded in: NaturalPositive::prev
|
|
66
|
+
With Contract: NatPos => NatPos
|
|
67
|
+
"""
|
|
68
|
+
And output should contain "nat_pos_usage.rb:8"
|
|
69
|
+
|
|
70
|
+
Scenario: Rejects negative integers as a return value
|
|
71
|
+
Given a file named "rejects_negative_integers.rb" with:
|
|
72
|
+
"""ruby
|
|
73
|
+
require "./nat_pos_usage"
|
|
74
|
+
puts NaturalPositive.new.prev(1)
|
|
75
|
+
"""
|
|
76
|
+
When I run `ruby rejects_negative_integers.rb`
|
|
77
|
+
Then output should contain:
|
|
78
|
+
"""
|
|
79
|
+
: Contract violation for return value: (ReturnContractError)
|
|
80
|
+
Expected: NatPos,
|
|
81
|
+
Actual: 0
|
|
82
|
+
Value guarded in: NaturalPositive::prev
|
|
83
|
+
With Contract: NatPos => NatPos
|
|
84
|
+
"""
|
|
85
|
+
And output should contain "nat_pos_usage.rb:8"
|
|
86
|
+
|
|
87
|
+
Scenario: Rejects floats
|
|
88
|
+
Given a file named "rejects_floats.rb" with:
|
|
89
|
+
"""ruby
|
|
90
|
+
require "./nat_pos_usage"
|
|
91
|
+
puts NaturalPositive.new.prev(3.43)
|
|
92
|
+
"""
|
|
93
|
+
When I run `ruby rejects_floats.rb`
|
|
94
|
+
Then output should contain:
|
|
95
|
+
"""
|
|
96
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
97
|
+
Expected: NatPos,
|
|
98
|
+
Actual: 3.43
|
|
99
|
+
Value guarded in: NaturalPositive::prev
|
|
100
|
+
With Contract: NatPos => NatPos
|
|
101
|
+
"""
|
|
102
|
+
And output should contain "nat_pos_usage.rb:8"
|
|
103
|
+
|
|
104
|
+
Scenario: Rejects other values
|
|
105
|
+
Given a file named "rejects_others.rb" with:
|
|
106
|
+
"""ruby
|
|
107
|
+
require "./nat_pos_usage"
|
|
108
|
+
puts NaturalPositive.new.prev("foo")
|
|
109
|
+
"""
|
|
110
|
+
When I run `ruby rejects_others.rb`
|
|
111
|
+
Then output should contain:
|
|
112
|
+
"""
|
|
113
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
114
|
+
Expected: NatPos,
|
|
115
|
+
Actual: "foo"
|
|
116
|
+
Value guarded in: NaturalPositive::prev
|
|
117
|
+
With Contract: NatPos => NatPos
|
|
118
|
+
"""
|
|
119
|
+
And output should contain "nat_pos_usage.rb:8"
|
|
@@ -41,13 +41,27 @@ module Contracts
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# Check that an argument is
|
|
44
|
+
# Check that an argument is an +Integer+.
|
|
45
|
+
class Int
|
|
46
|
+
def self.valid? val
|
|
47
|
+
val && val.is_a?(Integer)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Check that an argument is a natural number (includes zero).
|
|
45
52
|
class Nat
|
|
46
53
|
def self.valid? val
|
|
47
54
|
val && val.is_a?(Integer) && val >= 0
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
57
|
|
|
58
|
+
# Check that an argument is a positive natural number (excludes zero).
|
|
59
|
+
class NatPos
|
|
60
|
+
def self.valid? val
|
|
61
|
+
val && val.is_a?(Integer) && val > 0
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
51
65
|
# Passes for any argument.
|
|
52
66
|
class Any
|
|
53
67
|
def self.valid? val
|
data/lib/contracts/decorators.rb
CHANGED
|
@@ -18,6 +18,10 @@ module Contracts
|
|
|
18
18
|
return Engine.fetch_from(eigenclass) if Engine.applied?(eigenclass)
|
|
19
19
|
|
|
20
20
|
Target.new(eigenclass).apply(Eigenclass)
|
|
21
|
+
eigenclass.extend(MethodDecorators)
|
|
22
|
+
# FIXME; this should detect what user uses `include Contracts` or
|
|
23
|
+
# `include Contracts;;Core`
|
|
24
|
+
eigenclass.send(:include, Contracts)
|
|
21
25
|
Engine.fetch_from(owner).set_eigenclass_owner
|
|
22
26
|
Engine.fetch_from(eigenclass)
|
|
23
27
|
end
|
data/lib/contracts/version.rb
CHANGED
data/spec/contracts_spec.rb
CHANGED
|
@@ -141,32 +141,6 @@ RSpec.describe "Contracts:" do
|
|
|
141
141
|
end.to raise_error(ContractError, /Expected: String/)
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
-
context "when owner class does not include Contracts" do
|
|
145
|
-
let(:error) do
|
|
146
|
-
# NOTE Unable to support this user-friendly error for ruby
|
|
147
|
-
# 1.8.7 and jruby 1.8, 1.9 it has much less support for
|
|
148
|
-
# singleton inheritance hierarchy
|
|
149
|
-
if Contracts::Support.eigenclass_hierarchy_supported?
|
|
150
|
-
[Contracts::ContractsNotIncluded, Contracts::ContractsNotIncluded::DEFAULT_MESSAGE]
|
|
151
|
-
else
|
|
152
|
-
[NoMethodError, /undefined method `Contract'/]
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
it "fails with descriptive error" do
|
|
157
|
-
expect do
|
|
158
|
-
Class.new(GenericExample) do
|
|
159
|
-
class << self
|
|
160
|
-
Contract String => String
|
|
161
|
-
def hoge(name)
|
|
162
|
-
"super#{name}"
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end.to raise_error(*error)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
144
|
describe "builtin contracts usage" do
|
|
171
145
|
it "allows to use builtin contracts without namespacing and redundant Contracts inclusion" do
|
|
172
146
|
expect do
|
|
@@ -176,6 +150,14 @@ RSpec.describe "Contracts:" do
|
|
|
176
150
|
end
|
|
177
151
|
end
|
|
178
152
|
|
|
153
|
+
describe "usage in the singleton class of a subclass" do
|
|
154
|
+
subject { SingletonInheritanceExampleSubclass }
|
|
155
|
+
|
|
156
|
+
it "should work with a valid contract on a singleton method" do
|
|
157
|
+
expect(subject.num(1)).to eq(1)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
179
161
|
describe "no contracts feature" do
|
|
180
162
|
it "disables normal contract checks" do
|
|
181
163
|
object = NoContractsSimpleExample.new
|
data/spec/fixtures/fixtures.rb
CHANGED
|
@@ -621,6 +621,12 @@ class SingletonInheritanceExample
|
|
|
621
621
|
end
|
|
622
622
|
|
|
623
623
|
class SingletonInheritanceExampleSubclass < SingletonInheritanceExample
|
|
624
|
+
class << self
|
|
625
|
+
Contract Integer => Integer
|
|
626
|
+
def num(int)
|
|
627
|
+
int
|
|
628
|
+
end
|
|
629
|
+
end
|
|
624
630
|
end
|
|
625
631
|
|
|
626
632
|
class BareOptionalContractUsed
|
data/spec/validators_spec.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contracts
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aditya Bhargava
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: This library provides contracts for Ruby. Contracts let you clearly express
|
|
14
14
|
how your code behaves, and free you from writing tons of boilerplate, defensive
|
|
@@ -18,10 +18,10 @@ executables: []
|
|
|
18
18
|
extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
|
20
20
|
files:
|
|
21
|
-
- .gitignore
|
|
22
|
-
- .rspec
|
|
23
|
-
- .rubocop.yml
|
|
24
|
-
- .travis.yml
|
|
21
|
+
- ".gitignore"
|
|
22
|
+
- ".rspec"
|
|
23
|
+
- ".rubocop.yml"
|
|
24
|
+
- ".travis.yml"
|
|
25
25
|
- CHANGELOG.markdown
|
|
26
26
|
- Gemfile
|
|
27
27
|
- README.md
|
|
@@ -49,9 +49,11 @@ files:
|
|
|
49
49
|
- features/builtin_contracts/exactly.feature
|
|
50
50
|
- features/builtin_contracts/func.feature
|
|
51
51
|
- features/builtin_contracts/hash_of.feature
|
|
52
|
+
- features/builtin_contracts/int.feature
|
|
52
53
|
- features/builtin_contracts/keyword_args.feature
|
|
53
54
|
- features/builtin_contracts/maybe.feature
|
|
54
55
|
- features/builtin_contracts/nat.feature
|
|
56
|
+
- features/builtin_contracts/nat_pos.feature
|
|
55
57
|
- features/builtin_contracts/neg.feature
|
|
56
58
|
- features/builtin_contracts/none.feature
|
|
57
59
|
- features/builtin_contracts/not.feature
|
|
@@ -107,17 +109,17 @@ require_paths:
|
|
|
107
109
|
- lib
|
|
108
110
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
111
|
requirements:
|
|
110
|
-
- -
|
|
112
|
+
- - ">="
|
|
111
113
|
- !ruby/object:Gem::Version
|
|
112
114
|
version: '0'
|
|
113
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
116
|
requirements:
|
|
115
|
-
- -
|
|
117
|
+
- - ">="
|
|
116
118
|
- !ruby/object:Gem::Version
|
|
117
119
|
version: '0'
|
|
118
120
|
requirements: []
|
|
119
121
|
rubyforge_project:
|
|
120
|
-
rubygems_version: 2.4.
|
|
122
|
+
rubygems_version: 2.4.6
|
|
121
123
|
signing_key:
|
|
122
124
|
specification_version: 4
|
|
123
125
|
summary: Contracts for Ruby.
|