contracts 0.12.0 → 0.16.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 +5 -13
- data/.github/workflows/code_style_checks.yaml +36 -0
- data/.github/workflows/tests.yaml +47 -0
- data/CHANGELOG.markdown +57 -6
- data/Gemfile +2 -2
- data/LICENSE +23 -0
- data/README.md +14 -6
- data/Rakefile +3 -6
- data/TUTORIAL.md +55 -26
- data/contracts.gemspec +6 -1
- data/dependabot.yml +20 -0
- data/features/basics/pretty-print.feature +241 -0
- 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.rb +48 -12
- data/lib/contracts/attrs.rb +24 -0
- data/lib/contracts/builtin_contracts.rb +60 -1
- data/lib/contracts/call_with.rb +22 -11
- data/lib/contracts/core.rb +0 -2
- data/lib/contracts/decorators.rb +5 -0
- data/lib/contracts/engine/eigenclass.rb +4 -0
- data/lib/contracts/engine/target.rb +2 -0
- data/lib/contracts/formatters.rb +4 -2
- data/lib/contracts/method_handler.rb +14 -22
- data/lib/contracts/support.rb +11 -9
- data/lib/contracts/version.rb +1 -1
- data/spec/attrs_spec.rb +119 -0
- data/spec/builtin_contracts_spec.rb +157 -95
- data/spec/contracts_spec.rb +50 -29
- data/spec/fixtures/fixtures.rb +58 -0
- data/spec/methods_spec.rb +54 -0
- data/spec/override_validators_spec.rb +1 -1
- data/spec/ruby_version_specific/contracts_spec_2.0.rb +15 -0
- data/spec/ruby_version_specific/contracts_spec_2.1.rb +1 -1
- data/spec/validators_spec.rb +1 -1
- metadata +25 -14
- data/script/cucumber +0 -5
data/spec/contracts_spec.rb
CHANGED
@@ -7,7 +7,7 @@ RSpec.describe "Contracts:" do
|
|
7
7
|
it "should fail for insufficient arguments" do
|
8
8
|
expect do
|
9
9
|
@o.hello
|
10
|
-
end.to raise_error
|
10
|
+
end.to raise_error ArgumentError
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should fail for insufficient contracts" do
|
@@ -32,7 +32,7 @@ RSpec.describe "Contracts:" do
|
|
32
32
|
1
|
33
33
|
end
|
34
34
|
end
|
35
|
-
end.to raise_error
|
35
|
+
end.to raise_error NameError
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -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
|
@@ -655,6 +637,28 @@ RSpec.describe "Contracts:" do
|
|
655
637
|
end.to raise_error(ContractError, not_s(delim "String or Symbol"))
|
656
638
|
end
|
657
639
|
|
640
|
+
it "should wrap and pretty print for long param contracts" do
|
641
|
+
expect do
|
642
|
+
@o.long_array_param_contracts(true)
|
643
|
+
end.to(
|
644
|
+
raise_error(
|
645
|
+
ParamContractError,
|
646
|
+
/\[\(String or Symbol\),\n \(String or Symbol\),/
|
647
|
+
)
|
648
|
+
)
|
649
|
+
end
|
650
|
+
|
651
|
+
it "should wrap and pretty print for long return contracts" do
|
652
|
+
expect do
|
653
|
+
@o.long_array_return_contracts
|
654
|
+
end.to(
|
655
|
+
raise_error(
|
656
|
+
ReturnContractError,
|
657
|
+
/\[\(String or Symbol\),\n \(String or Symbol\),/
|
658
|
+
)
|
659
|
+
)
|
660
|
+
end
|
661
|
+
|
658
662
|
it "should not contain Contracts:: module prefix" do
|
659
663
|
expect do
|
660
664
|
@o.double("bad")
|
@@ -714,7 +718,7 @@ RSpec.describe "Contracts:" do
|
|
714
718
|
it "should apply the contract to an inherited method" do
|
715
719
|
c = Child.new
|
716
720
|
expect { c.double(2) }.to_not raise_error
|
717
|
-
expect { c.double("asd") }.to raise_error
|
721
|
+
expect { c.double("asd") }.to raise_error ParamContractError
|
718
722
|
end
|
719
723
|
end
|
720
724
|
|
@@ -745,5 +749,22 @@ RSpec.describe "Contracts:" do
|
|
745
749
|
it "works correctly with methods with passing contracts" do
|
746
750
|
expect { klass.new.foo(42) }.to raise_error(ContractError, /Expected: String/)
|
747
751
|
end
|
752
|
+
|
753
|
+
# See the discussion on this issue:
|
754
|
+
# https://github.com/egonSchiele/contracts.ruby/issues/229
|
755
|
+
it "should not fail with 'undefined method 'Contract''" do
|
756
|
+
expect do
|
757
|
+
class ModuleThenContracts
|
758
|
+
include ModuleWithContracts
|
759
|
+
include Contracts::Core
|
760
|
+
|
761
|
+
# fails on this line
|
762
|
+
Contract C::Num => C::Num
|
763
|
+
def double(x)
|
764
|
+
x * 2
|
765
|
+
end
|
766
|
+
end
|
767
|
+
end.to_not raise_error
|
768
|
+
end
|
748
769
|
end
|
749
770
|
end
|
data/spec/fixtures/fixtures.rb
CHANGED
@@ -104,6 +104,10 @@ class GenericExample
|
|
104
104
|
def person(data)
|
105
105
|
end
|
106
106
|
|
107
|
+
Contract C::StrictHash[{ :name => String, :age => Fixnum }] => nil
|
108
|
+
def strict_person(data)
|
109
|
+
end
|
110
|
+
|
107
111
|
Contract ({ :rigged => C::Or[TrueClass, FalseClass] }) => nil
|
108
112
|
def hash_complex_contracts(data)
|
109
113
|
end
|
@@ -119,6 +123,11 @@ class GenericExample
|
|
119
123
|
def person_keywordargs(data)
|
120
124
|
end
|
121
125
|
|
126
|
+
# Testing overloaded method
|
127
|
+
Contract String, Fixnum => nil
|
128
|
+
def person_keywordargs(name, age)
|
129
|
+
end
|
130
|
+
|
122
131
|
Contract C::KeywordArgs[:hash => C::HashOf[Symbol, C::Num]] => nil
|
123
132
|
def hash_keywordargs(data)
|
124
133
|
end
|
@@ -143,6 +152,30 @@ class GenericExample
|
|
143
152
|
def nested_array_complex_contracts(data)
|
144
153
|
end
|
145
154
|
|
155
|
+
Contract [
|
156
|
+
C::Or[String, Symbol],
|
157
|
+
C::Or[String, Symbol],
|
158
|
+
C::Or[String, Symbol],
|
159
|
+
C::Or[String, Symbol],
|
160
|
+
C::Or[String, Symbol],
|
161
|
+
C::Or[String, Symbol],
|
162
|
+
C::Or[String, Symbol]
|
163
|
+
] => nil
|
164
|
+
def long_array_param_contracts(data)
|
165
|
+
end
|
166
|
+
|
167
|
+
Contract C::None => [
|
168
|
+
C::Or[String, Symbol],
|
169
|
+
C::Or[String, Symbol],
|
170
|
+
C::Or[String, Symbol],
|
171
|
+
C::Or[String, Symbol],
|
172
|
+
C::Or[String, Symbol],
|
173
|
+
C::Or[String, Symbol],
|
174
|
+
C::Or[String, Symbol]
|
175
|
+
]
|
176
|
+
def long_array_return_contracts
|
177
|
+
end
|
178
|
+
|
146
179
|
Contract Proc => C::Any
|
147
180
|
def do_call(&block)
|
148
181
|
block.call
|
@@ -263,6 +296,10 @@ class GenericExample
|
|
263
296
|
r.first
|
264
297
|
end
|
265
298
|
|
299
|
+
Contract C::DescendantOf[Enumerable] => nil
|
300
|
+
def enumerable_descendant_test(enum)
|
301
|
+
end
|
302
|
+
|
266
303
|
Contract C::Bool => nil
|
267
304
|
def bool_test(x)
|
268
305
|
end
|
@@ -621,6 +658,12 @@ class SingletonInheritanceExample
|
|
621
658
|
end
|
622
659
|
|
623
660
|
class SingletonInheritanceExampleSubclass < SingletonInheritanceExample
|
661
|
+
class << self
|
662
|
+
Contract Integer => Integer
|
663
|
+
def num(int)
|
664
|
+
int
|
665
|
+
end
|
666
|
+
end
|
624
667
|
end
|
625
668
|
|
626
669
|
class BareOptionalContractUsed
|
@@ -670,3 +713,18 @@ module ModuleContractExample
|
|
670
713
|
:world
|
671
714
|
end
|
672
715
|
end
|
716
|
+
|
717
|
+
module ModuleWithContracts
|
718
|
+
def self.included(base)
|
719
|
+
base.extend ClassMethods
|
720
|
+
end
|
721
|
+
|
722
|
+
module ClassMethods
|
723
|
+
include Contracts::Core
|
724
|
+
|
725
|
+
Contract C::None => String
|
726
|
+
def foo
|
727
|
+
"bar"
|
728
|
+
end
|
729
|
+
end
|
730
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
RSpec.describe "Contracts:" do
|
2
|
+
describe "method called with blocks" do
|
3
|
+
module FuncTest
|
4
|
+
include Contracts::Core
|
5
|
+
include Contracts::Builtin
|
6
|
+
|
7
|
+
Contract Func[Num=>Num] => nil
|
8
|
+
def foo(&blk)
|
9
|
+
_ = blk.call(2)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
Contract Num, Func[Num=>Num] => nil
|
14
|
+
def foo2(a, &blk)
|
15
|
+
_ = blk.call(2)
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
Contract Func[Num=>Num] => nil
|
20
|
+
def bar(blk)
|
21
|
+
_ = blk.call(2)
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
Contract Num, Func[Num=>Num] => nil
|
26
|
+
def bar2(a, blk)
|
27
|
+
_ = blk.call(2)
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def obj
|
33
|
+
Object.new.tap do |o|
|
34
|
+
o.extend(FuncTest)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should enforce return value inside block with no other parameter" do
|
39
|
+
expect { obj.foo(&:to_s) }.to raise_error ReturnContractError
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should enforce return value inside block with other parameter" do
|
43
|
+
expect { obj.foo2(2) { |x| x.to_s } }.to raise_error ReturnContractError
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should enforce return value inside lambda with no other parameter" do
|
47
|
+
expect { obj.bar lambda { |x| x.to_s } }.to raise_error ReturnContractError
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should enforce return value inside lambda with other parameter" do
|
51
|
+
expect { obj.bar2(2, lambda { |x| x.to_s }) }.to raise_error ReturnContractError
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -7,6 +7,11 @@ class GenericExample
|
|
7
7
|
Contract ({foo: C::Nat}) => nil
|
8
8
|
def nat_test_with_kwarg(foo: 10)
|
9
9
|
end
|
10
|
+
|
11
|
+
Contract C::KeywordArgs[name: C::Optional[String]], C::Func[String => String] => String
|
12
|
+
def keyword_args_hello(name: "Adit", &block)
|
13
|
+
"Hey, #{yield name}!"
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
RSpec.describe "Contracts:" do
|
@@ -37,4 +42,14 @@ RSpec.describe "Contracts:" do
|
|
37
42
|
expect { @o.nat_test_with_kwarg }.to raise_error(ContractError)
|
38
43
|
end
|
39
44
|
end
|
45
|
+
|
46
|
+
describe "keyword args with defaults, with a block" do
|
47
|
+
it "should work when both keyword args and a block is given" do
|
48
|
+
expect(@o.keyword_args_hello(name: "maggie", &:upcase)).to eq("Hey, MAGGIE!")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should work even when keyword args aren't given" do
|
52
|
+
expect(@o.keyword_args_hello(&:upcase)).to eq("Hey, ADIT!")
|
53
|
+
end
|
54
|
+
end
|
40
55
|
end
|
@@ -51,7 +51,7 @@ RSpec.describe "Contracts:" do
|
|
51
51
|
end.to raise_error(ContractError)
|
52
52
|
end
|
53
53
|
|
54
|
-
it "should fail when passed nil to an optional argument which contract
|
54
|
+
it "should fail when passed nil to an optional argument which contract shouldn't accept nil" do
|
55
55
|
expect do
|
56
56
|
@o.complicated("a", true, :b, :c, 2.0, e: (1..5), f: nil, g: :d) do |x|
|
57
57
|
x
|
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.16.1
|
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: 2021-04-17 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,12 +18,15 @@ executables: []
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
-
- .
|
22
|
-
- .
|
23
|
-
- .
|
24
|
-
- .
|
21
|
+
- ".github/workflows/code_style_checks.yaml"
|
22
|
+
- ".github/workflows/tests.yaml"
|
23
|
+
- ".gitignore"
|
24
|
+
- ".rspec"
|
25
|
+
- ".rubocop.yml"
|
26
|
+
- ".rubocop_todo.yml"
|
25
27
|
- CHANGELOG.markdown
|
26
28
|
- Gemfile
|
29
|
+
- LICENSE
|
27
30
|
- README.md
|
28
31
|
- Rakefile
|
29
32
|
- TODO.markdown
|
@@ -35,8 +38,10 @@ files:
|
|
35
38
|
- benchmarks/wrap_test.rb
|
36
39
|
- contracts.gemspec
|
37
40
|
- cucumber.yml
|
41
|
+
- dependabot.yml
|
38
42
|
- features/README.md
|
39
43
|
- features/basics/functype.feature
|
44
|
+
- features/basics/pretty-print.feature
|
40
45
|
- features/basics/simple_example.feature
|
41
46
|
- features/builtin_contracts/README.md
|
42
47
|
- features/builtin_contracts/and.feature
|
@@ -49,9 +54,11 @@ files:
|
|
49
54
|
- features/builtin_contracts/exactly.feature
|
50
55
|
- features/builtin_contracts/func.feature
|
51
56
|
- features/builtin_contracts/hash_of.feature
|
57
|
+
- features/builtin_contracts/int.feature
|
52
58
|
- features/builtin_contracts/keyword_args.feature
|
53
59
|
- features/builtin_contracts/maybe.feature
|
54
60
|
- features/builtin_contracts/nat.feature
|
61
|
+
- features/builtin_contracts/nat_pos.feature
|
55
62
|
- features/builtin_contracts/neg.feature
|
56
63
|
- features/builtin_contracts/none.feature
|
57
64
|
- features/builtin_contracts/not.feature
|
@@ -65,6 +72,7 @@ files:
|
|
65
72
|
- features/builtin_contracts/xor.feature
|
66
73
|
- features/support/env.rb
|
67
74
|
- lib/contracts.rb
|
75
|
+
- lib/contracts/attrs.rb
|
68
76
|
- lib/contracts/builtin_contracts.rb
|
69
77
|
- lib/contracts/call_with.rb
|
70
78
|
- lib/contracts/core.rb
|
@@ -81,14 +89,15 @@ files:
|
|
81
89
|
- lib/contracts/support.rb
|
82
90
|
- lib/contracts/validators.rb
|
83
91
|
- lib/contracts/version.rb
|
84
|
-
- script/cucumber
|
85
92
|
- script/docs-release
|
86
93
|
- script/docs-staging
|
87
94
|
- script/rubocop.rb
|
95
|
+
- spec/attrs_spec.rb
|
88
96
|
- spec/builtin_contracts_spec.rb
|
89
97
|
- spec/contracts_spec.rb
|
90
98
|
- spec/fixtures/fixtures.rb
|
91
99
|
- spec/invariants_spec.rb
|
100
|
+
- spec/methods_spec.rb
|
92
101
|
- spec/module_spec.rb
|
93
102
|
- spec/override_validators_spec.rb
|
94
103
|
- spec/ruby_version_specific/contracts_spec_1.9.rb
|
@@ -98,26 +107,28 @@ files:
|
|
98
107
|
- spec/support.rb
|
99
108
|
- spec/support_spec.rb
|
100
109
|
- spec/validators_spec.rb
|
101
|
-
homepage:
|
102
|
-
licenses:
|
110
|
+
homepage: https://github.com/egonSchiele/contracts.ruby
|
111
|
+
licenses:
|
112
|
+
- BSD-2-Clause
|
103
113
|
metadata: {}
|
104
|
-
post_install_message:
|
114
|
+
post_install_message: "\n 0.16.x will be the supporting Ruby 2.x and be feature
|
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 "
|
105
117
|
rdoc_options: []
|
106
118
|
require_paths:
|
107
119
|
- lib
|
108
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
109
121
|
requirements:
|
110
|
-
- -
|
122
|
+
- - ">="
|
111
123
|
- !ruby/object:Gem::Version
|
112
124
|
version: '0'
|
113
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
126
|
requirements:
|
115
|
-
- -
|
127
|
+
- - ">="
|
116
128
|
- !ruby/object:Gem::Version
|
117
129
|
version: '0'
|
118
130
|
requirements: []
|
119
|
-
|
120
|
-
rubygems_version: 2.4.8
|
131
|
+
rubygems_version: 3.0.3
|
121
132
|
signing_key:
|
122
133
|
specification_version: 4
|
123
134
|
summary: Contracts for Ruby.
|