contracts 0.17 → 0.17.1
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 +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 [](https://github.com/egonSchiele/contracts.ruby/actions/workflows/tests.yaml) [](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: []
|