contracts 0.17 → 0.17.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/code_style_checks.yaml +2 -2
- data/.github/workflows/tests.yaml +6 -6
- data/.rubocop.yml +1 -1
- data/README.md +10 -2
- data/TUTORIAL.md +14 -14
- data/contracts.gemspec +0 -4
- data/features/builtin_contracts/keyword_args_with_optional_positional_args.feature +76 -0
- data/features/builtin_contracts/none.feature +15 -9
- data/lib/contracts/builtin_contracts.rb +3 -3
- data/lib/contracts/call_with.rb +14 -3
- data/lib/contracts/formatters.rb +3 -0
- data/lib/contracts/version.rb +1 -1
- data/lib/contracts.rb +7 -24
- data/spec/builtin_contracts_spec.rb +1 -1
- data/spec/fixtures/fixtures.rb +9 -9
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a151d83a8b03910e5dd1171c384e0ea8a01ff9437d81140f995358d888ac0fa
|
4
|
+
data.tar.gz: b92d01b9dd8702b866e004c41834781885d8178b1ceacb1e5166982243a13a49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94df8b86d22522b7c573f9cd7b3ee425568b024d7d3a88701759a2b47cdce691bd9ce7ec45710e7e8dafb993c7aa1cb93d6d9a0110d3c4effeece4b24fda29a9
|
7
|
+
data.tar.gz: dbbddaf090e48b52cde302f6a6b5b89fc84045e9c392ef1d34ddcfb2e149f65c3da825b8140ebd4b3d36672ed933b841e1c59b9e684098bb3144762bcd7b4b50
|
@@ -22,16 +22,16 @@ jobs:
|
|
22
22
|
os:
|
23
23
|
- ubuntu
|
24
24
|
ruby:
|
25
|
+
- "3.3"
|
26
|
+
- "3.2"
|
27
|
+
- "3.1"
|
25
28
|
- "3.0"
|
26
|
-
test_command:
|
27
|
-
|
28
|
-
- os: ubuntu
|
29
|
-
ruby: "3.0"
|
30
|
-
test_command: "bundle exec rspec"
|
29
|
+
test_command:
|
30
|
+
- "bundle exec rspec && bundle exec cucumber"
|
31
31
|
runs-on: ${{ matrix.os }}-latest
|
32
32
|
steps:
|
33
33
|
- name: Checkout
|
34
|
-
uses: actions/checkout@
|
34
|
+
uses: actions/checkout@v4
|
35
35
|
- name: Setup Ruby
|
36
36
|
uses: ruby/setup-ruby@v1
|
37
37
|
with:
|
data/.rubocop.yml
CHANGED
@@ -64,7 +64,7 @@ Style/Documentation:
|
|
64
64
|
Layout/LineLength:
|
65
65
|
Enabled: false
|
66
66
|
|
67
|
-
# triggered by Contract ({ :name => String, :age =>
|
67
|
+
# triggered by Contract ({ :name => String, :age => Integer }) => nil
|
68
68
|
Lint/ParenthesesAsGroupedExpression:
|
69
69
|
Enabled: false
|
70
70
|
|
data/README.md
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
This project is looking for a new maintainer! [More details here](https://github.com/egonSchiele/contracts.ruby/issues/249)
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
|
5
|
+
# contracts.ruby [![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/egonSchiele/contracts.ruby/tests.yaml?branch=master&style=flat-square)](https://github.com/egonSchiele/contracts.ruby/actions/workflows/tests.yaml) [![Join the chat at https://gitter.im/egonSchiele/contracts.ruby](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg)](https://gitter.im/egonSchiele/contracts.ruby)
|
4
6
|
|
5
7
|
Contracts let you clearly – even beautifully – express how your code behaves, and free you from writing tons of boilerplate, defensive code.
|
6
8
|
|
7
9
|
You can think of contracts as `assert` on steroids.
|
8
10
|
|
11
|
+
## 0.17.x = Ruby 3.x only
|
12
|
+
|
13
|
+
0.17.x only supports Ruby 3.x
|
14
|
+
Looking for Ruby 2.x support?
|
15
|
+
Use 0.16.x
|
16
|
+
|
9
17
|
## Installation
|
10
18
|
|
11
19
|
gem install contracts
|
@@ -83,7 +91,7 @@ Using contracts.ruby results in very little slowdown. Check out [this blog post]
|
|
83
91
|
|
84
92
|
**Q.** What Rubies can I use this with?
|
85
93
|
|
86
|
-
**A.** It's been tested with `
|
94
|
+
**A.** It's been tested with `3.0` and `3.1`. (In case this list becomes outdated see [`.github/workflows/tests.yaml`](/.github/workflows/tests.yaml))
|
87
95
|
|
88
96
|
If you're using the library, please [let me know](https://github.com/egonSchiele) what project you're using it on :)
|
89
97
|
|
data/TUTORIAL.md
CHANGED
@@ -80,8 +80,8 @@ contracts.ruby comes with a lot of built-in contracts, including the following:
|
|
80
80
|
|
81
81
|
* Logical combinations
|
82
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[
|
84
|
-
* [`Xor`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Xor) – passes if exactly one of the given contracts pass, e.g. `Xor[
|
83
|
+
* [`Or`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Or) – passes if any of the given contracts pass, e.g. `Or[Integer, Float]`
|
84
|
+
* [`Xor`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Xor) – passes if exactly one of the given contracts pass, e.g. `Xor[Integer, Float]`
|
85
85
|
* [`And`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/And) – passes if all contracts pass, e.g. `And[Nat, -> (n) { n.even? }]`
|
86
86
|
* [`Not`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Not) – passes if all contracts fail for the given argument, e.g. `Not[nil]`
|
87
87
|
|
@@ -89,7 +89,7 @@ contracts.ruby comes with a lot of built-in contracts, including the following:
|
|
89
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
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
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
|
-
* [`StrictHash`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/StrictHash) – checks that the argument is a hash, and every key passed is present in the given contract, e.g. `StrictHash[{ :description => String, :number =>
|
92
|
+
* [`StrictHash`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/StrictHash) – checks that the argument is a hash, and every key passed is present in the given contract, e.g. `StrictHash[{ :description => String, :number => Integer }]`
|
93
93
|
* [`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]`
|
94
94
|
* [`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]`
|
95
95
|
|
@@ -152,7 +152,7 @@ end
|
|
152
152
|
|
153
153
|
You always need to specify a contract for the return value. In this example, `hello` doesn't return anything, so the contract is `nil`. Now you know that you can use a constant like `nil` as the end of a contract. Valid values for a contract are:
|
154
154
|
|
155
|
-
- the name of a class (like `String` or `
|
155
|
+
- the name of a class (like `String` or `Integer`)
|
156
156
|
- a constant (like `nil` or `1`)
|
157
157
|
- a `Proc` that takes a value and returns true or false to indicate whether the contract passed or not
|
158
158
|
- a class that responds to the `valid?` class method (more on this later)
|
@@ -161,32 +161,32 @@ You always need to specify a contract for the return value. In this example, `he
|
|
161
161
|
### A Double Function
|
162
162
|
|
163
163
|
```ruby
|
164
|
-
Contract C::Or[
|
164
|
+
Contract C::Or[Integer, Float] => C::Or[Integer, Float]
|
165
165
|
def double(x)
|
166
166
|
2 * x
|
167
167
|
end
|
168
168
|
```
|
169
169
|
|
170
170
|
Sometimes you want to be able to choose between a few contracts. `Or` takes a variable number of contracts and checks the argument against all of them. If it passes for any of the contracts, then the `Or` contract passes.
|
171
|
-
This introduces some new syntax. One of the valid values for a contract is an instance of a class that responds to the `valid?` method. This is what `Or[
|
171
|
+
This introduces some new syntax. One of the valid values for a contract is an instance of a class that responds to the `valid?` method. This is what `Or[Integer, Float]` is. The longer way to write it would have been:
|
172
172
|
|
173
173
|
```ruby
|
174
|
-
Contract C::Or.new(
|
174
|
+
Contract C::Or.new(Integer, Float) => C::Or.new(Integer, Float)
|
175
175
|
```
|
176
176
|
|
177
177
|
All the built-in contracts have overridden the square brackets (`[]`) to give the same functionality. So you could write
|
178
178
|
|
179
179
|
```ruby
|
180
|
-
Contract C::Or[
|
180
|
+
Contract C::Or[Integer, Float] => C::Or[Integer, Float]
|
181
181
|
```
|
182
182
|
|
183
183
|
or
|
184
184
|
|
185
185
|
```ruby
|
186
|
-
Contract C::Or.new(
|
186
|
+
Contract C::Or.new(Integer, Float) => C::Or.new(Integer, Float)
|
187
187
|
```
|
188
188
|
|
189
|
-
whichever you prefer. They both mean the same thing here: make a new instance of `Or` with `
|
189
|
+
whichever you prefer. They both mean the same thing here: make a new instance of `Or` with `Integer` and `Float`. Use that instance to validate the argument.
|
190
190
|
|
191
191
|
### A Product Function
|
192
192
|
|
@@ -455,7 +455,7 @@ Now you can use `Person` wherever you would have used `Or[Hash, nil]`. Your code
|
|
455
455
|
|
456
456
|
Contracts are very easy to define. To re-iterate, there are 5 kinds of contracts:
|
457
457
|
|
458
|
-
- the name of a class (like `String` or `
|
458
|
+
- the name of a class (like `String` or `Integer`)
|
459
459
|
- a constant (like `nil` or `1`)
|
460
460
|
- a `Proc` that takes a value and returns true or false to indicate whether the contract passed or not
|
461
461
|
- a class that responds to the `valid?` class method (more on this later)
|
@@ -511,7 +511,7 @@ The `Or` contract takes a sequence of contracts, and passes if any of them pass.
|
|
511
511
|
This class inherits from `CallableClass`, which allows us to use `[]` when using the class:
|
512
512
|
|
513
513
|
```ruby
|
514
|
-
Contract C::Or[
|
514
|
+
Contract C::Or[Integer, Float] => C::Num
|
515
515
|
def double(x)
|
516
516
|
2 * x
|
517
517
|
end
|
@@ -520,7 +520,7 @@ end
|
|
520
520
|
Without `CallableClass`, we would have to use `.new` instead:
|
521
521
|
|
522
522
|
```ruby
|
523
|
-
Contract C::Or.new(
|
523
|
+
Contract C::Or.new(Integer, Float) => C::Num
|
524
524
|
def double(x)
|
525
525
|
# etc
|
526
526
|
```
|
@@ -723,7 +723,7 @@ class MyBirthday < Struct.new(:day, :month)
|
|
723
723
|
invariant(:day) { 1 <= day && day <= 31 }
|
724
724
|
invariant(:month) { 1 <= month && month <= 12 }
|
725
725
|
|
726
|
-
Contract C::None =>
|
726
|
+
Contract C::None => Integer
|
727
727
|
def silly_next_day!
|
728
728
|
self.day += 1
|
729
729
|
end
|
data/contracts.gemspec
CHANGED
@@ -13,8 +13,4 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.homepage = "https://github.com/egonSchiele/contracts.ruby"
|
14
14
|
s.license = "BSD-2-Clause"
|
15
15
|
s.required_ruby_version = [">= 3.0", "< 4"]
|
16
|
-
s.post_install_message = "
|
17
|
-
0.16.x will be the supporting Ruby 2.x and be feature frozen (only fixes will be released)
|
18
|
-
For Ruby 3.x use 0.17.x or later (might not be released yet)
|
19
|
-
"
|
20
16
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
Feature: KeywordArgs when used with optional positional arguments
|
2
|
+
|
3
|
+
Checks that the argument is an options hash, and all required keyword arguments are present, and all values pass their respective contracts
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
Contract Any, KeywordArgs[:number => Num, :description => Optional[String]] => Any
|
7
|
+
```
|
8
|
+
|
9
|
+
Background:
|
10
|
+
Given a file named "keyword_args_with_optional_positional_args_usage.rb" with:
|
11
|
+
"""ruby
|
12
|
+
require "contracts"
|
13
|
+
C = Contracts
|
14
|
+
|
15
|
+
class Example
|
16
|
+
include Contracts::Core
|
17
|
+
|
18
|
+
Contract C::Any, String, C::KeywordArgs[b: C::Optional[String]] => Symbol
|
19
|
+
def foo(output, a = 'a', b: 'b')
|
20
|
+
p [a, b]
|
21
|
+
output
|
22
|
+
end
|
23
|
+
end
|
24
|
+
"""
|
25
|
+
|
26
|
+
Scenario: Accepts arguments when only require arguments filled and valid
|
27
|
+
Given a file named "accepts_all_filled_valid_args.rb" with:
|
28
|
+
"""ruby
|
29
|
+
require "./keyword_args_with_optional_positional_args_usage"
|
30
|
+
puts Example.new.foo(:output)
|
31
|
+
"""
|
32
|
+
When I run `ruby accepts_all_filled_valid_args.rb`
|
33
|
+
Then output should contain:
|
34
|
+
"""
|
35
|
+
["a", "b"]
|
36
|
+
output
|
37
|
+
"""
|
38
|
+
|
39
|
+
Scenario: Accepts arguments when all filled and valid
|
40
|
+
Given a file named "accepts_all_filled_valid_args.rb" with:
|
41
|
+
"""ruby
|
42
|
+
require "./keyword_args_with_optional_positional_args_usage"
|
43
|
+
puts Example.new.foo(:output, 'c', b: 'd')
|
44
|
+
"""
|
45
|
+
When I run `ruby accepts_all_filled_valid_args.rb`
|
46
|
+
Then output should contain:
|
47
|
+
"""
|
48
|
+
["c", "d"]
|
49
|
+
output
|
50
|
+
"""
|
51
|
+
|
52
|
+
Scenario: Accepts arguments when only require arguments & optional keyword arguments filled and valid
|
53
|
+
Given a file named "accepts_all_filled_valid_args.rb" with:
|
54
|
+
"""ruby
|
55
|
+
require "./keyword_args_with_optional_positional_args_usage"
|
56
|
+
puts Example.new.foo(:output, b: 'd')
|
57
|
+
"""
|
58
|
+
When I run `ruby accepts_all_filled_valid_args.rb`
|
59
|
+
Then output should contain:
|
60
|
+
"""
|
61
|
+
["a", "d"]
|
62
|
+
output
|
63
|
+
"""
|
64
|
+
|
65
|
+
Scenario: Accepts arguments when only require arguments & optional positional arguments filled and valid
|
66
|
+
Given a file named "accepts_all_filled_valid_args.rb" with:
|
67
|
+
"""ruby
|
68
|
+
require "./keyword_args_with_optional_positional_args_usage"
|
69
|
+
puts Example.new.foo(:output, 'c')
|
70
|
+
"""
|
71
|
+
When I run `ruby accepts_all_filled_valid_args.rb`
|
72
|
+
Then output should contain:
|
73
|
+
"""
|
74
|
+
["c", "b"]
|
75
|
+
output
|
76
|
+
"""
|
@@ -26,7 +26,8 @@ Feature: None
|
|
26
26
|
def autorescue
|
27
27
|
yield
|
28
28
|
rescue => e
|
29
|
-
|
29
|
+
# Since ruby 3.2 the `#inspect` output becomes a bit different
|
30
|
+
puts e.inspect.gsub(/^#</, "").gsub(/Error:\"/, "Error: ")
|
30
31
|
end
|
31
32
|
"""
|
32
33
|
Given a file named "none_usage.rb" with:
|
@@ -42,6 +43,11 @@ Feature: None
|
|
42
43
|
def self.a_symbol(*args)
|
43
44
|
:a_symbol
|
44
45
|
end
|
46
|
+
|
47
|
+
Contract C::None => Symbol
|
48
|
+
def a_symbol(*args)
|
49
|
+
:a_symbol
|
50
|
+
end
|
45
51
|
end
|
46
52
|
"""
|
47
53
|
|
@@ -61,14 +67,14 @@ Feature: None
|
|
61
67
|
Given a file named "anything.rb" with:
|
62
68
|
"""ruby
|
63
69
|
require "./none_usage"
|
64
|
-
autorescue { Example.a_symbol(nil) }
|
65
|
-
autorescue { Example.a_symbol(12) }
|
66
|
-
autorescue { Example.a_symbol(37.5) }
|
67
|
-
autorescue { Example.a_symbol("foo") }
|
68
|
-
autorescue { Example.a_symbol(:foo) }
|
69
|
-
autorescue { Example.a_symbol({}) }
|
70
|
-
autorescue { Example.a_symbol([]) }
|
71
|
-
autorescue { Example.a_symbol(Object) }
|
70
|
+
autorescue { Example.new.a_symbol(nil) }
|
71
|
+
autorescue { Example.new.a_symbol(12) }
|
72
|
+
autorescue { Example.new.a_symbol(37.5) }
|
73
|
+
autorescue { Example.new.a_symbol("foo") }
|
74
|
+
autorescue { Example.new.a_symbol(:foo) }
|
75
|
+
autorescue { Example.new.a_symbol({}) }
|
76
|
+
autorescue { Example.new.a_symbol([]) }
|
77
|
+
autorescue { Example.new.a_symbol(Object) }
|
72
78
|
"""
|
73
79
|
When I run `ruby anything.rb`
|
74
80
|
|
@@ -95,7 +95,7 @@ module Contracts
|
|
95
95
|
|
96
96
|
# Takes a variable number of contracts.
|
97
97
|
# The contract passes if any of the contracts pass.
|
98
|
-
# Example: <tt>Or[
|
98
|
+
# Example: <tt>Or[Integer, Float]</tt>
|
99
99
|
class Or < CallableClass
|
100
100
|
def initialize(*vals)
|
101
101
|
super()
|
@@ -120,7 +120,7 @@ module Contracts
|
|
120
120
|
|
121
121
|
# Takes a variable number of contracts.
|
122
122
|
# The contract passes if exactly one of those contracts pass.
|
123
|
-
# Example: <tt>Xor[
|
123
|
+
# Example: <tt>Xor[Integer, Float]</tt>
|
124
124
|
class Xor < CallableClass
|
125
125
|
def initialize(*vals)
|
126
126
|
super()
|
@@ -146,7 +146,7 @@ module Contracts
|
|
146
146
|
|
147
147
|
# Takes a variable number of contracts.
|
148
148
|
# The contract passes if all contracts pass.
|
149
|
-
# Example: <tt>And[
|
149
|
+
# Example: <tt>And[Integer, Float]</tt>
|
150
150
|
class And < CallableClass
|
151
151
|
def initialize(*vals)
|
152
152
|
super()
|
data/lib/contracts/call_with.rb
CHANGED
@@ -12,8 +12,20 @@ module Contracts
|
|
12
12
|
# Explicitly append blk=nil if nil != Proc contract violation anticipated
|
13
13
|
nil_block_appended = maybe_append_block!(args, blk)
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
if @kargs_validator && !@kargs_validator[kargs]
|
16
|
+
data = {
|
17
|
+
arg: kargs,
|
18
|
+
contract: kargs_contract,
|
19
|
+
class: klass,
|
20
|
+
method: method,
|
21
|
+
contracts: self,
|
22
|
+
arg_pos: :keyword,
|
23
|
+
total_args: args.size,
|
24
|
+
return_value: false,
|
25
|
+
}
|
26
|
+
return ParamContractError.new("as return value", data) if returns
|
27
|
+
return unless Contract.failure_callback(data)
|
28
|
+
end
|
17
29
|
|
18
30
|
# Loop forward validating the arguments up to the splat (if there is one)
|
19
31
|
(@args_contract_index || args.size).times do |i|
|
@@ -84,7 +96,6 @@ module Contracts
|
|
84
96
|
# If we put the block into args for validating, restore the args
|
85
97
|
# OR if we added a fake nil at the end because a block wasn't passed in.
|
86
98
|
args.slice!(-1) if blk || nil_block_appended
|
87
|
-
args.slice!(-1) if kargs_appended
|
88
99
|
result = if method.respond_to?(:call)
|
89
100
|
# proc, block, lambda, etc
|
90
101
|
method.call(*args, **kargs, &blk)
|
data/lib/contracts/formatters.rb
CHANGED
data/lib/contracts/version.rb
CHANGED
data/lib/contracts.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "contracts/version"
|
3
4
|
require "contracts/attrs"
|
4
5
|
require "contracts/builtin_contracts"
|
5
6
|
require "contracts/decorators"
|
@@ -52,7 +53,7 @@ class Contract < Contracts::Decorator
|
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
|
-
attr_reader :args_contracts, :ret_contract, :klass, :method
|
56
|
+
attr_reader :args_contracts, :kargs_contract, :ret_contract, :klass, :method
|
56
57
|
|
57
58
|
def initialize(klass, method, *contracts)
|
58
59
|
super(klass, method)
|
@@ -69,6 +70,9 @@ class Contract < Contracts::Decorator
|
|
69
70
|
|
70
71
|
# internally we just convert that return value syntax back to an array
|
71
72
|
@args_contracts = contracts[0, contracts.size - 1] + contracts[-1].keys
|
73
|
+
# Extract contract for keyword arguments
|
74
|
+
@kargs_contract = args_contracts.find { |c| c.is_a?(Contracts::Builtin::KeywordArgs) }
|
75
|
+
args_contracts.delete(kargs_contract) if kargs_contract
|
72
76
|
|
73
77
|
@ret_contract = contracts[-1].values[0]
|
74
78
|
|
@@ -76,6 +80,8 @@ class Contract < Contracts::Decorator
|
|
76
80
|
Contract.make_validator(contract)
|
77
81
|
end
|
78
82
|
|
83
|
+
@kargs_validator = kargs_contract ? Contract.make_validator(kargs_contract) : nil
|
84
|
+
|
79
85
|
@args_contract_index = args_contracts.index do |contract|
|
80
86
|
contract.is_a? Contracts::Args
|
81
87
|
end
|
@@ -93,16 +99,6 @@ class Contract < Contracts::Decorator
|
|
93
99
|
|
94
100
|
# ====
|
95
101
|
|
96
|
-
# == @has_options_contract
|
97
|
-
last_contract = args_contracts.last
|
98
|
-
penultimate_contract = args_contracts[-2]
|
99
|
-
@has_options_contract = if @has_proc_contract
|
100
|
-
penultimate_contract.is_a?(Contracts::Builtin::KeywordArgs)
|
101
|
-
else
|
102
|
-
last_contract.is_a?(Contracts::Builtin::KeywordArgs)
|
103
|
-
end
|
104
|
-
# ===
|
105
|
-
|
106
102
|
@klass, @method = klass, method
|
107
103
|
end
|
108
104
|
|
@@ -255,19 +251,6 @@ class Contract < Contracts::Decorator
|
|
255
251
|
true
|
256
252
|
end
|
257
253
|
|
258
|
-
# Same thing for when we have named params but didn't pass any in.
|
259
|
-
# returns true if it appended nil
|
260
|
-
def maybe_append_options! args, kargs, blk
|
261
|
-
return false unless @has_options_contract
|
262
|
-
|
263
|
-
if @has_proc_contract && args_contracts[-2].is_a?(Contracts::Builtin::KeywordArgs)
|
264
|
-
args.insert(-2, kargs)
|
265
|
-
elsif args_contracts[-1].is_a?(Contracts::Builtin::KeywordArgs)
|
266
|
-
args << kargs
|
267
|
-
end
|
268
|
-
true
|
269
|
-
end
|
270
|
-
|
271
254
|
# Used to determine type of failure exception this contract should raise in case of failure
|
272
255
|
def failure_exception
|
273
256
|
if pattern_match?
|
data/spec/fixtures/fixtures.rb
CHANGED
@@ -100,11 +100,11 @@ class GenericExample
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
Contract ({ :name => String, :age =>
|
103
|
+
Contract ({ :name => String, :age => Integer }) => nil
|
104
104
|
def person(data)
|
105
105
|
end
|
106
106
|
|
107
|
-
Contract C::StrictHash[{ :name => String, :age =>
|
107
|
+
Contract C::StrictHash[{ :name => String, :age => Integer }] => nil
|
108
108
|
def strict_person(data)
|
109
109
|
end
|
110
110
|
|
@@ -119,7 +119,7 @@ class GenericExample
|
|
119
119
|
def nested_hash_complex_contracts(data)
|
120
120
|
end
|
121
121
|
|
122
|
-
Contract C::KeywordArgs[:name => String, :age =>
|
122
|
+
Contract C::KeywordArgs[:name => String, :age => Integer] => nil
|
123
123
|
def person_keywordargs(name: "name", age: 10)
|
124
124
|
end
|
125
125
|
|
@@ -529,30 +529,30 @@ class MyBirthday
|
|
529
529
|
@month = month
|
530
530
|
end
|
531
531
|
|
532
|
-
Contract C::None =>
|
532
|
+
Contract C::None => Integer
|
533
533
|
def silly_next_day!
|
534
534
|
self.day += 1
|
535
535
|
end
|
536
536
|
|
537
|
-
Contract C::None =>
|
537
|
+
Contract C::None => Integer
|
538
538
|
def silly_next_month!
|
539
539
|
self.month += 1
|
540
540
|
end
|
541
541
|
|
542
|
-
Contract C::None =>
|
542
|
+
Contract C::None => Integer
|
543
543
|
def clever_next_day!
|
544
544
|
return clever_next_month! if day == 31
|
545
545
|
self.day += 1
|
546
546
|
end
|
547
547
|
|
548
|
-
Contract C::None =>
|
548
|
+
Contract C::None => Integer
|
549
549
|
def clever_next_month!
|
550
550
|
return next_year! if month == 12
|
551
551
|
self.month += 1
|
552
552
|
self.day = 1
|
553
553
|
end
|
554
554
|
|
555
|
-
Contract C::None =>
|
555
|
+
Contract C::None => Integer
|
556
556
|
def next_year!
|
557
557
|
self.month = 1
|
558
558
|
self.day = 1
|
@@ -610,7 +610,7 @@ with_enabled_no_contracts do
|
|
610
610
|
body + "!"
|
611
611
|
end
|
612
612
|
|
613
|
-
Contract
|
613
|
+
Contract Integer, String => String
|
614
614
|
def on_response(status, body)
|
615
615
|
"error #{status}: #{body}"
|
616
616
|
end
|
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:
|
4
|
+
version: 0.17.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aditya Bhargava
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-05 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
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- features/builtin_contracts/hash_of.feature
|
57
57
|
- features/builtin_contracts/int.feature
|
58
58
|
- features/builtin_contracts/keyword_args.feature
|
59
|
+
- features/builtin_contracts/keyword_args_with_optional_positional_args.feature
|
59
60
|
- features/builtin_contracts/maybe.feature
|
60
61
|
- features/builtin_contracts/nat.feature
|
61
62
|
- features/builtin_contracts/nat_pos.feature
|
@@ -111,9 +112,7 @@ homepage: https://github.com/egonSchiele/contracts.ruby
|
|
111
112
|
licenses:
|
112
113
|
- BSD-2-Clause
|
113
114
|
metadata: {}
|
114
|
-
post_install_message:
|
115
|
-
frozen (only fixes will be released)\n For Ruby 3.x use 0.17.x or later (might
|
116
|
-
not be released yet)\n "
|
115
|
+
post_install_message:
|
117
116
|
rdoc_options: []
|
118
117
|
require_paths:
|
119
118
|
- lib
|
@@ -131,8 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
130
|
- !ruby/object:Gem::Version
|
132
131
|
version: '0'
|
133
132
|
requirements: []
|
134
|
-
rubygems_version: 3.
|
135
|
-
signing_key:
|
133
|
+
rubygems_version: 3.4.10
|
134
|
+
signing_key:
|
136
135
|
specification_version: 4
|
137
136
|
summary: Contracts for Ruby.
|
138
137
|
test_files: []
|