contracts 0.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d2050dfd5418498598d0f857e3fe285daa65908c
4
- data.tar.gz: 9d5ae5ad04a508233be8ec25b2fb657f2a2b713e
2
+ SHA256:
3
+ metadata.gz: 0f008c5c8ab0f0e8d60c14f29413e2b6b262f53b53d9bdc34a618d438a3065a2
4
+ data.tar.gz: 812d80e1696cfe92350c4402d5a2368589d7ecca4b1849f6ca110a8afe239d18
5
5
  SHA512:
6
- metadata.gz: 714992e52ce0d9bdc52c1a0d0ee0c89b0541559e924d2e63e902f73d253c09343f37e8bec1c082ba5bdae76cf146835f09e252f273a617fd5235108b3d2b9f49
7
- data.tar.gz: 50518932f7576ddb8a092fa42267321b4502b87a45f96255d2673197075dbdaf9008b3096ce0753cfe57a39a0055c14326dfddeae81ef4ce4243157e55dadd08
6
+ metadata.gz: 37e8c58c78748244de26e797301d7510a16263a1373a45b69b01749f34d8a0990c60b9ec02adf49b745abf1493911e61596b90d37af60663abd84e8f5c5273d5
7
+ data.tar.gz: 502421a171fc8284295c9253edb405321c05ef871d0aafb52b80e9b7cf5099f216b7f71ca3dce696e582854feedaad80faa00394a0fb903760fa732c34cd87a0
@@ -0,0 +1,36 @@
1
+ name: Code Style Checks
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - master
7
+ paths-ignore:
8
+ - 'README.md'
9
+ push:
10
+ branches:
11
+ - master
12
+ paths-ignore:
13
+ - 'README.md'
14
+
15
+ jobs:
16
+ rubocop:
17
+ name: Rubocop
18
+ if: "contains(github.event.commits[0].message, '[ci skip]') == false"
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ os:
23
+ - ubuntu
24
+ ruby:
25
+ - "2.7"
26
+ runs-on: ${{ matrix.os }}-latest
27
+ steps:
28
+ - name: Checkout
29
+ uses: actions/checkout@v2
30
+ - name: Setup Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby }}
34
+ bundler-cache: true
35
+ - name: Run Rubocop
36
+ run: bundle exec rubocop
@@ -0,0 +1,47 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - master
7
+ paths-ignore:
8
+ - 'README.md'
9
+ push:
10
+ branches:
11
+ - master
12
+ paths-ignore:
13
+ - 'README.md'
14
+
15
+ jobs:
16
+ unit_tests:
17
+ name: Unit Tests
18
+ if: "contains(github.event.commits[0].message, '[ci skip]') == false"
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ os:
23
+ - ubuntu
24
+ ruby:
25
+ - "2.1"
26
+ - "2.2"
27
+ - "2.3"
28
+ - "2.4"
29
+ - "2.5"
30
+ - "2.6"
31
+ - "2.7"
32
+ test_command: ["bundle exec rspec && bundle exec cucumber"]
33
+ include:
34
+ - os: ubuntu
35
+ ruby: "2.4.2"
36
+ test_command: "bundle exec rspec"
37
+ runs-on: ${{ matrix.os }}-latest
38
+ steps:
39
+ - name: Checkout
40
+ uses: actions/checkout@v2
41
+ - name: Setup Ruby
42
+ uses: ruby/setup-ruby@v1
43
+ with:
44
+ ruby-version: ${{ matrix.ruby }}
45
+ bundler-cache: true
46
+ - name: Test
47
+ run: ${{ matrix.test_command }}
data/CHANGELOG.markdown CHANGED
@@ -1,14 +1,29 @@
1
- ## v0.16.0
1
+
2
+ ## [v0.16.1] - 2021-04-17
3
+
4
+ - Enhancement: Pretty-print contracts in error messages - [Corey Farwell](https://github.com/frewsxcv) [#289](https://github.com/egonSchiele/contracts.ruby/pull/289)
5
+ - Bugfix: Fix `attr_accessor_with_contract` with multiple attribute names input - [Kevin Yeh](https://github.com/kyeah) [#259](https://github.com/egonSchiele/contracts.ruby/pull/259)
6
+ - Bugfix: Fix "stack level too deep" in CI builds - [md-work](https://github.com/md-work) [#283](https://github.com/egonSchiele/contracts.ruby/pull/283)
7
+
8
+ ## [v0.16.0] - 2017-04-24
9
+
10
+ [v0.16.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.15.0...v0.16.0
2
11
 
3
12
  - **Support for Ruby 1.8 has been discontinued** - [Corey Farwell](https://github.com/frewsxcv) [#256](https://github.com/egonSchiele/contracts.ruby/pull/256)
4
13
  - Enhancement: Add a `Contracts::Attrs` module containing attribute w/ contracts utilities - [Corey Farwell](https://github.com/frewsxcv) [#255](https://github.com/egonSchiele/contracts.ruby/pull/255)
5
14
  - Bugfix: Fix StrictHash contract for extra keys - [Maciej Malecki](https://github.com/smt116) [#254](https://github.com/egonSchiele/contracts.ruby/pull/254)
6
15
 
7
- ## v0.15.0
16
+ ## [v0.15.0] - 2017-02-24
17
+
18
+ [v0.15.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.14.0...v0.15.0
19
+
8
20
  - Bugfix: Func contract's return value isn't enforced with blocks - [Piotr Szmielew](https://github.com/esse) [#251](https://github.com/egonSchiele/contracts.ruby/pull/251)
9
21
  - Bugfx: Fix contracts used in AR-models - [Gert Goet](https://github.com/eval) [#237](https://github.com/egonSchiele/contracts.ruby/pull/237)
10
22
 
11
- ## v0.14.0
23
+ ## [v0.14.0] - 2016-04-26
24
+
25
+ [v0.14.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.13.0...v0.14.0
26
+
12
27
  - Enhancement: Add StrictHash contract - [Fyodor](https://github.com/cbrwizard) [#236](https://github.com/egonSchiele/contracts.ruby/pull/236)
13
28
  - Bugfix: dont fail if something other than a hash is passed to a KeywordArgs - [Dan Padilha](https://github.com/dpad) [#234](https://github.com/egonSchiele/contracts.ruby/pull/234)
14
29
  - LICENSE ADDED: Simplified BSD (same as what is specified in the readme) - [Charles Dale](https://github.com/chuckd) [#233](https://github.com/egonSchiele/contracts.ruby/pull/233)
@@ -16,20 +31,26 @@
16
31
  - Bugfix for err case when KeywordArgs and Proc are used together - [Aditya Bhargava](https://github.com/egonSchiele) [#230](https://github.com/egonSchiele/contracts.ruby/pull/230)
17
32
  - Enhancement: Add DescendantOf contract - [Miguel Palhas](https://github.com/naps62) [#227](https://github.com/egonSchiele/contracts.ruby/pull/227)
18
33
 
19
- ## v0.13.0
34
+ ## [v0.13.0] - 2016-01-25
35
+
36
+ [v0.13.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.12.0...v0.13.0
20
37
 
21
38
  - Enhancement: Add support for Ruby 2.3 - [Oleksii Fedorov](https://github.com/waterlink) [#216](https://github.com/egonSchiele/contracts.ruby/pull/216)
22
39
  - Enhancement: Added Int, Nat and NatPos builtin contracts - [Simon George](https://github.com/sfcgeorge) [#212](https://github.com/egonSchiele/contracts.ruby/pull/212)
23
40
  - Bugfix: Allow contracts on singleton of subclass - [Oleksii Federov](https://github.com/waterlink) [#211](https://github.com/egonSchiele/contracts.ruby/pull/211)
24
41
 
25
- ## v0.12.0
42
+ ## [v0.12.0] - 2015-09-15
43
+
44
+ [v0.12.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.11.0...v0.12.0
26
45
 
27
46
  - Feature: add `Regexp` validator - [Gert Goet](https://github.com/eval) [#196](https://github.com/egonSchiele/contracts.ruby/pull/196)
28
47
  - Docs: bootstrap cucumber/aruba/relish setup - [Oleksii Fedorov](https://github.com/waterlink) [#195](https://github.com/egonSchiele/contracts.ruby/pull/195)
29
48
  - Bugfix: allow to `extend` module, that has `Contracts` or `Contracts::Core` included without harming current module/class `Contracts` functionality, see: [#176](https://github.com/egonSchiele/contracts.ruby/issues/176) - [Oleksii Fedorov](https://github.com/waterlink) [#198](https://github.com/egonSchiele/contracts.ruby/pull/198)
30
49
  - Enhancement: add `include Contracts::Builtin` to allow users to use builtin contracts without `Contracts::` prefix together with `include Contracts::Core` - [PikachuEXE](https://github.com/PikachuEXE) [#199](https://github.com/egonSchiele/contracts.ruby/pull/199)
31
50
 
32
- ## v0.11.0
51
+ ## [v0.11.0] - 2015-07-30
52
+
53
+ [v0.11.0]: https://github.com/egonSchiele/contracts.ruby/compare/v0.10.1...v0.11.0
33
54
 
34
55
  - Enhancement: add `include Contracts::Core` that doesn't pollute the namespace as much as `include Contracts` - [Oleksii Federov](https://github.com/waterlink) [#185](https://github.com/egonSchiele/contracts.ruby/pull/185)
35
56
  - Bugfix: fail if a non-hash is provided to a `HashOf` contract - [Abe Voelker](https://github.com/abevoelker) [#190](https://github.com/egonSchiele/contracts.ruby/pull/190)
@@ -38,11 +59,15 @@
38
59
  - Feature: range contract added - [Oleksii Fedorov](https://github.com/waterlink) [#184](https://github.com/egonSchiele/contracts.ruby/pull/184)
39
60
  - Feature: enum contract added - [Dennis Günnewig](https://github.com/dg-ratiodata) [#181](https://github.com/egonSchiele/contracts.ruby/pull/181)
40
61
 
41
- ## v0.10.1
62
+ ## [v0.10.1] - 2015-07-16
63
+
64
+ [v0.10.1]: https://github.com/egonSchiele/contracts.ruby/compare/v0.10...v0.10.1
42
65
 
43
66
  - Enhancement: make `@pattern_match` instance variable not render ruby warning. Required to use new aruba versions in rspec tests - [Dennis Günnewig](https://github.com/dg-ratiodata) [#179](https://github.com/egonSchiele/contracts.ruby/pull/179)
44
67
 
45
- ## v0.10
68
+ ## [v0.10] - 2015-07-07
69
+
70
+ [v0.10]: https://github.com/egonSchiele/contracts.ruby/compare/v0.9...v0.10
46
71
 
47
72
  - Bugfix: make `Maybe[Proc]` work correctly - [Simon George](https://github.com/sfcgeorge) [#142](https://github.com/egonSchiele/contracts.ruby/pull/142)
48
73
  - Bugfix: make `Func` contract verified when used as return contract - [Rob Rosenbaum](https://github.com/robnormal) [#145](https://github.com/egonSchiele/contracts.ruby/pull/145)
@@ -53,7 +78,9 @@
53
78
  - Feature: custom validators with `Contract.override_validator` - [Oleksii Fedorov](https://github.com/waterlink) [#159](https://github.com/egonSchiele/contracts.ruby/pull/159)
54
79
  - Feature: add builtin `RangeOf[...]` contract - [Gavin Sinclair](https://github.com/gsinclair) [#171](https://github.com/egonSchiele/contracts.ruby/pull/171)
55
80
 
56
- ## v0.9
81
+ ## [v0.9] - 2015-04-24
82
+
83
+ [v0.9]: https://github.com/egonSchiele/contracts.ruby/compare/0.8...v0.9
57
84
 
58
85
  - MAJOR fix in pattern-matching: If the return contract for a pattern-matched function fails, it should NOT try the next pattern-match function. Pattern-matching is only for params, not return values.
59
86
  - raise an error if multiple defns have the same contract for pattern matching.
@@ -74,7 +101,7 @@
74
101
  - Add `SetOf` contract
75
102
  - various small fixes
76
103
 
77
- ## v0.8
104
+ ## v0.8 - 2015-04-03
78
105
 
79
106
  - code refactored (very slight loss of performance, big increase in readability)
80
107
  - fail when defining a contract on a module without `include Contracts::Modules`
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
@@ -6,7 +6,7 @@ group :test do
6
6
  gem "rspec"
7
7
  gem "aruba"
8
8
  gem "cucumber", "~> 1.3.20"
9
- gem "rubocop", "~> 0.29.1" if RUBY_VERSION >= "2"
9
+ gem "rubocop", "~> 0.41.2" if RUBY_VERSION >= "2"
10
10
  end
11
11
 
12
12
  group :development do
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # contracts.ruby [![Build Status](https://travis-ci.org/egonSchiele/contracts.ruby.png?branch=master)](https://travis-ci.org/egonSchiele/contracts.ruby) [![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)
1
+ This project is looking for a new maintainer! [More details here](https://github.com/egonSchiele/contracts.ruby/issues/249)
2
+
3
+ # contracts.ruby [![GitHub Build Status](https://img.shields.io/github/workflow/status/egonSchiele/contracts.ruby/Tests?style=flat-square)](https://github.com/egonSchiele/contracts.ruby/actions?query=workflow%3ATests) [![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)
2
4
 
3
5
  Contracts let you clearly – even beautifully – express how your code behaves, and free you from writing tons of boilerplate, defensive code.
4
6
 
@@ -53,7 +55,7 @@ Instead of throwing an exception, you could log it, print a clean error message
53
55
 
54
56
  ## Tutorial
55
57
 
56
- Check out [this awesome tutorial](http://egonschiele.github.com/contracts.ruby).
58
+ Check out [this awesome tutorial](https://egonschiele.github.io/contracts.ruby/).
57
59
 
58
60
  ## Use Cases
59
61
 
@@ -81,7 +83,7 @@ Using contracts.ruby results in very little slowdown. Check out [this blog post]
81
83
 
82
84
  **Q.** What Rubies can I use this with?
83
85
 
84
- **A.** It's been tested with `1.9.2`, `1.9.3`, `2.0.0`, `2.1`, `2.2`, and `jruby` (1.9 mode).
86
+ **A.** It's been tested with `2.1`, `2.2`, `2.3`, `2.4`, `2.5`, `2.6` and `2.7`.
85
87
 
86
88
  If you're using the library, please [let me know](https://github.com/egonSchiele) what project you're using it on :)
87
89
 
data/Rakefile CHANGED
@@ -1,11 +1,4 @@
1
- if RUBY_VERSION >= "2"
2
- task :default => [:spec, :rubocop]
3
-
4
- require "rubocop/rake_task"
5
- RuboCop::RakeTask.new
6
- else
7
- task :default => [:spec]
8
- end
1
+ task :default => [:spec]
9
2
 
10
3
  task :add_tag do
11
4
  `git tag -a v#{Contracts::VERSION} -m 'v#{Contracts::VERSION}'`
data/contracts.gemspec CHANGED
@@ -8,6 +8,10 @@ Gem::Specification.new do |s|
8
8
  s.author = "Aditya Bhargava"
9
9
  s.email = "bluemangroupie@gmail.com"
10
10
  s.files = `git ls-files`.split("\n")
11
- s.homepage = "http://github.com/egonSchiele/contracts.ruby"
11
+ s.homepage = "https://github.com/egonSchiele/contracts.ruby"
12
12
  s.license = "BSD-2-Clause"
13
+ s.post_install_message = "
14
+ 0.16.x will be the supporting Ruby 2.x and be feature frozen (only fixes will be released)
15
+ For Ruby 3.x use 0.17.x or later (might not be released yet)
16
+ "
13
17
  end
data/dependabot.yml ADDED
@@ -0,0 +1,20 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: monthly
7
+ time: "06:00"
8
+ timezone: Asia/Hong_Kong
9
+ open-pull-requests-limit: 10
10
+ labels:
11
+ - "dependencies"
12
+ - package-ecosystem: github-actions
13
+ directory: "/"
14
+ schedule:
15
+ interval: monthly
16
+ time: "06:00"
17
+ timezone: Asia/Hong_Kong
18
+ open-pull-requests-limit: 10
19
+ labels:
20
+ - "dependencies"
@@ -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
+ """
data/lib/contracts.rb CHANGED
@@ -116,22 +116,57 @@ class Contract < Contracts::Decorator
116
116
  # This function is used by the default #failure_callback method
117
117
  # and uses the hash passed into the failure_callback method.
118
118
  def self.failure_msg(data)
119
- expected = Contracts::Formatters::Expected.new(data[:contract]).contract
120
- position = Contracts::Support.method_position(data[:method])
119
+ indent_amount = 8
121
120
  method_name = Contracts::Support.method_name(data[:method])
122
121
 
122
+ # Header
123
123
  header = if data[:return_value]
124
124
  "Contract violation for return value:"
125
125
  else
126
126
  "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:"
127
127
  end
128
128
 
129
- %{#{header}
130
- Expected: #{expected},
131
- Actual: #{data[:arg].inspect}
132
- Value guarded in: #{data[:class]}::#{method_name}
133
- With Contract: #{data[:contracts]}
134
- At: #{position} }
129
+ # Expected
130
+ expected_prefix = "Expected: "
131
+ expected_value = Contracts::Support.indent_string(
132
+ Contracts::Formatters::Expected.new(data[:contract]).contract.pretty_inspect,
133
+ expected_prefix.length
134
+ ).strip
135
+ expected_line = expected_prefix + expected_value + ","
136
+
137
+ # Actual
138
+ actual_prefix = "Actual: "
139
+ actual_value = Contracts::Support.indent_string(
140
+ data[:arg].pretty_inspect,
141
+ actual_prefix.length
142
+ ).strip
143
+ actual_line = actual_prefix + actual_value
144
+
145
+ # Value guarded in
146
+ value_prefix = "Value guarded in: "
147
+ value_value = "#{data[:class]}::#{method_name}"
148
+ value_line = value_prefix + value_value
149
+
150
+ # Contract
151
+ contract_prefix = "With Contract: "
152
+ contract_value = data[:contracts].to_s
153
+ contract_line = contract_prefix + contract_value
154
+
155
+ # Position
156
+ position_prefix = "At: "
157
+ position_value = Contracts::Support.method_position(data[:method])
158
+ position_line = position_prefix + position_value
159
+
160
+ header +
161
+ "\n" +
162
+ Contracts::Support.indent_string(
163
+ [expected_line,
164
+ actual_line,
165
+ value_line,
166
+ contract_line,
167
+ position_line].join("\n"),
168
+ indent_amount
169
+ )
135
170
  end
136
171
 
137
172
  # Callback for when a contract fails. By default it raises
@@ -1,13 +1,17 @@
1
1
  module Contracts
2
2
  module Attrs
3
3
  def attr_reader_with_contract(*names, contract)
4
- Contract Contracts::None => contract
5
- attr_reader(*names)
4
+ names.each do |name|
5
+ Contract Contracts::None => contract
6
+ attr_reader(name)
7
+ end
6
8
  end
7
9
 
8
10
  def attr_writer_with_contract(*names, contract)
9
- Contract contract => contract
10
- attr_writer(*names)
11
+ names.each do |name|
12
+ Contract contract => contract
13
+ attr_writer(name)
14
+ end
11
15
  end
12
16
 
13
17
  def attr_accessor_with_contract(*names, contract)
@@ -1,6 +1,10 @@
1
1
  module Contracts
2
2
  module CallWith
3
3
  def call_with(this, *args, &blk)
4
+ call_with_inner(false, this, *args, &blk)
5
+ end
6
+
7
+ def call_with_inner(returns, this, *args, &blk)
4
8
  args << blk if blk
5
9
 
6
10
  # Explicitly append blk=nil if nil != Proc contract violation anticipated
@@ -16,14 +20,16 @@ module Contracts
16
20
  validator = @args_validators[i]
17
21
 
18
22
  unless validator && validator[arg]
19
- return unless Contract.failure_callback(:arg => arg,
20
- :contract => contract,
21
- :class => klass,
22
- :method => method,
23
- :contracts => self,
24
- :arg_pos => i+1,
25
- :total_args => args.size,
26
- :return_value => false)
23
+ data = {:arg => arg,
24
+ :contract => contract,
25
+ :class => klass,
26
+ :method => method,
27
+ :contracts => self,
28
+ :arg_pos => i+1,
29
+ :total_args => args.size,
30
+ :return_value => false}
31
+ return ParamContractError.new("as return value", data) if returns
32
+ return unless Contract.failure_callback(data)
27
33
  end
28
34
 
29
35
  if contract.is_a?(Contracts::Func) && blk && !nil_block_appended
@@ -74,9 +80,11 @@ module Contracts
74
80
  # proc, block, lambda, etc
75
81
  method.call(*args, &blk)
76
82
  else
77
- # original method name referrence
78
- added_block = blk ? lambda { |*params| blk.call(*params) } : nil
79
- method.send_to(this, *args, &added_block)
83
+ # original method name reference
84
+ # Don't reassign blk, else Travis CI shows "stack level too deep".
85
+ target_blk = blk
86
+ target_blk = lambda { |*params| blk.call(*params) } if blk && blk.is_a?(Contract)
87
+ method.send_to(this, *args, &target_blk)
80
88
  end
81
89
 
82
90
  unless @ret_validator[result]
@@ -1,3 +1,5 @@
1
+ require "pp"
2
+
1
3
  module Contracts
2
4
  # A namespace for classes related to formatting.
3
5
  module Formatters
@@ -25,13 +27,13 @@ module Contracts
25
27
  @full = true # Complex values output completely, overriding @full
26
28
  hash.inject({}) do |repr, (k, v)|
27
29
  repr.merge(k => InspectWrapper.create(contract(v), @full))
28
- end.inspect
30
+ end
29
31
  end
30
32
 
31
33
  # Formats Array contracts.
32
34
  def array_contract(array)
33
35
  @full = true
34
- array.map { |v| InspectWrapper.create(contract(v), @full) }.inspect
36
+ array.map { |v| InspectWrapper.create(contract(v), @full) }
35
37
  end
36
38
  end
37
39
 
@@ -125,31 +125,23 @@ module Contracts
125
125
  # function. Otherwise we return the result.
126
126
  # If we run out of functions, we raise the last error, but
127
127
  # convert it to_contract_error.
128
- success = false
129
- i = 0
130
- result = nil
128
+
131
129
  expected_error = decorated_methods[0].failure_exception
130
+ last_error = nil
132
131
 
133
- until success
134
- decorated_method = decorated_methods[i]
135
- i += 1
136
- begin
137
- success = true
138
- result = decorated_method.call_with(self, *args, &blk)
139
- rescue expected_error => error
140
- success = false
141
- unless decorated_methods[i]
142
- begin
143
- ::Contract.failure_callback(error.data, false)
144
- rescue expected_error => final_error
145
- raise final_error.to_contract_error
146
- end
147
- end
148
- end
132
+ decorated_methods.each do |decorated_method|
133
+ result = decorated_method.call_with_inner(true, self, *args, &blk)
134
+ return result unless result.is_a?(ParamContractError)
135
+ last_error = result
149
136
  end
150
137
 
151
- # Return the result of successfully called method
152
- result
138
+ begin
139
+ if ::Contract.failure_callback(last_error.data, false)
140
+ decorated_methods.last.call_with_inner(false, self, *args, &blk)
141
+ end
142
+ rescue expected_error => final_error
143
+ raise final_error.to_contract_error
144
+ end
153
145
  end
154
146
  end
155
147
 
@@ -157,7 +149,7 @@ module Contracts
157
149
  return if decorators.size == 1
158
150
 
159
151
  fail %{
160
- Oops, it looks like method '#{name}' has multiple contracts:
152
+ Oops, it looks like method '#{method_name}' has multiple contracts:
161
153
  #{decorators.map { |x| x[1][0].inspect }.join("\n")}
162
154
 
163
155
  Did you accidentally put more than one contract on a single function, like so?
@@ -42,6 +42,13 @@ module Contracts
42
42
  target <= eigenclass_of(Object)
43
43
  end
44
44
 
45
+ def indent_string(string, amount)
46
+ string.gsub(
47
+ /^(?!$)/,
48
+ (string[/^[ \t]/] || " ") * amount
49
+ )
50
+ end
51
+
45
52
  private
46
53
 
47
54
  # Module eigenclass can be detected by its ancestor chain
@@ -1,3 +1,3 @@
1
1
  module Contracts
2
- VERSION = "0.16.0"
2
+ VERSION = "0.16.1"
3
3
  end
data/spec/attrs_spec.rb CHANGED
@@ -9,11 +9,15 @@ RSpec.describe "Contracts:" do
9
9
  @name_r = name
10
10
  @name_w = name
11
11
  @name_rw = name
12
+
13
+ @name_r_2 = name
14
+ @name_w_2 = name
15
+ @name_rw_2 = name
12
16
  end
13
17
 
14
- attr_reader_with_contract :name_r, String
15
- attr_writer_with_contract :name_w, String
16
- attr_accessor_with_contract :name_rw, String
18
+ attr_reader_with_contract :name_r, :name_r_2, String
19
+ attr_writer_with_contract :name_w, :name_w_2, String
20
+ attr_accessor_with_contract :name_rw, :name_rw_2, String
17
21
  end
18
22
 
19
23
  context "attr_reader_with_contract" do
@@ -27,6 +31,16 @@ RSpec.describe "Contracts:" do
27
31
  .to(raise_error(ReturnContractError))
28
32
  end
29
33
 
34
+ it "getting valid type for second val" do
35
+ expect(Person.new("bob").name_r_2)
36
+ .to(eq("bob"))
37
+ end
38
+
39
+ it "getting invalid type for second val" do
40
+ expect { Person.new(1.3).name_r_2 }
41
+ .to(raise_error(ReturnContractError))
42
+ end
43
+
30
44
  it "setting" do
31
45
  expect { Person.new("bob").name_r = "alice" }
32
46
  .to(raise_error(NoMethodError))
@@ -48,6 +62,16 @@ RSpec.describe "Contracts:" do
48
62
  expect { Person.new("bob").name_w = 1.2 }
49
63
  .to(raise_error(ParamContractError))
50
64
  end
65
+
66
+ it "setting valid type for second val" do
67
+ expect(Person.new("bob").name_w_2 = "alice")
68
+ .to(eq("alice"))
69
+ end
70
+
71
+ it "setting invalid type for second val" do
72
+ expect { Person.new("bob").name_w_2 = 1.2 }
73
+ .to(raise_error(ParamContractError))
74
+ end
51
75
  end
52
76
 
53
77
  context "attr_accessor_with_contract" do
@@ -70,6 +94,26 @@ RSpec.describe "Contracts:" do
70
94
  expect { Person.new("bob").name_rw = 1.2 }
71
95
  .to(raise_error(ParamContractError))
72
96
  end
97
+
98
+ it "getting valid type for second val" do
99
+ expect(Person.new("bob").name_rw_2)
100
+ .to(eq("bob"))
101
+ end
102
+
103
+ it "getting invalid type for second val" do
104
+ expect { Person.new(1.2).name_rw_2 }
105
+ .to(raise_error(ReturnContractError))
106
+ end
107
+
108
+ it "setting valid type for second val" do
109
+ expect(Person.new("bob").name_rw_2 = "alice")
110
+ .to(eq("alice"))
111
+ end
112
+
113
+ it "setting invalid type for second val" do
114
+ expect { Person.new("bob").name_rw_2 = 1.2 }
115
+ .to(raise_error(ParamContractError))
116
+ end
73
117
  end
74
118
  end
75
119
  end
@@ -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
 
@@ -637,6 +637,28 @@ RSpec.describe "Contracts:" do
637
637
  end.to raise_error(ContractError, not_s(delim "String or Symbol"))
638
638
  end
639
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
+
640
662
  it "should not contain Contracts:: module prefix" do
641
663
  expect do
642
664
  @o.double("bad")
@@ -696,7 +718,7 @@ RSpec.describe "Contracts:" do
696
718
  it "should apply the contract to an inherited method" do
697
719
  c = Child.new
698
720
  expect { c.double(2) }.to_not raise_error
699
- expect { c.double("asd") }.to raise_error
721
+ expect { c.double("asd") }.to raise_error ParamContractError
700
722
  end
701
723
  end
702
724
 
@@ -152,6 +152,30 @@ class GenericExample
152
152
  def nested_array_complex_contracts(data)
153
153
  end
154
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
+
155
179
  Contract Proc => C::Any
156
180
  def do_call(&block)
157
181
  block.call
data/spec/methods_spec.rb CHANGED
@@ -36,19 +36,19 @@ RSpec.describe "Contracts:" do
36
36
  end
37
37
 
38
38
  it "should enforce return value inside block with no other parameter" do
39
- expect { obj.foo(&:to_s) }.to raise_error
39
+ expect { obj.foo(&:to_s) }.to raise_error ReturnContractError
40
40
  end
41
41
 
42
42
  it "should enforce return value inside block with other parameter" do
43
- expect { obj.foo2(2) { |x| x.to_s } }.to raise_error
43
+ expect { obj.foo2(2) { |x| x.to_s } }.to raise_error ReturnContractError
44
44
  end
45
45
 
46
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
47
+ expect { obj.bar lambda { |x| x.to_s } }.to raise_error ReturnContractError
48
48
  end
49
49
 
50
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
51
+ expect { obj.bar2(2, lambda { |x| x.to_s }) }.to raise_error ReturnContractError
52
52
  end
53
53
  end
54
54
  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 shouldnt accept nil" do
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
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.16.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: 2017-04-24 00:00:00.000000000 Z
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,10 +18,12 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - ".github/workflows/code_style_checks.yaml"
22
+ - ".github/workflows/tests.yaml"
21
23
  - ".gitignore"
22
24
  - ".rspec"
23
25
  - ".rubocop.yml"
24
- - ".travis.yml"
26
+ - ".rubocop_todo.yml"
25
27
  - CHANGELOG.markdown
26
28
  - Gemfile
27
29
  - LICENSE
@@ -36,8 +38,10 @@ files:
36
38
  - benchmarks/wrap_test.rb
37
39
  - contracts.gemspec
38
40
  - cucumber.yml
41
+ - dependabot.yml
39
42
  - features/README.md
40
43
  - features/basics/functype.feature
44
+ - features/basics/pretty-print.feature
41
45
  - features/basics/simple_example.feature
42
46
  - features/builtin_contracts/README.md
43
47
  - features/builtin_contracts/and.feature
@@ -85,7 +89,6 @@ files:
85
89
  - lib/contracts/support.rb
86
90
  - lib/contracts/validators.rb
87
91
  - lib/contracts/version.rb
88
- - script/cucumber
89
92
  - script/docs-release
90
93
  - script/docs-staging
91
94
  - script/rubocop.rb
@@ -104,11 +107,13 @@ files:
104
107
  - spec/support.rb
105
108
  - spec/support_spec.rb
106
109
  - spec/validators_spec.rb
107
- homepage: http://github.com/egonSchiele/contracts.ruby
110
+ homepage: https://github.com/egonSchiele/contracts.ruby
108
111
  licenses:
109
112
  - BSD-2-Clause
110
113
  metadata: {}
111
- 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 "
112
117
  rdoc_options: []
113
118
  require_paths:
114
119
  - lib
@@ -123,8 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
128
  - !ruby/object:Gem::Version
124
129
  version: '0'
125
130
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.5.1
131
+ rubygems_version: 3.0.3
128
132
  signing_key:
129
133
  specification_version: 4
130
134
  summary: Contracts for Ruby.
data/script/cucumber DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- if ruby -e 'exit(1) unless RUBY_VERSION.to_f >= 2.0'; then
4
- bundle exec cucumber
5
- fi