entitlements 0.1.8 → 0.2.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 +4 -4
- data/VERSION +1 -1
- data/bin/deploy-entitlements +10 -1
- data/lib/contracts-ruby2/CHANGELOG.markdown +115 -0
- data/lib/contracts-ruby2/Gemfile +17 -0
- data/lib/contracts-ruby2/LICENSE +23 -0
- data/lib/contracts-ruby2/README.md +108 -0
- data/lib/contracts-ruby2/Rakefile +8 -0
- data/lib/contracts-ruby2/TODO.markdown +6 -0
- data/lib/contracts-ruby2/TUTORIAL.md +773 -0
- data/lib/contracts-ruby2/benchmarks/bench.rb +67 -0
- data/lib/contracts-ruby2/benchmarks/hash.rb +69 -0
- data/lib/contracts-ruby2/benchmarks/invariants.rb +91 -0
- data/lib/contracts-ruby2/benchmarks/io.rb +62 -0
- data/lib/contracts-ruby2/benchmarks/wrap_test.rb +57 -0
- data/lib/contracts-ruby2/contracts.gemspec +17 -0
- data/lib/contracts-ruby2/cucumber.yml +1 -0
- data/lib/contracts-ruby2/dependabot.yml +20 -0
- data/lib/contracts-ruby2/features/README.md +17 -0
- data/lib/contracts-ruby2/features/basics/functype.feature +71 -0
- data/lib/contracts-ruby2/features/basics/pretty-print.feature +241 -0
- data/lib/contracts-ruby2/features/basics/simple_example.feature +210 -0
- data/lib/contracts-ruby2/features/builtin_contracts/README.md +22 -0
- data/lib/contracts-ruby2/features/builtin_contracts/and.feature +103 -0
- data/lib/contracts-ruby2/features/builtin_contracts/any.feature +44 -0
- data/lib/contracts-ruby2/features/builtin_contracts/args.feature +80 -0
- data/lib/contracts-ruby2/features/builtin_contracts/array_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/bool.feature +64 -0
- data/lib/contracts-ruby2/features/builtin_contracts/enum.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/eq.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/exactly.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/func.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/hash_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/int.feature +93 -0
- data/lib/contracts-ruby2/features/builtin_contracts/keyword_args.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/maybe.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/nat.feature +115 -0
- data/lib/contracts-ruby2/features/builtin_contracts/nat_pos.feature +119 -0
- data/lib/contracts-ruby2/features/builtin_contracts/neg.feature +115 -0
- data/lib/contracts-ruby2/features/builtin_contracts/none.feature +145 -0
- data/lib/contracts-ruby2/features/builtin_contracts/not.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/num.feature +64 -0
- data/lib/contracts-ruby2/features/builtin_contracts/or.feature +83 -0
- data/lib/contracts-ruby2/features/builtin_contracts/pos.feature +116 -0
- data/lib/contracts-ruby2/features/builtin_contracts/range_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/respond_to.feature +78 -0
- data/lib/contracts-ruby2/features/builtin_contracts/send.feature +147 -0
- data/lib/contracts-ruby2/features/builtin_contracts/set_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/xor.feature +99 -0
- data/lib/contracts-ruby2/features/support/env.rb +6 -0
- data/lib/contracts-ruby2/lib/contracts/attrs.rb +24 -0
- data/lib/contracts-ruby2/lib/contracts/builtin_contracts.rb +542 -0
- data/lib/contracts-ruby2/lib/contracts/call_with.rb +108 -0
- data/lib/contracts-ruby2/lib/contracts/core.rb +52 -0
- data/lib/contracts-ruby2/lib/contracts/decorators.rb +47 -0
- data/lib/contracts-ruby2/lib/contracts/engine/base.rb +136 -0
- data/lib/contracts-ruby2/lib/contracts/engine/eigenclass.rb +50 -0
- data/lib/contracts-ruby2/lib/contracts/engine/target.rb +70 -0
- data/lib/contracts-ruby2/lib/contracts/engine.rb +26 -0
- data/lib/contracts-ruby2/lib/contracts/errors.rb +71 -0
- data/lib/contracts-ruby2/lib/contracts/formatters.rb +136 -0
- data/lib/contracts-ruby2/lib/contracts/invariants.rb +68 -0
- data/lib/contracts-ruby2/lib/contracts/method_handler.rb +187 -0
- data/lib/contracts-ruby2/lib/contracts/method_reference.rb +100 -0
- data/lib/contracts-ruby2/lib/contracts/support.rb +61 -0
- data/lib/contracts-ruby2/lib/contracts/validators.rb +139 -0
- data/lib/contracts-ruby2/lib/contracts/version.rb +3 -0
- data/lib/contracts-ruby2/lib/contracts.rb +281 -0
- data/lib/contracts-ruby2/script/docs-release +3 -0
- data/lib/contracts-ruby2/script/docs-staging +3 -0
- data/lib/contracts-ruby2/script/rubocop.rb +5 -0
- data/lib/contracts-ruby2/spec/attrs_spec.rb +119 -0
- data/lib/contracts-ruby2/spec/builtin_contracts_spec.rb +461 -0
- data/lib/contracts-ruby2/spec/contracts_spec.rb +770 -0
- data/lib/contracts-ruby2/spec/fixtures/fixtures.rb +730 -0
- data/lib/contracts-ruby2/spec/invariants_spec.rb +17 -0
- data/lib/contracts-ruby2/spec/methods_spec.rb +54 -0
- data/lib/contracts-ruby2/spec/module_spec.rb +18 -0
- data/lib/contracts-ruby2/spec/override_validators_spec.rb +162 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
- data/lib/contracts-ruby2/spec/spec_helper.rb +102 -0
- data/lib/contracts-ruby2/spec/support.rb +10 -0
- data/lib/contracts-ruby2/spec/support_spec.rb +21 -0
- data/lib/contracts-ruby2/spec/validators_spec.rb +47 -0
- data/lib/contracts-ruby3/CHANGELOG.markdown +117 -0
- data/lib/contracts-ruby3/Gemfile +21 -0
- data/lib/contracts-ruby3/LICENSE +23 -0
- data/lib/contracts-ruby3/README.md +114 -0
- data/lib/contracts-ruby3/Rakefile +10 -0
- data/lib/contracts-ruby3/TODO.markdown +6 -0
- data/lib/contracts-ruby3/TUTORIAL.md +773 -0
- data/lib/contracts-ruby3/benchmarks/bench.rb +67 -0
- data/lib/contracts-ruby3/benchmarks/hash.rb +69 -0
- data/lib/contracts-ruby3/benchmarks/invariants.rb +91 -0
- data/lib/contracts-ruby3/benchmarks/io.rb +62 -0
- data/lib/contracts-ruby3/benchmarks/wrap_test.rb +57 -0
- data/lib/contracts-ruby3/contracts.gemspec +20 -0
- data/lib/contracts-ruby3/cucumber.yml +1 -0
- data/lib/contracts-ruby3/dependabot.yml +20 -0
- data/lib/contracts-ruby3/features/README.md +17 -0
- data/lib/contracts-ruby3/features/basics/functype.feature +71 -0
- data/lib/contracts-ruby3/features/basics/pretty-print.feature +241 -0
- data/lib/contracts-ruby3/features/basics/simple_example.feature +210 -0
- data/lib/contracts-ruby3/features/builtin_contracts/README.md +22 -0
- data/lib/contracts-ruby3/features/builtin_contracts/and.feature +103 -0
- data/lib/contracts-ruby3/features/builtin_contracts/any.feature +44 -0
- data/lib/contracts-ruby3/features/builtin_contracts/args.feature +80 -0
- data/lib/contracts-ruby3/features/builtin_contracts/array_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/bool.feature +64 -0
- data/lib/contracts-ruby3/features/builtin_contracts/enum.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/eq.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/exactly.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/func.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/hash_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/int.feature +93 -0
- data/lib/contracts-ruby3/features/builtin_contracts/keyword_args.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/maybe.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/nat.feature +115 -0
- data/lib/contracts-ruby3/features/builtin_contracts/nat_pos.feature +119 -0
- data/lib/contracts-ruby3/features/builtin_contracts/neg.feature +115 -0
- data/lib/contracts-ruby3/features/builtin_contracts/none.feature +145 -0
- data/lib/contracts-ruby3/features/builtin_contracts/not.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/num.feature +64 -0
- data/lib/contracts-ruby3/features/builtin_contracts/or.feature +83 -0
- data/lib/contracts-ruby3/features/builtin_contracts/pos.feature +116 -0
- data/lib/contracts-ruby3/features/builtin_contracts/range_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/respond_to.feature +78 -0
- data/lib/contracts-ruby3/features/builtin_contracts/send.feature +147 -0
- data/lib/contracts-ruby3/features/builtin_contracts/set_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/xor.feature +99 -0
- data/lib/contracts-ruby3/features/support/env.rb +8 -0
- data/lib/contracts-ruby3/lib/contracts/attrs.rb +26 -0
- data/lib/contracts-ruby3/lib/contracts/builtin_contracts.rb +575 -0
- data/lib/contracts-ruby3/lib/contracts/call_with.rb +119 -0
- data/lib/contracts-ruby3/lib/contracts/core.rb +54 -0
- data/lib/contracts-ruby3/lib/contracts/decorators.rb +50 -0
- data/lib/contracts-ruby3/lib/contracts/engine/base.rb +137 -0
- data/lib/contracts-ruby3/lib/contracts/engine/eigenclass.rb +51 -0
- data/lib/contracts-ruby3/lib/contracts/engine/target.rb +72 -0
- data/lib/contracts-ruby3/lib/contracts/engine.rb +28 -0
- data/lib/contracts-ruby3/lib/contracts/errors.rb +74 -0
- data/lib/contracts-ruby3/lib/contracts/formatters.rb +140 -0
- data/lib/contracts-ruby3/lib/contracts/invariants.rb +72 -0
- data/lib/contracts-ruby3/lib/contracts/method_handler.rb +197 -0
- data/lib/contracts-ruby3/lib/contracts/method_reference.rb +102 -0
- data/lib/contracts-ruby3/lib/contracts/support.rb +63 -0
- data/lib/contracts-ruby3/lib/contracts/validators.rb +143 -0
- data/lib/contracts-ruby3/lib/contracts/version.rb +5 -0
- data/lib/contracts-ruby3/lib/contracts.rb +290 -0
- data/lib/contracts-ruby3/script/docs-release +3 -0
- data/lib/contracts-ruby3/script/docs-staging +3 -0
- data/lib/contracts-ruby3/script/rubocop.rb +5 -0
- data/lib/contracts-ruby3/spec/attrs_spec.rb +119 -0
- data/lib/contracts-ruby3/spec/builtin_contracts_spec.rb +457 -0
- data/lib/contracts-ruby3/spec/contracts_spec.rb +773 -0
- data/lib/contracts-ruby3/spec/fixtures/fixtures.rb +725 -0
- data/lib/contracts-ruby3/spec/invariants_spec.rb +17 -0
- data/lib/contracts-ruby3/spec/methods_spec.rb +54 -0
- data/lib/contracts-ruby3/spec/module_spec.rb +18 -0
- data/lib/contracts-ruby3/spec/override_validators_spec.rb +162 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
- data/lib/contracts-ruby3/spec/spec_helper.rb +102 -0
- data/lib/contracts-ruby3/spec/support.rb +10 -0
- data/lib/contracts-ruby3/spec/support_spec.rb +21 -0
- data/lib/contracts-ruby3/spec/validators_spec.rb +47 -0
- data/lib/entitlements/data/groups/calculated/yaml.rb +7 -1
- data/lib/entitlements/data/people/yaml.rb +9 -1
- data/lib/entitlements/extras/ldap_group/rules/ldap_group.rb +5 -1
- data/lib/entitlements/extras/orgchart/person_methods.rb +7 -1
- data/lib/entitlements.rb +13 -2
- data/lib/ruby_version_check.rb +17 -0
- metadata +209 -14
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Feature: Pretty printing Contract violations
|
|
2
|
+
|
|
3
|
+
Scenario: Big array argument being passed to big array method parameter
|
|
4
|
+
Given a file named "example.rb" with:
|
|
5
|
+
"""ruby
|
|
6
|
+
require "contracts"
|
|
7
|
+
C = Contracts
|
|
8
|
+
|
|
9
|
+
class Example
|
|
10
|
+
include Contracts::Core
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
Contract [
|
|
14
|
+
C::Or[String, Symbol],
|
|
15
|
+
C::Or[String, Symbol],
|
|
16
|
+
C::Or[String, Symbol],
|
|
17
|
+
C::Or[String, Symbol],
|
|
18
|
+
C::Or[String, Symbol],
|
|
19
|
+
C::Or[String, Symbol],
|
|
20
|
+
C::Or[String, Symbol]
|
|
21
|
+
] => nil
|
|
22
|
+
def run(data)
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
puts Example.run([
|
|
29
|
+
["foo", "foo"],
|
|
30
|
+
["foo", "foo"],
|
|
31
|
+
["foo", "foo"],
|
|
32
|
+
["foo", "foo"],
|
|
33
|
+
["foo", "foo"],
|
|
34
|
+
["foo", "foo"],
|
|
35
|
+
["foo", "foo"],
|
|
36
|
+
["foo", "foo"],
|
|
37
|
+
["foo", "foo"]
|
|
38
|
+
])
|
|
39
|
+
"""
|
|
40
|
+
When I run `ruby example.rb`
|
|
41
|
+
Then the output should contain:
|
|
42
|
+
"""
|
|
43
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
44
|
+
Expected: [(String or Symbol),
|
|
45
|
+
(String or Symbol),
|
|
46
|
+
(String or Symbol),
|
|
47
|
+
(String or Symbol),
|
|
48
|
+
(String or Symbol),
|
|
49
|
+
(String or Symbol),
|
|
50
|
+
(String or Symbol)],
|
|
51
|
+
Actual: [["foo", "foo"],
|
|
52
|
+
["foo", "foo"],
|
|
53
|
+
["foo", "foo"],
|
|
54
|
+
["foo", "foo"],
|
|
55
|
+
["foo", "foo"],
|
|
56
|
+
["foo", "foo"],
|
|
57
|
+
["foo", "foo"],
|
|
58
|
+
["foo", "foo"],
|
|
59
|
+
["foo", "foo"]]
|
|
60
|
+
Value guarded in: Example::run
|
|
61
|
+
With Contract: Array => NilClass
|
|
62
|
+
At: example.rb:17
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
Scenario: Big array value being returned from method expecting different big array type
|
|
66
|
+
Given a file named "example.rb" with:
|
|
67
|
+
"""ruby
|
|
68
|
+
require "contracts"
|
|
69
|
+
C = Contracts
|
|
70
|
+
|
|
71
|
+
class Example
|
|
72
|
+
include Contracts::Core
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
Contract C::None => [
|
|
76
|
+
C::Or[String, Symbol],
|
|
77
|
+
C::Or[String, Symbol],
|
|
78
|
+
C::Or[String, Symbol],
|
|
79
|
+
C::Or[String, Symbol],
|
|
80
|
+
C::Or[String, Symbol],
|
|
81
|
+
C::Or[String, Symbol],
|
|
82
|
+
C::Or[String, Symbol]
|
|
83
|
+
]
|
|
84
|
+
def run
|
|
85
|
+
[
|
|
86
|
+
["foo", "foo"],
|
|
87
|
+
["foo", "foo"],
|
|
88
|
+
["foo", "foo"],
|
|
89
|
+
["foo", "foo"],
|
|
90
|
+
["foo", "foo"],
|
|
91
|
+
["foo", "foo"],
|
|
92
|
+
["foo", "foo"],
|
|
93
|
+
["foo", "foo"],
|
|
94
|
+
["foo", "foo"]
|
|
95
|
+
]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
puts Example.run
|
|
101
|
+
"""
|
|
102
|
+
When I run `ruby example.rb`
|
|
103
|
+
Then the output should contain:
|
|
104
|
+
"""
|
|
105
|
+
: Contract violation for return value: (ReturnContractError)
|
|
106
|
+
Expected: [(String or Symbol),
|
|
107
|
+
(String or Symbol),
|
|
108
|
+
(String or Symbol),
|
|
109
|
+
(String or Symbol),
|
|
110
|
+
(String or Symbol),
|
|
111
|
+
(String or Symbol),
|
|
112
|
+
(String or Symbol)],
|
|
113
|
+
Actual: [["foo", "foo"],
|
|
114
|
+
["foo", "foo"],
|
|
115
|
+
["foo", "foo"],
|
|
116
|
+
["foo", "foo"],
|
|
117
|
+
["foo", "foo"],
|
|
118
|
+
["foo", "foo"],
|
|
119
|
+
["foo", "foo"],
|
|
120
|
+
["foo", "foo"],
|
|
121
|
+
["foo", "foo"]]
|
|
122
|
+
Value guarded in: Example::run
|
|
123
|
+
With Contract: None => Array
|
|
124
|
+
At: example.rb:17
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
Scenario: Big hash argument being passed to big hash method parameter
|
|
128
|
+
Given a file named "example.rb" with:
|
|
129
|
+
"""ruby
|
|
130
|
+
require "contracts"
|
|
131
|
+
C = Contracts
|
|
132
|
+
|
|
133
|
+
class Example
|
|
134
|
+
include Contracts::Core
|
|
135
|
+
|
|
136
|
+
class << self
|
|
137
|
+
Contract ({
|
|
138
|
+
a: C::Or[String, Symbol],
|
|
139
|
+
b: C::Or[String, Symbol],
|
|
140
|
+
c: C::Or[String, Symbol],
|
|
141
|
+
d: C::Or[String, Symbol],
|
|
142
|
+
e: C::Or[String, Symbol],
|
|
143
|
+
f: C::Or[String, Symbol],
|
|
144
|
+
g: C::Or[String, Symbol]
|
|
145
|
+
}) => nil
|
|
146
|
+
def run(data)
|
|
147
|
+
nil
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
puts Example.run({
|
|
153
|
+
a: ["foo", "foo"],
|
|
154
|
+
b: ["foo", "foo"],
|
|
155
|
+
c: ["foo", "foo"],
|
|
156
|
+
d: ["foo", "foo"],
|
|
157
|
+
e: ["foo", "foo"],
|
|
158
|
+
f: ["foo", "foo"],
|
|
159
|
+
g: ["foo", "foo"]
|
|
160
|
+
})
|
|
161
|
+
"""
|
|
162
|
+
When I run `ruby example.rb`
|
|
163
|
+
Then the output should contain:
|
|
164
|
+
"""
|
|
165
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
166
|
+
Expected: {:a=>(String or Symbol),
|
|
167
|
+
:b=>(String or Symbol),
|
|
168
|
+
:c=>(String or Symbol),
|
|
169
|
+
:d=>(String or Symbol),
|
|
170
|
+
:e=>(String or Symbol),
|
|
171
|
+
:f=>(String or Symbol),
|
|
172
|
+
:g=>(String or Symbol)},
|
|
173
|
+
Actual: {:a=>["foo", "foo"],
|
|
174
|
+
:b=>["foo", "foo"],
|
|
175
|
+
:c=>["foo", "foo"],
|
|
176
|
+
:d=>["foo", "foo"],
|
|
177
|
+
:e=>["foo", "foo"],
|
|
178
|
+
:f=>["foo", "foo"],
|
|
179
|
+
:g=>["foo", "foo"]}
|
|
180
|
+
Value guarded in: Example::run
|
|
181
|
+
With Contract: Hash => NilClass
|
|
182
|
+
At: example.rb:17
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
Scenario: Big hash value being returned from method expecting different big hash type
|
|
186
|
+
Given a file named "example.rb" with:
|
|
187
|
+
"""ruby
|
|
188
|
+
require "contracts"
|
|
189
|
+
C = Contracts
|
|
190
|
+
|
|
191
|
+
class Example
|
|
192
|
+
include Contracts::Core
|
|
193
|
+
|
|
194
|
+
class << self
|
|
195
|
+
Contract C::None => ({
|
|
196
|
+
a: C::Or[String, Symbol],
|
|
197
|
+
b: C::Or[String, Symbol],
|
|
198
|
+
c: C::Or[String, Symbol],
|
|
199
|
+
d: C::Or[String, Symbol],
|
|
200
|
+
e: C::Or[String, Symbol],
|
|
201
|
+
f: C::Or[String, Symbol],
|
|
202
|
+
g: C::Or[String, Symbol]
|
|
203
|
+
})
|
|
204
|
+
def run
|
|
205
|
+
{
|
|
206
|
+
a: ["foo", "foo"],
|
|
207
|
+
b: ["foo", "foo"],
|
|
208
|
+
c: ["foo", "foo"],
|
|
209
|
+
d: ["foo", "foo"],
|
|
210
|
+
e: ["foo", "foo"],
|
|
211
|
+
f: ["foo", "foo"],
|
|
212
|
+
g: ["foo", "foo"]
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
puts Example.run
|
|
219
|
+
"""
|
|
220
|
+
When I run `ruby example.rb`
|
|
221
|
+
Then the output should contain:
|
|
222
|
+
"""
|
|
223
|
+
: Contract violation for return value: (ReturnContractError)
|
|
224
|
+
Expected: {:a=>(String or Symbol),
|
|
225
|
+
:b=>(String or Symbol),
|
|
226
|
+
:c=>(String or Symbol),
|
|
227
|
+
:d=>(String or Symbol),
|
|
228
|
+
:e=>(String or Symbol),
|
|
229
|
+
:f=>(String or Symbol),
|
|
230
|
+
:g=>(String or Symbol)},
|
|
231
|
+
Actual: {:a=>["foo", "foo"],
|
|
232
|
+
:b=>["foo", "foo"],
|
|
233
|
+
:c=>["foo", "foo"],
|
|
234
|
+
:d=>["foo", "foo"],
|
|
235
|
+
:e=>["foo", "foo"],
|
|
236
|
+
:f=>["foo", "foo"],
|
|
237
|
+
:g=>["foo", "foo"]}
|
|
238
|
+
Value guarded in: Example::run
|
|
239
|
+
With Contract: None => Hash
|
|
240
|
+
At: example.rb:17
|
|
241
|
+
"""
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Feature: Simple examples and Contract violations
|
|
2
|
+
|
|
3
|
+
Contracts.ruby allows specification of contracts on per-method basis, where
|
|
4
|
+
method arguments and return value will be validated upon method call.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
Contract C::Num, C::Num => C::Num
|
|
10
|
+
def add(a, b)
|
|
11
|
+
a + b
|
|
12
|
+
end
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Here `Contract arg_contracts... => return_contract` defines list of argument
|
|
16
|
+
contracts `args_contracts...` as `C::Num, C::Num` (i.e.: both arguments
|
|
17
|
+
should be numbers) and return value contract `return_contract` as `C::Num`
|
|
18
|
+
(i.e.: return value should be a number too).
|
|
19
|
+
|
|
20
|
+
`Contract arg_contracts... => return_contract` affects next defined instance,
|
|
21
|
+
class or singleton method, meaning that all of these work:
|
|
22
|
+
|
|
23
|
+
- [Instance method](#instance-method),
|
|
24
|
+
|
|
25
|
+
- [Class method](#class-method),
|
|
26
|
+
|
|
27
|
+
- [Singleton method](#singleton-method).
|
|
28
|
+
|
|
29
|
+
Whenever invalid argument is passed to a contracted method, corresponding
|
|
30
|
+
`ContractError` will be raised. That happens right after bad value got into
|
|
31
|
+
system protected by contracts and prevents error propagation: first
|
|
32
|
+
non-contracts library frame in exception's backtrace is a culprit for passing
|
|
33
|
+
an invalid argument - you do not need to verify 20-30 frames to find a
|
|
34
|
+
culprit! Example of such error: [instance method contract
|
|
35
|
+
violation](#instance-method-contract-violation).
|
|
36
|
+
|
|
37
|
+
Whenever invalid return value is returned from a contracted method,
|
|
38
|
+
corresponding `ContractError` will be raised. That happens right after method
|
|
39
|
+
returned this value and prevents error propagation: `At: your_filename.rb:17`
|
|
40
|
+
part of error message points directly to a culprit method. Example of such
|
|
41
|
+
error: [return value contract
|
|
42
|
+
violation](#singleton-method-return-value-contract-violation).
|
|
43
|
+
|
|
44
|
+
Contract violation error consists of such parts:
|
|
45
|
+
- Violation type:
|
|
46
|
+
- `Contract violation for argument X of Y: (ParamContractError)`,
|
|
47
|
+
- `Contract violation for return value (ReturnContractError)`.
|
|
48
|
+
- Expected contract, example: `Expected: Num`.
|
|
49
|
+
- Actual value, example: `Actual: "foo"`.
|
|
50
|
+
- Location of violated contract, example: `Value guarded in: Example::add`.
|
|
51
|
+
- Full contract, example: `With Contract: Num, Num => Num`.
|
|
52
|
+
- Source code location of contracted method, example: `At: lib/your_library/some_class.rb:17`.
|
|
53
|
+
|
|
54
|
+
Scenario: Instance method
|
|
55
|
+
Given a file named "instance_method.rb" with:
|
|
56
|
+
"""ruby
|
|
57
|
+
require "contracts"
|
|
58
|
+
C = Contracts
|
|
59
|
+
|
|
60
|
+
class Example
|
|
61
|
+
include Contracts::Core
|
|
62
|
+
|
|
63
|
+
Contract C::Num, C::Num => C::Num
|
|
64
|
+
def add(a, b)
|
|
65
|
+
a + b
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
puts Example.new.add(2, 2)
|
|
70
|
+
"""
|
|
71
|
+
When I run `ruby instance_method.rb`
|
|
72
|
+
Then the output should contain:
|
|
73
|
+
"""
|
|
74
|
+
4
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
Scenario: Instance method contract violation
|
|
78
|
+
Given a file named "instance_method_violation.rb" with:
|
|
79
|
+
"""ruby
|
|
80
|
+
require "contracts"
|
|
81
|
+
C = Contracts
|
|
82
|
+
|
|
83
|
+
class Example
|
|
84
|
+
include Contracts::Core
|
|
85
|
+
|
|
86
|
+
Contract C::Num, C::Num => C::Num
|
|
87
|
+
def add(a, b)
|
|
88
|
+
a + b
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
puts Example.new.add(2, "foo")
|
|
93
|
+
"""
|
|
94
|
+
When I run `ruby instance_method_violation.rb`
|
|
95
|
+
Then the output should contain:
|
|
96
|
+
"""
|
|
97
|
+
: Contract violation for argument 2 of 2: (ParamContractError)
|
|
98
|
+
Expected: Num,
|
|
99
|
+
Actual: "foo"
|
|
100
|
+
Value guarded in: Example::add
|
|
101
|
+
With Contract: Num, Num => Num
|
|
102
|
+
At: instance_method_violation.rb:8
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
Scenario: Class method
|
|
106
|
+
Given a file named "class_method.rb" with:
|
|
107
|
+
"""ruby
|
|
108
|
+
require "contracts"
|
|
109
|
+
C = Contracts
|
|
110
|
+
|
|
111
|
+
class Example
|
|
112
|
+
include Contracts::Core
|
|
113
|
+
|
|
114
|
+
Contract C::Num, C::Num => C::Num
|
|
115
|
+
def self.add(a, b)
|
|
116
|
+
a + b
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
puts Example.add(2, 2)
|
|
121
|
+
"""
|
|
122
|
+
When I run `ruby class_method.rb`
|
|
123
|
+
Then the output should contain:
|
|
124
|
+
"""
|
|
125
|
+
4
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
Scenario: Class method contract violation
|
|
129
|
+
Given a file named "class_method_violation.rb" with:
|
|
130
|
+
"""ruby
|
|
131
|
+
require "contracts"
|
|
132
|
+
C = Contracts
|
|
133
|
+
|
|
134
|
+
class Example
|
|
135
|
+
include Contracts::Core
|
|
136
|
+
|
|
137
|
+
Contract C::Num, C::Num => C::Num
|
|
138
|
+
def self.add(a, b)
|
|
139
|
+
a + b
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
puts Example.add(:foo, 2)
|
|
144
|
+
"""
|
|
145
|
+
When I run `ruby class_method_violation.rb`
|
|
146
|
+
Then the output should contain:
|
|
147
|
+
"""
|
|
148
|
+
: Contract violation for argument 1 of 2: (ParamContractError)
|
|
149
|
+
Expected: Num,
|
|
150
|
+
Actual: :foo
|
|
151
|
+
Value guarded in: Example::add
|
|
152
|
+
With Contract: Num, Num => Num
|
|
153
|
+
At: class_method_violation.rb:8
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
Scenario: Singleton method
|
|
157
|
+
Given a file named "singleton_method.rb" with:
|
|
158
|
+
"""ruby
|
|
159
|
+
require "contracts"
|
|
160
|
+
C = Contracts
|
|
161
|
+
|
|
162
|
+
class Example
|
|
163
|
+
include Contracts::Core
|
|
164
|
+
|
|
165
|
+
class << self
|
|
166
|
+
Contract C::Num, C::Num => C::Num
|
|
167
|
+
def add(a, b)
|
|
168
|
+
a + b
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
puts Example.add(2, 2)
|
|
174
|
+
"""
|
|
175
|
+
When I run `ruby singleton_method.rb`
|
|
176
|
+
Then the output should contain:
|
|
177
|
+
"""
|
|
178
|
+
4
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
Scenario: Singleton method return value contract violation
|
|
182
|
+
Given a file named "singleton_method_violation.rb" with:
|
|
183
|
+
"""ruby
|
|
184
|
+
require "contracts"
|
|
185
|
+
C = Contracts
|
|
186
|
+
|
|
187
|
+
class Example
|
|
188
|
+
include Contracts::Core
|
|
189
|
+
|
|
190
|
+
class << self
|
|
191
|
+
Contract C::Num, C::Num => C::Num
|
|
192
|
+
def add(a, b)
|
|
193
|
+
# notice here non-number is returned
|
|
194
|
+
nil
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
puts Example.add(2, 2)
|
|
200
|
+
"""
|
|
201
|
+
When I run `ruby singleton_method_violation.rb`
|
|
202
|
+
Then the output should contain:
|
|
203
|
+
"""
|
|
204
|
+
: Contract violation for return value: (ReturnContractError)
|
|
205
|
+
Expected: Num,
|
|
206
|
+
Actual: nil
|
|
207
|
+
Value guarded in: Example::add
|
|
208
|
+
With Contract: Num, Num => Num
|
|
209
|
+
At: singleton_method_violation.rb:9
|
|
210
|
+
"""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
To use builtin contracts you can refer them with `Contracts::*`:
|
|
2
|
+
|
|
3
|
+
```ruby
|
|
4
|
+
Contract Contracts::Num => Contracts::Maybe(Contracts::Num)
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
It is recommended to use a short alias for `Contracts`, for example `C`:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
C = Contracts
|
|
11
|
+
|
|
12
|
+
Contract C::Num => C::Maybe(C::Num)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
It is possible to `include Contracts` and refer them without namespace, but
|
|
16
|
+
this is deprecated and not recommended.
|
|
17
|
+
|
|
18
|
+
*NOTE: in the future it will be possible to do `include Contracts::Builtin`
|
|
19
|
+
instead.*
|
|
20
|
+
|
|
21
|
+
*NOTE: all contracts marked as (TODO) have their documentaion `.feature` file
|
|
22
|
+
as stub. Contributions to those are warmly welcome!*
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Feature: And
|
|
2
|
+
|
|
3
|
+
Takes a variable number of contracts. The contract passes if all of the
|
|
4
|
+
contracts pass.
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
Contract C::And[Float, C::Neg] => String
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
This example will validate first argument of a method and accept only
|
|
11
|
+
negative `Float`.
|
|
12
|
+
|
|
13
|
+
Background:
|
|
14
|
+
Given a file named "and_usage.rb" with:
|
|
15
|
+
"""ruby
|
|
16
|
+
require "contracts"
|
|
17
|
+
C = Contracts
|
|
18
|
+
|
|
19
|
+
class Example
|
|
20
|
+
include Contracts::Core
|
|
21
|
+
|
|
22
|
+
Contract C::And[Float, C::Neg] => String
|
|
23
|
+
def fneg_string(number)
|
|
24
|
+
number.to_i.to_s
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
Scenario: Accepts negative float
|
|
30
|
+
Given a file named "accepts_negative_float.rb" with:
|
|
31
|
+
"""ruby
|
|
32
|
+
require "./and_usage"
|
|
33
|
+
puts Example.new.fneg_string(-3.7)
|
|
34
|
+
"""
|
|
35
|
+
When I run `ruby accepts_negative_float.rb`
|
|
36
|
+
Then output should contain:
|
|
37
|
+
"""
|
|
38
|
+
-3
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
Scenario: Rejects positive float
|
|
42
|
+
Given a file named "rejects_positive_float.rb" with:
|
|
43
|
+
"""ruby
|
|
44
|
+
require "./and_usage"
|
|
45
|
+
puts Example.new.fneg_string(7.5)
|
|
46
|
+
"""
|
|
47
|
+
When I run `ruby rejects_positive_float.rb`
|
|
48
|
+
Then output should contain:
|
|
49
|
+
"""
|
|
50
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
51
|
+
Expected: (Float and Neg),
|
|
52
|
+
Actual: 7.5
|
|
53
|
+
Value guarded in: Example::fneg_string
|
|
54
|
+
With Contract: And => String
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
Scenario: Rejects negative integer
|
|
58
|
+
Given a file named "rejects_negative_integer.rb" with:
|
|
59
|
+
"""ruby
|
|
60
|
+
require "./and_usage"
|
|
61
|
+
puts Example.new.fneg_string(-5)
|
|
62
|
+
"""
|
|
63
|
+
When I run `ruby rejects_negative_integer.rb`
|
|
64
|
+
Then output should contain:
|
|
65
|
+
"""
|
|
66
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
67
|
+
Expected: (Float and Neg),
|
|
68
|
+
Actual: -5
|
|
69
|
+
Value guarded in: Example::fneg_string
|
|
70
|
+
With Contract: And => String
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
Scenario: Rejects positive integer
|
|
74
|
+
Given a file named "rejects_positive_integer.rb" with:
|
|
75
|
+
"""ruby
|
|
76
|
+
require "./and_usage"
|
|
77
|
+
puts Example.new.fneg_string(5)
|
|
78
|
+
"""
|
|
79
|
+
When I run `ruby rejects_positive_integer.rb`
|
|
80
|
+
Then output should contain:
|
|
81
|
+
"""
|
|
82
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
83
|
+
Expected: (Float and Neg),
|
|
84
|
+
Actual: 5
|
|
85
|
+
Value guarded in: Example::fneg_string
|
|
86
|
+
With Contract: And => String
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
Scenario: Rejects others
|
|
90
|
+
Given a file named "rejects_others.rb" with:
|
|
91
|
+
"""ruby
|
|
92
|
+
require "./and_usage"
|
|
93
|
+
puts Example.new.fneg_string(:foo)
|
|
94
|
+
"""
|
|
95
|
+
When I run `ruby rejects_others.rb`
|
|
96
|
+
Then output should contain:
|
|
97
|
+
"""
|
|
98
|
+
: Contract violation for argument 1 of 1: (ParamContractError)
|
|
99
|
+
Expected: (Float and Neg),
|
|
100
|
+
Actual: :foo
|
|
101
|
+
Value guarded in: Example::fneg_string
|
|
102
|
+
With Contract: And => String
|
|
103
|
+
"""
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Feature: Any
|
|
2
|
+
|
|
3
|
+
Passes for any argument.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
Contract C::Any => String
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Scenario: Accepts any argument
|
|
10
|
+
Given a file named "any_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
|
|
19
|
+
def self.stringify(x)
|
|
20
|
+
x.inspect
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
puts Example.stringify(25)
|
|
25
|
+
puts Example.stringify(37.59)
|
|
26
|
+
puts Example.stringify("foo")
|
|
27
|
+
puts Example.stringify(:foo)
|
|
28
|
+
puts Example.stringify(nil)
|
|
29
|
+
puts Example.stringify(Object)
|
|
30
|
+
"""
|
|
31
|
+
When I run `ruby any_usage.rb`
|
|
32
|
+
Then output should contain:
|
|
33
|
+
"""
|
|
34
|
+
25
|
|
35
|
+
37.59
|
|
36
|
+
"foo"
|
|
37
|
+
:foo
|
|
38
|
+
nil
|
|
39
|
+
Object
|
|
40
|
+
"""
|
|
41
|
+
And output should not contain:
|
|
42
|
+
"""
|
|
43
|
+
Contract violation for
|
|
44
|
+
"""
|
|
@@ -0,0 +1,80 @@
|
|
|
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 @@
|
|
|
1
|
+
Feature: ArrayOf (TODO)
|