matchi 2.4.0 → 3.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/README.md +96 -90
- data/lib/matchi.rb +4 -2
- data/lib/matchi/be.rb +49 -0
- data/lib/matchi/be_an_instance_of.rb +49 -0
- data/lib/matchi/be_within.rb +35 -0
- data/lib/matchi/be_within/of.rb +53 -0
- data/lib/matchi/change.rb +109 -0
- data/lib/matchi/change/by.rb +63 -0
- data/lib/matchi/change/by_at_least.rb +63 -0
- data/lib/matchi/change/by_at_most.rb +63 -0
- data/lib/matchi/change/from.rb +44 -0
- data/lib/matchi/change/from/to.rb +69 -0
- data/lib/matchi/change/to.rb +62 -0
- data/lib/matchi/eq.rb +49 -0
- data/lib/matchi/match.rb +49 -0
- data/lib/matchi/raise_exception.rb +53 -0
- data/lib/matchi/satisfy.rb +49 -0
- metadata +19 -23
- data/lib/matchi/helper.rb +0 -40
- data/lib/matchi/matcher.rb +0 -11
- data/lib/matchi/matcher/base.rb +0 -63
- data/lib/matchi/matcher/be_an_instance_of.rb +0 -51
- data/lib/matchi/matcher/be_false.rb +0 -24
- data/lib/matchi/matcher/be_nil.rb +0 -24
- data/lib/matchi/matcher/be_true.rb +0 -24
- data/lib/matchi/matcher/change.rb +0 -78
- data/lib/matchi/matcher/change/by.rb +0 -57
- data/lib/matchi/matcher/change/by_at_least.rb +0 -57
- data/lib/matchi/matcher/change/by_at_most.rb +0 -57
- data/lib/matchi/matcher/change/from.rb +0 -35
- data/lib/matchi/matcher/change/from/to.rb +0 -68
- data/lib/matchi/matcher/change/to.rb +0 -56
- data/lib/matchi/matcher/eql.rb +0 -35
- data/lib/matchi/matcher/equal.rb +0 -35
- data/lib/matchi/matcher/match.rb +0 -35
- data/lib/matchi/matcher/raise_exception.rb +0 -39
- data/lib/matchi/matcher/satisfy.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aabf9e773ac6210d1170b3a0f3aa19f38845ea0215bb07280d97c35ef66add16
|
4
|
+
data.tar.gz: 2900c9b936d50bfbe50ba31c6418dcb1402c1fbef5cfbb9f7a1ce289ff6450c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2cfb5b1c32a01b84c1e2eec84cfc3ad34df2a7a17c91ecb1e6012ef84d5b4ef5b11f24817de7dcea77e08006e72c578d0d88947470436f231efef8fed18f061
|
7
|
+
data.tar.gz: 235a73246185fec310960caf6b8c868cbc2daf7598f29c863def9b560ec66ba7a0f43ab303cd164b04c81b5ebbcbddae3224c5550002f9ab924f8202f58a289f
|
data/README.md
CHANGED
@@ -6,9 +6,15 @@
|
|
6
6
|
[](https://github.com/fixrb/matchi/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
7
|
[](https://github.com/fixrb/matchi/raw/main/LICENSE.md)
|
8
8
|
|
9
|
-
> Collection of expectation matchers for
|
9
|
+
> Collection of expectation matchers for Rubyists 🤹
|
10
10
|
|
11
|
-

|
12
|
+
|
13
|
+
## Project goals
|
14
|
+
|
15
|
+
* Adding matchers should be as simple as possible.
|
16
|
+
* Being framework agnostic and easy to integrate.
|
17
|
+
* Avoid false positives/negatives due to malicious actual values.
|
12
18
|
|
13
19
|
## Installation
|
14
20
|
|
@@ -44,115 +50,136 @@ require "matchi"
|
|
44
50
|
|
45
51
|
All examples here assume that this has been done.
|
46
52
|
|
53
|
+
### Anatomy of a matcher
|
54
|
+
|
55
|
+
A __Matchi__ matcher is an object that must respond to the `matches?` method with a block as argument, and return a boolean.
|
56
|
+
|
57
|
+
To facilitate the integration of the matchers in other tools, __Matchi__ matchers may expose expected values via the `expected` method.
|
58
|
+
|
47
59
|
### Built-in matchers
|
48
60
|
|
61
|
+
Here is the collection of useful generic matchers.
|
62
|
+
|
49
63
|
**Equivalence** matcher:
|
50
64
|
|
51
65
|
```ruby
|
52
|
-
|
53
|
-
|
66
|
+
matcher = Matchi::Eq.new("foo")
|
67
|
+
|
68
|
+
matcher.expected # => "foo"
|
69
|
+
matcher.matches? { "foo" } # => true
|
54
70
|
```
|
55
71
|
|
56
72
|
**Identity** matcher:
|
57
73
|
|
58
74
|
```ruby
|
59
|
-
|
60
|
-
equal.matches? { :foo } # => true
|
61
|
-
```
|
75
|
+
matcher = Matchi::Be.new(:foo)
|
62
76
|
|
63
|
-
|
64
|
-
|
65
|
-
```ruby
|
66
|
-
match = Matchi::Matcher::Match.new(/^foo$/)
|
67
|
-
match.matches? { "foo" } # => true
|
77
|
+
matcher.expected # => :foo
|
78
|
+
matcher.matches? { :foo } # => true
|
68
79
|
```
|
69
80
|
|
70
|
-
**
|
81
|
+
**Comparisons** matcher:
|
71
82
|
|
72
83
|
```ruby
|
73
|
-
|
74
|
-
raise_exception.matches? { Boom } # => true
|
75
|
-
```
|
76
|
-
|
77
|
-
**Truth** matcher:
|
84
|
+
matcher = Matchi::BeWithin.new(8).of(37)
|
78
85
|
|
79
|
-
|
80
|
-
|
81
|
-
be_true.matches? { true } # => true
|
86
|
+
matcher.expected # => 37
|
87
|
+
matcher.matches? { 42 } # => true
|
82
88
|
```
|
83
89
|
|
84
|
-
**
|
90
|
+
**Regular expressions** matcher:
|
85
91
|
|
86
92
|
```ruby
|
87
|
-
|
88
|
-
|
93
|
+
matcher = Matchi::Match.new(/^foo$/)
|
94
|
+
|
95
|
+
matcher.expected # => /^foo$/
|
96
|
+
matcher.matches? { "foo" } # => true
|
89
97
|
```
|
90
98
|
|
91
|
-
**
|
99
|
+
**Expecting errors** matcher:
|
92
100
|
|
93
101
|
```ruby
|
94
|
-
|
95
|
-
|
102
|
+
matcher = Matchi::RaiseException.new(:NameError)
|
103
|
+
|
104
|
+
matcher.expected # => "NameError"
|
105
|
+
matcher.matches? { Boom } # => true
|
96
106
|
```
|
97
107
|
|
98
108
|
**Type/class** matcher:
|
99
109
|
|
100
110
|
```ruby
|
101
|
-
|
102
|
-
|
111
|
+
matcher = Matchi::BeAnInstanceOf.new(:String)
|
112
|
+
|
113
|
+
matcher.expected # => "String"
|
114
|
+
matcher.matches? { "foo" } # => true
|
103
115
|
```
|
104
116
|
|
105
117
|
**Change** matcher:
|
106
118
|
|
107
119
|
```ruby
|
108
120
|
object = []
|
109
|
-
|
110
|
-
|
121
|
+
matcher = Matchi::Change.new(object, :length).by(1)
|
122
|
+
|
123
|
+
matcher.expected # => 1
|
124
|
+
matcher.matches? { object << 1 } # => true
|
111
125
|
|
112
126
|
object = []
|
113
|
-
|
114
|
-
|
127
|
+
matcher = Matchi::Change.new(object, :length).by_at_least(1)
|
128
|
+
|
129
|
+
matcher.expected # => 1
|
130
|
+
matcher.matches? { object << 1 } # => true
|
115
131
|
|
116
132
|
object = []
|
117
|
-
|
118
|
-
|
133
|
+
matcher = Matchi::Change.new(object, :length).by_at_most(1)
|
134
|
+
|
135
|
+
matcher.expected # => 1
|
136
|
+
matcher.matches? { object << 1 } # => true
|
119
137
|
|
120
138
|
object = "foo"
|
121
|
-
|
122
|
-
|
139
|
+
matcher = Matchi::Change.new(object, :to_s).from("foo").to("FOO")
|
140
|
+
|
141
|
+
matcher.expected # => "FOO"
|
142
|
+
matcher.matches? { object.upcase! } # => true
|
123
143
|
|
124
144
|
object = "foo"
|
125
|
-
|
126
|
-
|
145
|
+
matcher = Matchi::Change.new(object, :to_s).to("FOO")
|
146
|
+
|
147
|
+
matcher.expected # => "FOO"
|
148
|
+
matcher.matches? { object.upcase! } # => true
|
127
149
|
```
|
128
150
|
|
129
151
|
**Satisfy** matcher:
|
130
152
|
|
131
153
|
```ruby
|
132
|
-
|
133
|
-
|
154
|
+
matcher = Matchi::Satisfy.new { |value| value == 42 }
|
155
|
+
|
156
|
+
matcher.expected # => #<Proc:0x00007fbaafc65540>
|
157
|
+
matcher.matches? { 42 } # => true
|
134
158
|
```
|
135
159
|
|
136
160
|
### Custom matchers
|
137
161
|
|
138
|
-
Custom matchers can easily be
|
139
|
-
They can be any Ruby class that responds to `matches?` instance method with a block.
|
162
|
+
Custom matchers can easily be added to express more specific expectations.
|
140
163
|
|
141
164
|
A **Be the answer** matcher:
|
142
165
|
|
143
166
|
```ruby
|
144
167
|
module Matchi
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
168
|
+
class BeTheAnswer
|
169
|
+
def expected
|
170
|
+
42
|
171
|
+
end
|
172
|
+
|
173
|
+
def matches?
|
174
|
+
expected.equal?(yield)
|
150
175
|
end
|
151
176
|
end
|
152
177
|
end
|
153
178
|
|
154
|
-
|
155
|
-
|
179
|
+
matcher = Matchi::BeTheAnswer.new
|
180
|
+
|
181
|
+
matcher.expected # => 42
|
182
|
+
matcher.matches? { 42 } # => true
|
156
183
|
```
|
157
184
|
|
158
185
|
A **Be prime** matcher:
|
@@ -161,60 +188,39 @@ A **Be prime** matcher:
|
|
161
188
|
require "prime"
|
162
189
|
|
163
190
|
module Matchi
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
Prime.prime?(yield)
|
168
|
-
end
|
191
|
+
class BePrime
|
192
|
+
def matches?
|
193
|
+
Prime.prime?(yield)
|
169
194
|
end
|
170
195
|
end
|
171
196
|
end
|
172
197
|
|
173
|
-
|
174
|
-
|
198
|
+
matcher = Matchi::BePrime.new
|
199
|
+
|
200
|
+
matcher.matches? { 42 } # => false
|
175
201
|
```
|
176
202
|
|
177
203
|
A **Start with** matcher:
|
178
204
|
|
179
205
|
```ruby
|
180
206
|
module Matchi
|
181
|
-
|
182
|
-
|
183
|
-
def initialize(expected)
|
184
|
-
super()
|
185
|
-
@expected = expected
|
186
|
-
end
|
187
|
-
|
188
|
-
def matches?
|
189
|
-
Regexp.new(/\A#{expected}/).match?(yield)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
207
|
+
class StartWith
|
208
|
+
attr_reader :expected
|
194
209
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
### Helper methods
|
200
|
-
|
201
|
-
For convenience, it is possible to instantiate a matcher with a method rather than with its class.
|
202
|
-
To do so, the `Helper` module can be included like this:
|
203
|
-
|
204
|
-
```ruby
|
205
|
-
require "matchi/helper"
|
210
|
+
def initialize(expected)
|
211
|
+
@expected = expected
|
212
|
+
end
|
206
213
|
|
207
|
-
|
208
|
-
|
214
|
+
def matches?
|
215
|
+
Regexp.new(/\A#{expected}/).match?(yield)
|
216
|
+
end
|
217
|
+
end
|
209
218
|
end
|
210
|
-
```
|
211
219
|
|
212
|
-
|
220
|
+
matcher = Matchi::StartWith.new("foo")
|
213
221
|
|
214
|
-
|
215
|
-
matcher
|
216
|
-
matcher.equal(42).matches? { 44 } # => false
|
217
|
-
matcher.be_an_instance_of(:String).matches? { "안녕하세요" } # => true
|
222
|
+
matcher.expected # => "foo"
|
223
|
+
matcher.matches? { "foobar" } # => true
|
218
224
|
```
|
219
225
|
|
220
226
|
## Contact
|
@@ -228,7 +234,7 @@ __Matchi__ follows [Semantic Versioning 2.0](https://semver.org/).
|
|
228
234
|
|
229
235
|
## License
|
230
236
|
|
231
|
-
The [gem](https://rubygems.org/gems/matchi) is available as open source under the terms of the [MIT License](https://
|
237
|
+
The [gem](https://rubygems.org/gems/matchi) is available as open source under the terms of the [MIT License](https://github.com/fixrb/matchi/raw/main/LICENSE.md).
|
232
238
|
|
233
239
|
***
|
234
240
|
|
data/lib/matchi.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# A collection of damn simple expectation matchers.
|
4
4
|
#
|
5
5
|
# @api public
|
6
6
|
module Matchi
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
Dir[File.join(File.dirname(__FILE__), "matchi", "*.rb")].each do |fname|
|
10
|
+
require_relative fname
|
11
|
+
end
|
data/lib/matchi/be.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Matchi
|
4
|
+
# *Identity* matcher.
|
5
|
+
class Be
|
6
|
+
# @return [#equal?] The expected identical object.
|
7
|
+
attr_reader :expected
|
8
|
+
|
9
|
+
# Initialize the matcher with an object.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# require "matchi/be"
|
13
|
+
#
|
14
|
+
# Matchi::Be.new(:foo)
|
15
|
+
#
|
16
|
+
# @param expected [#equal?] The expected identical object.
|
17
|
+
def initialize(expected)
|
18
|
+
@expected = expected
|
19
|
+
end
|
20
|
+
|
21
|
+
# Boolean comparison between the actual value and the expected value.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# require "matchi/be"
|
25
|
+
#
|
26
|
+
# matcher = Matchi::Be.new(:foo)
|
27
|
+
#
|
28
|
+
# matcher.expected # => :foo
|
29
|
+
# matcher.matches? { :foo } # => true
|
30
|
+
#
|
31
|
+
# @yieldreturn [#object_id] The actual value to compare to the expected
|
32
|
+
# one.
|
33
|
+
#
|
34
|
+
# @return [Boolean] Comparison between actual and expected values.
|
35
|
+
def matches?
|
36
|
+
expected.equal?(yield)
|
37
|
+
end
|
38
|
+
|
39
|
+
# A string containing a human-readable representation of the matcher.
|
40
|
+
def inspect
|
41
|
+
"#{self.class}(#{expected.inspect})"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a string representing the matcher.
|
45
|
+
def to_s
|
46
|
+
"be #{expected.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Matchi
|
4
|
+
# *Type/class* matcher.
|
5
|
+
class BeAnInstanceOf
|
6
|
+
# @return [String] The expected class name.
|
7
|
+
attr_reader :expected
|
8
|
+
|
9
|
+
# Initialize the matcher with (the name of) a class or module.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# require "matchi/be_an_instance_of"
|
13
|
+
#
|
14
|
+
# Matchi::BeAnInstanceOf.new(String)
|
15
|
+
#
|
16
|
+
# @param expected [Class, #to_s] The expected class name.
|
17
|
+
def initialize(expected)
|
18
|
+
@expected = String(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Boolean comparison between the class of the actual value and the
|
22
|
+
# expected class.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# require "matchi/be_an_instance_of"
|
26
|
+
#
|
27
|
+
# matcher = Matchi::BeAnInstanceOf.new(String)
|
28
|
+
#
|
29
|
+
# matcher.expected # => "String"
|
30
|
+
# matcher.matches? { "foo" } # => true
|
31
|
+
#
|
32
|
+
# @yieldreturn [#class] the actual value to compare to the expected one.
|
33
|
+
#
|
34
|
+
# @return [Boolean] Comparison between actual and expected values.
|
35
|
+
def matches?
|
36
|
+
self.class.const_get(expected).equal?(yield.class)
|
37
|
+
end
|
38
|
+
|
39
|
+
# A string containing a human-readable representation of the matcher.
|
40
|
+
def inspect
|
41
|
+
"#{self.class}(#{expected})"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a string representing the matcher.
|
45
|
+
def to_s
|
46
|
+
"be an instance of #{expected}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative File.join("be_within", "of")
|
4
|
+
|
5
|
+
module Matchi
|
6
|
+
# Wraps the target of a be_within matcher.
|
7
|
+
class BeWithin
|
8
|
+
# Initialize a wrapper of the be_within matcher with a numeric value.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# require "matchi/be_within"
|
12
|
+
#
|
13
|
+
# Matchi::BeWithin.new(1)
|
14
|
+
#
|
15
|
+
# @param delta [Numeric] A numeric value.
|
16
|
+
def initialize(delta)
|
17
|
+
@delta = delta
|
18
|
+
end
|
19
|
+
|
20
|
+
# Specifies an expected numeric value.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# require "matchi/be_within"
|
24
|
+
#
|
25
|
+
# be_within_wrapper = Matchi::BeWithin.new(1)
|
26
|
+
# be_within_wrapper.of(41)
|
27
|
+
#
|
28
|
+
# @param expected [Numeric] The expected value.
|
29
|
+
#
|
30
|
+
# @return [#matches?] A *be_within of* matcher.
|
31
|
+
def of(expected)
|
32
|
+
Of.new(@delta, expected)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|