contracts 0.16.0 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
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