matchi 3.0.0 → 3.3.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 +61 -5
- data/lib/matchi/be.rb +9 -4
- data/lib/matchi/be_an_instance_of.rb +11 -6
- data/lib/matchi/be_within.rb +35 -0
- data/lib/matchi/be_within/of.rb +53 -0
- data/lib/matchi/change.rb +25 -25
- data/lib/matchi/change/by.rb +9 -4
- data/lib/matchi/change/by_at_least.rb +9 -4
- data/lib/matchi/change/by_at_most.rb +9 -4
- data/lib/matchi/change/from.rb +2 -2
- data/lib/matchi/change/from/to.rb +9 -4
- data/lib/matchi/change/to.rb +10 -5
- data/lib/matchi/eq.rb +9 -4
- data/lib/matchi/match.rb +9 -4
- data/lib/matchi/predicate.rb +94 -0
- data/lib/matchi/raise_exception.rb +11 -6
- data/lib/matchi/satisfy.rb +7 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5596c7ba2d1153eadaa1ba438b009c0cc17954a360b4192bb6419c674d864822
|
4
|
+
data.tar.gz: 0c717e7642961b8707433584c58a1e2369f810c11114caa7530c890563df78a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e89b77b4f7fd25fc53ea570b865b3479be5a3291bc437f55b3ea126111fdd120afd907439ec87c565bbb28b4fe6e7be34a932a218e55933bb3d4bb890b0edcf
|
7
|
+
data.tar.gz: f19a1f799d1b8f9c1f40dc747c00863ae1cd9bf1ed545aabdea774e4c658a242a74d2bd6f03709fe124786f327fd7401b104aa9e567496265b966937c61841e3
|
data/README.md
CHANGED
@@ -12,9 +12,9 @@
|
|
12
12
|
|
13
13
|
## Project goals
|
14
14
|
|
15
|
-
* Provide a collection of useful generic matchers.
|
16
15
|
* Adding matchers should be as simple as possible.
|
17
16
|
* Being framework agnostic and easy to integrate.
|
17
|
+
* Avoid false positives/negatives due to malicious actual values.
|
18
18
|
|
19
19
|
## Installation
|
20
20
|
|
@@ -52,16 +52,20 @@ All examples here assume that this has been done.
|
|
52
52
|
|
53
53
|
### Anatomy of a matcher
|
54
54
|
|
55
|
-
A __Matchi__ matcher is
|
55
|
+
A __Matchi__ matcher is an object that must respond to the `matches?` method with a block as argument, and return a boolean.
|
56
56
|
|
57
|
-
|
57
|
+
To facilitate the integration of the matchers in other tools, __Matchi__ matchers may expose expected values via the `expected` method.
|
58
58
|
|
59
59
|
### Built-in matchers
|
60
60
|
|
61
|
+
Here is the collection of useful generic matchers.
|
62
|
+
|
61
63
|
**Equivalence** matcher:
|
62
64
|
|
63
65
|
```ruby
|
64
66
|
matcher = Matchi::Eq.new("foo")
|
67
|
+
|
68
|
+
matcher.expected # => "foo"
|
65
69
|
matcher.matches? { "foo" } # => true
|
66
70
|
```
|
67
71
|
|
@@ -69,20 +73,35 @@ matcher.matches? { "foo" } # => true
|
|
69
73
|
|
70
74
|
```ruby
|
71
75
|
matcher = Matchi::Be.new(:foo)
|
76
|
+
|
77
|
+
matcher.expected # => :foo
|
72
78
|
matcher.matches? { :foo } # => true
|
73
79
|
```
|
74
80
|
|
81
|
+
**Comparisons** matcher:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
matcher = Matchi::BeWithin.new(8).of(37)
|
85
|
+
|
86
|
+
matcher.expected # => 37
|
87
|
+
matcher.matches? { 42 } # => true
|
88
|
+
```
|
89
|
+
|
75
90
|
**Regular expressions** matcher:
|
76
91
|
|
77
92
|
```ruby
|
78
93
|
matcher = Matchi::Match.new(/^foo$/)
|
94
|
+
|
95
|
+
matcher.expected # => /^foo$/
|
79
96
|
matcher.matches? { "foo" } # => true
|
80
97
|
```
|
81
98
|
|
82
99
|
**Expecting errors** matcher:
|
83
100
|
|
84
101
|
```ruby
|
85
|
-
matcher = Matchi::RaiseException.new(NameError)
|
102
|
+
matcher = Matchi::RaiseException.new(:NameError)
|
103
|
+
|
104
|
+
matcher.expected # => "NameError"
|
86
105
|
matcher.matches? { Boom } # => true
|
87
106
|
```
|
88
107
|
|
@@ -90,30 +109,56 @@ matcher.matches? { Boom } # => true
|
|
90
109
|
|
91
110
|
```ruby
|
92
111
|
matcher = Matchi::BeAnInstanceOf.new(:String)
|
112
|
+
|
113
|
+
matcher.expected # => "String"
|
93
114
|
matcher.matches? { "foo" } # => true
|
94
115
|
```
|
95
116
|
|
117
|
+
**Predicate** matcher:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
matcher = Matchi::Predicate.new(:be_empty)
|
121
|
+
|
122
|
+
matcher.expected # => [:empty?, [], {}, nil]
|
123
|
+
matcher.matches? { [] } # => true
|
124
|
+
|
125
|
+
matcher = Matchi::Predicate.new(:have_key, :foo)
|
126
|
+
|
127
|
+
matcher.expected # => [:has_key?, [:foo], {}, nil]
|
128
|
+
matcher.matches? { { foo: 42 } } # => true
|
129
|
+
```
|
130
|
+
|
96
131
|
**Change** matcher:
|
97
132
|
|
98
133
|
```ruby
|
99
134
|
object = []
|
100
135
|
matcher = Matchi::Change.new(object, :length).by(1)
|
136
|
+
|
137
|
+
matcher.expected # => 1
|
101
138
|
matcher.matches? { object << 1 } # => true
|
102
139
|
|
103
140
|
object = []
|
104
141
|
matcher = Matchi::Change.new(object, :length).by_at_least(1)
|
142
|
+
|
143
|
+
matcher.expected # => 1
|
105
144
|
matcher.matches? { object << 1 } # => true
|
106
145
|
|
107
146
|
object = []
|
108
147
|
matcher = Matchi::Change.new(object, :length).by_at_most(1)
|
148
|
+
|
149
|
+
matcher.expected # => 1
|
109
150
|
matcher.matches? { object << 1 } # => true
|
110
151
|
|
111
152
|
object = "foo"
|
112
153
|
matcher = Matchi::Change.new(object, :to_s).from("foo").to("FOO")
|
154
|
+
|
155
|
+
matcher.expected # => "FOO"
|
113
156
|
matcher.matches? { object.upcase! } # => true
|
114
157
|
|
115
158
|
object = "foo"
|
116
159
|
matcher = Matchi::Change.new(object, :to_s).to("FOO")
|
160
|
+
|
161
|
+
matcher.expected # => "FOO"
|
117
162
|
matcher.matches? { object.upcase! } # => true
|
118
163
|
```
|
119
164
|
|
@@ -121,6 +166,8 @@ matcher.matches? { object.upcase! } # => true
|
|
121
166
|
|
122
167
|
```ruby
|
123
168
|
matcher = Matchi::Satisfy.new { |value| value == 42 }
|
169
|
+
|
170
|
+
matcher.expected # => #<Proc:0x00007fbaafc65540>
|
124
171
|
matcher.matches? { 42 } # => true
|
125
172
|
```
|
126
173
|
|
@@ -133,13 +180,19 @@ A **Be the answer** matcher:
|
|
133
180
|
```ruby
|
134
181
|
module Matchi
|
135
182
|
class BeTheAnswer
|
183
|
+
def expected
|
184
|
+
42
|
185
|
+
end
|
186
|
+
|
136
187
|
def matches?
|
137
|
-
|
188
|
+
expected.equal?(yield)
|
138
189
|
end
|
139
190
|
end
|
140
191
|
end
|
141
192
|
|
142
193
|
matcher = Matchi::BeTheAnswer.new
|
194
|
+
|
195
|
+
matcher.expected # => 42
|
143
196
|
matcher.matches? { 42 } # => true
|
144
197
|
```
|
145
198
|
|
@@ -157,6 +210,7 @@ module Matchi
|
|
157
210
|
end
|
158
211
|
|
159
212
|
matcher = Matchi::BePrime.new
|
213
|
+
|
160
214
|
matcher.matches? { 42 } # => false
|
161
215
|
```
|
162
216
|
|
@@ -178,6 +232,8 @@ module Matchi
|
|
178
232
|
end
|
179
233
|
|
180
234
|
matcher = Matchi::StartWith.new("foo")
|
235
|
+
|
236
|
+
matcher.expected # => "foo"
|
181
237
|
matcher.matches? { "foobar" } # => true
|
182
238
|
```
|
183
239
|
|
data/lib/matchi/be.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Identity* matcher.
|
5
5
|
class Be
|
6
|
+
# @return [#equal?] The expected identical object.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with an object.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -21,24 +24,26 @@ module Matchi
|
|
21
24
|
# require "matchi/be"
|
22
25
|
#
|
23
26
|
# matcher = Matchi::Be.new(:foo)
|
27
|
+
#
|
28
|
+
# matcher.expected # => :foo
|
24
29
|
# matcher.matches? { :foo } # => true
|
25
30
|
#
|
26
31
|
# @yieldreturn [#object_id] The actual value to compare to the expected
|
27
32
|
# one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
31
|
-
|
35
|
+
def matches?
|
36
|
+
expected.equal?(yield)
|
32
37
|
end
|
33
38
|
|
34
39
|
# A string containing a human-readable representation of the matcher.
|
35
40
|
def inspect
|
36
|
-
"#{self.class}(#{
|
41
|
+
"#{self.class}(#{expected.inspect})"
|
37
42
|
end
|
38
43
|
|
39
44
|
# Returns a string representing the matcher.
|
40
45
|
def to_s
|
41
|
-
"be #{
|
46
|
+
"be #{expected.inspect}"
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Type/class* matcher.
|
5
5
|
class BeAnInstanceOf
|
6
|
+
# @return [String] The expected class name.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with (the name of) a class or module.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -10,9 +13,9 @@ module Matchi
|
|
10
13
|
#
|
11
14
|
# Matchi::BeAnInstanceOf.new(String)
|
12
15
|
#
|
13
|
-
# @param expected [#to_s]
|
16
|
+
# @param expected [Class, #to_s] The expected class name.
|
14
17
|
def initialize(expected)
|
15
|
-
@expected = String(expected)
|
18
|
+
@expected = String(expected)
|
16
19
|
end
|
17
20
|
|
18
21
|
# Boolean comparison between the class of the actual value and the
|
@@ -22,23 +25,25 @@ module Matchi
|
|
22
25
|
# require "matchi/be_an_instance_of"
|
23
26
|
#
|
24
27
|
# matcher = Matchi::BeAnInstanceOf.new(String)
|
28
|
+
#
|
29
|
+
# matcher.expected # => "String"
|
25
30
|
# matcher.matches? { "foo" } # => true
|
26
31
|
#
|
27
32
|
# @yieldreturn [#class] the actual value to compare to the expected one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
31
|
-
self.class.const_get(
|
35
|
+
def matches?
|
36
|
+
self.class.const_get(expected).equal?(yield.class)
|
32
37
|
end
|
33
38
|
|
34
39
|
# A string containing a human-readable representation of the matcher.
|
35
40
|
def inspect
|
36
|
-
"#{self.class}(#{
|
41
|
+
"#{self.class}(#{expected})"
|
37
42
|
end
|
38
43
|
|
39
44
|
# Returns a string representing the matcher.
|
40
45
|
def to_s
|
41
|
-
"be an instance of #{
|
46
|
+
"be an instance of #{expected}"
|
42
47
|
end
|
43
48
|
end
|
44
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
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Matchi
|
4
|
+
class BeWithin
|
5
|
+
# *BeWithin of* matcher.
|
6
|
+
class Of
|
7
|
+
# @return [Numeric] An expected value.
|
8
|
+
attr_reader :expected
|
9
|
+
|
10
|
+
# Initialize the matcher with a delta and an expected value.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# require "matchi/be_within/of"
|
14
|
+
#
|
15
|
+
# Matchi::BeWithin::Of.new(1, 41)
|
16
|
+
#
|
17
|
+
# @param delta [Numeric] The accepted variation of the actual value.
|
18
|
+
# @param expected [Numeric] The expected value.
|
19
|
+
def initialize(delta, expected)
|
20
|
+
@delta = delta
|
21
|
+
@expected = expected
|
22
|
+
end
|
23
|
+
|
24
|
+
# Boolean comparison on the expected be_within by comparing the actual
|
25
|
+
# value and the expected value.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# require "matchi/be_within/of"
|
29
|
+
#
|
30
|
+
# matcher = Matchi::BeWithin::Of.new(1, 41)
|
31
|
+
#
|
32
|
+
# matcher.expected # => 41
|
33
|
+
# matcher.matches? { 42 } # => true
|
34
|
+
#
|
35
|
+
# @yieldreturn [Numeric] The block of code to execute.
|
36
|
+
#
|
37
|
+
# @return [Boolean] Comparison between the actual and the expected values.
|
38
|
+
def matches?
|
39
|
+
(expected - yield).abs <= @delta
|
40
|
+
end
|
41
|
+
|
42
|
+
# A string containing a human-readable representation of the matcher.
|
43
|
+
def inspect
|
44
|
+
"#{self.class}(#{@delta}, #{expected})"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a string representing the matcher.
|
48
|
+
def to_s
|
49
|
+
"be within #{@delta} of #{expected}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/matchi/change.rb
CHANGED
@@ -32,14 +32,14 @@ module Matchi
|
|
32
32
|
#
|
33
33
|
# object = []
|
34
34
|
#
|
35
|
-
#
|
36
|
-
#
|
35
|
+
# change_wrapper = Matchi::Change.new(object, :length)
|
36
|
+
# change_wrapper.by_at_least(1)
|
37
37
|
#
|
38
|
-
# @param
|
38
|
+
# @param minimum_delta [#object_id] The minimum delta of the expected change.
|
39
39
|
#
|
40
40
|
# @return [#matches?] A *change by at least* matcher.
|
41
|
-
def by_at_least(
|
42
|
-
ByAtLeast.new(
|
41
|
+
def by_at_least(minimum_delta)
|
42
|
+
ByAtLeast.new(minimum_delta, &@state)
|
43
43
|
end
|
44
44
|
|
45
45
|
# Specifies a maximum delta of the expected change.
|
@@ -49,14 +49,14 @@ module Matchi
|
|
49
49
|
#
|
50
50
|
# object = []
|
51
51
|
#
|
52
|
-
#
|
53
|
-
#
|
52
|
+
# change_wrapper = Matchi::Change.new(object, :length)
|
53
|
+
# change_wrapper.by_at_most(1)
|
54
54
|
#
|
55
|
-
# @param
|
55
|
+
# @param maximum_delta [#object_id] The maximum delta of the expected change.
|
56
56
|
#
|
57
57
|
# @return [#matches?] A *change by at most* matcher.
|
58
|
-
def by_at_most(
|
59
|
-
ByAtMost.new(
|
58
|
+
def by_at_most(maximum_delta)
|
59
|
+
ByAtMost.new(maximum_delta, &@state)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Specifies the delta of the expected change.
|
@@ -66,14 +66,14 @@ module Matchi
|
|
66
66
|
#
|
67
67
|
# object = []
|
68
68
|
#
|
69
|
-
#
|
70
|
-
#
|
69
|
+
# change_wrapper = Matchi::Change.new(object, :length)
|
70
|
+
# change_wrapper.by(1)
|
71
71
|
#
|
72
|
-
# @param
|
72
|
+
# @param delta [#object_id] The delta of the expected change.
|
73
73
|
#
|
74
74
|
# @return [#matches?] A *change by* matcher.
|
75
|
-
def by(
|
76
|
-
By.new(
|
75
|
+
def by(delta)
|
76
|
+
By.new(delta, &@state)
|
77
77
|
end
|
78
78
|
|
79
79
|
# Specifies the original value.
|
@@ -81,14 +81,14 @@ module Matchi
|
|
81
81
|
# @example
|
82
82
|
# require "matchi/change"
|
83
83
|
#
|
84
|
-
#
|
85
|
-
#
|
84
|
+
# change_wrapper = Matchi::Change.new("foo", :to_s)
|
85
|
+
# change_wrapper.from("foo")
|
86
86
|
#
|
87
|
-
# @param
|
87
|
+
# @param old_value [#object_id] The original value.
|
88
88
|
#
|
89
89
|
# @return [#matches?] A *change from* wrapper.
|
90
|
-
def from(
|
91
|
-
From.new(
|
90
|
+
def from(old_value)
|
91
|
+
From.new(old_value, &@state)
|
92
92
|
end
|
93
93
|
|
94
94
|
# Specifies the new value to expect.
|
@@ -96,14 +96,14 @@ module Matchi
|
|
96
96
|
# @example
|
97
97
|
# require "matchi/change"
|
98
98
|
#
|
99
|
-
#
|
100
|
-
#
|
99
|
+
# change_wrapper = Matchi::Change.new("foo", :to_s)
|
100
|
+
# change_wrapper.to("FOO")
|
101
101
|
#
|
102
|
-
# @param
|
102
|
+
# @param new_value [#object_id] The new value to expect.
|
103
103
|
#
|
104
104
|
# @return [#matches?] A *change to* matcher.
|
105
|
-
def to(
|
106
|
-
To.new(
|
105
|
+
def to(new_value)
|
106
|
+
To.new(new_value, &@state)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
data/lib/matchi/change/by.rb
CHANGED
@@ -4,6 +4,9 @@ module Matchi
|
|
4
4
|
class Change
|
5
5
|
# *Change by* matcher.
|
6
6
|
class By
|
7
|
+
# @return [#object_id] An expected delta.
|
8
|
+
attr_reader :expected
|
9
|
+
|
7
10
|
# Initialize the matcher with an object and a block.
|
8
11
|
#
|
9
12
|
# @example
|
@@ -30,28 +33,30 @@ module Matchi
|
|
30
33
|
# object = []
|
31
34
|
#
|
32
35
|
# matcher = Matchi::Change::By.new(1) { object.length }
|
36
|
+
#
|
37
|
+
# matcher.expected # => 1
|
33
38
|
# matcher.matches? { object << "foo" } # => true
|
34
39
|
#
|
35
40
|
# @yieldreturn [#object_id] The block of code to execute.
|
36
41
|
#
|
37
42
|
# @return [Boolean] Comparison between the value before and after the
|
38
43
|
# code execution.
|
39
|
-
def matches?
|
44
|
+
def matches?
|
40
45
|
value_before = @state.call
|
41
46
|
yield
|
42
47
|
value_after = @state.call
|
43
48
|
|
44
|
-
|
49
|
+
expected == (value_after - value_before)
|
45
50
|
end
|
46
51
|
|
47
52
|
# A string containing a human-readable representation of the matcher.
|
48
53
|
def inspect
|
49
|
-
"#{self.class}(#{
|
54
|
+
"#{self.class}(#{expected.inspect})"
|
50
55
|
end
|
51
56
|
|
52
57
|
# Returns a string representing the matcher.
|
53
58
|
def to_s
|
54
|
-
"change by #{
|
59
|
+
"change by #{expected.inspect}"
|
55
60
|
end
|
56
61
|
end
|
57
62
|
end
|
@@ -4,6 +4,9 @@ module Matchi
|
|
4
4
|
class Change
|
5
5
|
# *Change by at least* matcher.
|
6
6
|
class ByAtLeast
|
7
|
+
# @return [#object_id] An expected delta.
|
8
|
+
attr_reader :expected
|
9
|
+
|
7
10
|
# Initialize the matcher with an object and a block.
|
8
11
|
#
|
9
12
|
# @example
|
@@ -30,28 +33,30 @@ module Matchi
|
|
30
33
|
# object = []
|
31
34
|
#
|
32
35
|
# matcher = Matchi::Change::ByAtLeast.new(1) { object.length }
|
36
|
+
#
|
37
|
+
# matcher.expected # => 1
|
33
38
|
# matcher.matches? { object << "foo" } # => true
|
34
39
|
#
|
35
40
|
# @yieldreturn [#object_id] The block of code to execute.
|
36
41
|
#
|
37
42
|
# @return [Boolean] Comparison between the value before and after the
|
38
43
|
# code execution.
|
39
|
-
def matches?
|
44
|
+
def matches?
|
40
45
|
value_before = @state.call
|
41
46
|
yield
|
42
47
|
value_after = @state.call
|
43
48
|
|
44
|
-
|
49
|
+
expected <= (value_after - value_before)
|
45
50
|
end
|
46
51
|
|
47
52
|
# A string containing a human-readable representation of the matcher.
|
48
53
|
def inspect
|
49
|
-
"#{self.class}(#{
|
54
|
+
"#{self.class}(#{expected.inspect})"
|
50
55
|
end
|
51
56
|
|
52
57
|
# Returns a string representing the matcher.
|
53
58
|
def to_s
|
54
|
-
"change by at least #{
|
59
|
+
"change by at least #{expected.inspect}"
|
55
60
|
end
|
56
61
|
end
|
57
62
|
end
|
@@ -4,6 +4,9 @@ module Matchi
|
|
4
4
|
class Change
|
5
5
|
# *Change by at most* matcher.
|
6
6
|
class ByAtMost
|
7
|
+
# @return [#object_id] An expected delta.
|
8
|
+
attr_reader :expected
|
9
|
+
|
7
10
|
# Initialize the matcher with an object and a block.
|
8
11
|
#
|
9
12
|
# @example
|
@@ -30,28 +33,30 @@ module Matchi
|
|
30
33
|
# object = []
|
31
34
|
#
|
32
35
|
# matcher = Matchi::Change::ByAtMost.new(1) { object.length }
|
36
|
+
#
|
37
|
+
# matcher.expected # => 1
|
33
38
|
# matcher.matches? { object << "foo" } # => true
|
34
39
|
#
|
35
40
|
# @yieldreturn [#object_id] The block of code to execute.
|
36
41
|
#
|
37
42
|
# @return [Boolean] Comparison between the value before and after the
|
38
43
|
# code execution.
|
39
|
-
def matches?
|
44
|
+
def matches?
|
40
45
|
value_before = @state.call
|
41
46
|
yield
|
42
47
|
value_after = @state.call
|
43
48
|
|
44
|
-
|
49
|
+
expected >= (value_after - value_before)
|
45
50
|
end
|
46
51
|
|
47
52
|
# A string containing a human-readable representation of the matcher.
|
48
53
|
def inspect
|
49
|
-
"#{self.class}(#{
|
54
|
+
"#{self.class}(#{expected.inspect})"
|
50
55
|
end
|
51
56
|
|
52
57
|
# Returns a string representing the matcher.
|
53
58
|
def to_s
|
54
|
-
"change by at most #{
|
59
|
+
"change by at most #{expected.inspect}"
|
55
60
|
end
|
56
61
|
end
|
57
62
|
end
|
data/lib/matchi/change/from.rb
CHANGED
@@ -30,8 +30,8 @@ module Matchi
|
|
30
30
|
#
|
31
31
|
# object = "foo"
|
32
32
|
#
|
33
|
-
#
|
34
|
-
#
|
33
|
+
# change_from_wrapper = Matchi::Change::From.new("foo") { object.to_s }
|
34
|
+
# change_from_wrapper.to("FOO")
|
35
35
|
#
|
36
36
|
# @param expected_new_value [#object_id] The new value to expect.
|
37
37
|
#
|
@@ -5,6 +5,9 @@ module Matchi
|
|
5
5
|
class From
|
6
6
|
# *Change from to* matcher.
|
7
7
|
class To
|
8
|
+
# @return [#object_id] An expected new value.
|
9
|
+
attr_reader :expected
|
10
|
+
|
8
11
|
# Initialize the matcher with two objects and a block.
|
9
12
|
#
|
10
13
|
# @example
|
@@ -33,30 +36,32 @@ module Matchi
|
|
33
36
|
# object = "foo"
|
34
37
|
#
|
35
38
|
# matcher = Matchi::Change::From::To.new("foo", "FOO") { object.to_s }
|
39
|
+
#
|
40
|
+
# matcher.expected # => "FOO"
|
36
41
|
# matcher.matches? { object.upcase! } # => true
|
37
42
|
#
|
38
43
|
# @yieldreturn [#object_id] The block of code to execute.
|
39
44
|
#
|
40
45
|
# @return [Boolean] Comparison between the value before and after the
|
41
46
|
# code execution.
|
42
|
-
def matches?
|
47
|
+
def matches?
|
43
48
|
value_before = @state.call
|
44
49
|
return false unless @expected_init == value_before
|
45
50
|
|
46
51
|
yield
|
47
52
|
value_after = @state.call
|
48
53
|
|
49
|
-
|
54
|
+
expected == value_after
|
50
55
|
end
|
51
56
|
|
52
57
|
# A string containing a human-readable representation of the matcher.
|
53
58
|
def inspect
|
54
|
-
"#{self.class}(#{@expected_init.inspect}, #{
|
59
|
+
"#{self.class}(#{@expected_init.inspect}, #{expected.inspect})"
|
55
60
|
end
|
56
61
|
|
57
62
|
# Returns a string representing the matcher.
|
58
63
|
def to_s
|
59
|
-
"change from #{@expected_init.inspect} to #{
|
64
|
+
"change from #{@expected_init.inspect} to #{expected.inspect}"
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
data/lib/matchi/change/to.rb
CHANGED
@@ -4,6 +4,9 @@ module Matchi
|
|
4
4
|
class Change
|
5
5
|
# *Change to* matcher.
|
6
6
|
class To
|
7
|
+
# @return [#object_id] An expected new value.
|
8
|
+
attr_reader :expected
|
9
|
+
|
7
10
|
# Initialize the matcher with an object and a block.
|
8
11
|
#
|
9
12
|
# @example
|
@@ -13,7 +16,7 @@ module Matchi
|
|
13
16
|
#
|
14
17
|
# Matchi::Change::To.new("FOO") { object.to_s }
|
15
18
|
#
|
16
|
-
# @param expected [#object_id] An expected
|
19
|
+
# @param expected [#object_id] An expected new value.
|
17
20
|
# @param state [Proc] A block of code to execute to get the
|
18
21
|
# state of the object.
|
19
22
|
def initialize(expected, &state)
|
@@ -30,27 +33,29 @@ module Matchi
|
|
30
33
|
# object = "foo"
|
31
34
|
#
|
32
35
|
# matcher = Matchi::Change::To.new("FOO") { object.to_s }
|
36
|
+
#
|
37
|
+
# matcher.expected # => "FOO"
|
33
38
|
# matcher.matches? { object.upcase! } # => true
|
34
39
|
#
|
35
40
|
# @yieldreturn [#object_id] The block of code to execute.
|
36
41
|
#
|
37
42
|
# @return [Boolean] Comparison between the value before and after the
|
38
43
|
# code execution.
|
39
|
-
def matches?
|
44
|
+
def matches?
|
40
45
|
yield
|
41
46
|
value_after = @state.call
|
42
47
|
|
43
|
-
|
48
|
+
expected == value_after
|
44
49
|
end
|
45
50
|
|
46
51
|
# A string containing a human-readable representation of the matcher.
|
47
52
|
def inspect
|
48
|
-
"#{self.class}(#{
|
53
|
+
"#{self.class}(#{expected.inspect})"
|
49
54
|
end
|
50
55
|
|
51
56
|
# Returns a string representing the matcher.
|
52
57
|
def to_s
|
53
|
-
"change to #{
|
58
|
+
"change to #{expected.inspect}"
|
54
59
|
end
|
55
60
|
end
|
56
61
|
end
|
data/lib/matchi/eq.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Equivalence* matcher.
|
5
5
|
class Eq
|
6
|
+
# @return [#eql?] An expected equivalent object.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with an object.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -21,24 +24,26 @@ module Matchi
|
|
21
24
|
# require "matchi/eq"
|
22
25
|
#
|
23
26
|
# matcher = Matchi::Eq.new("foo")
|
27
|
+
#
|
28
|
+
# matcher.expected # => "foo"
|
24
29
|
# matcher.matches? { "foo" } # => true
|
25
30
|
#
|
26
31
|
# @yieldreturn [#object_id] The actual value to compare to the expected
|
27
32
|
# one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
31
|
-
|
35
|
+
def matches?
|
36
|
+
expected.eql?(yield)
|
32
37
|
end
|
33
38
|
|
34
39
|
# A string containing a human-readable representation of the matcher.
|
35
40
|
def inspect
|
36
|
-
"#{self.class}(#{
|
41
|
+
"#{self.class}(#{expected.inspect})"
|
37
42
|
end
|
38
43
|
|
39
44
|
# Returns a string representing the matcher.
|
40
45
|
def to_s
|
41
|
-
"eq #{
|
46
|
+
"eq #{expected.inspect}"
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
data/lib/matchi/match.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Regular expressions* matcher.
|
5
5
|
class Match
|
6
|
+
# @return [#match] A regular expression.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with an instance of Regexp.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -21,24 +24,26 @@ module Matchi
|
|
21
24
|
# require "matchi/match"
|
22
25
|
#
|
23
26
|
# matcher = Matchi::Match.new(/^foo$/)
|
27
|
+
#
|
28
|
+
# matcher.expected # => /^foo$/
|
24
29
|
# matcher.matches? { "foo" } # => true
|
25
30
|
#
|
26
31
|
# @yieldreturn [#object_id] The actual value to compare to the expected
|
27
32
|
# one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
31
|
-
|
35
|
+
def matches?
|
36
|
+
expected.match?(yield)
|
32
37
|
end
|
33
38
|
|
34
39
|
# A string containing a human-readable representation of the matcher.
|
35
40
|
def inspect
|
36
|
-
"#{self.class}(#{
|
41
|
+
"#{self.class}(#{expected.inspect})"
|
37
42
|
end
|
38
43
|
|
39
44
|
# Returns a string representing the matcher.
|
40
45
|
def to_s
|
41
|
-
"match #{
|
46
|
+
"match #{expected.inspect}"
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Matchi
|
4
|
+
# *Predicate* matcher.
|
5
|
+
class Predicate
|
6
|
+
# Initialize the matcher with a name and arguments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# require "matchi/predicate"
|
10
|
+
#
|
11
|
+
# Matchi::Predicate.new(:be_empty)
|
12
|
+
#
|
13
|
+
# @param name [#to_s] A matcher name.
|
14
|
+
# @param args [Array] A list of parameters.
|
15
|
+
# @param kwargs [Hash] A list of keyword parameters.
|
16
|
+
# @param block [Proc] A block of code.
|
17
|
+
def initialize(name, *args, **kwargs, &block)
|
18
|
+
@name = String(name)
|
19
|
+
|
20
|
+
raise ::ArgumentError unless valid_name?
|
21
|
+
|
22
|
+
@args = args
|
23
|
+
@kwargs = kwargs
|
24
|
+
@block = block
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Array] The method name with any arguments to send to the subject.
|
28
|
+
def expected
|
29
|
+
[method_name, @args, @kwargs, @block]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Boolean comparison between the actual value and the expected value.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require "matchi/predicate"
|
36
|
+
#
|
37
|
+
# matcher = Matchi::Predicate.new(:be_empty)
|
38
|
+
#
|
39
|
+
# matcher.expected # => [:empty?, [], {}, nil]
|
40
|
+
# matcher.matches? { [] } # => true
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# require "matchi/predicate"
|
44
|
+
#
|
45
|
+
# matcher = Matchi::Predicate.new(:have_key, :foo)
|
46
|
+
#
|
47
|
+
# matcher.expected # => [:has_key?, [:foo], {}, nil]
|
48
|
+
# matcher.matches? { { foo: 42 } } # => true
|
49
|
+
#
|
50
|
+
# @yieldreturn [#object_id] The actual value to receive the method request.
|
51
|
+
#
|
52
|
+
# @return [Boolean] A boolean returned by the actual value being tested.
|
53
|
+
def matches?
|
54
|
+
value = yield.send(method_name, *@args, **@kwargs, &@block)
|
55
|
+
return value if [false, true].include?(value)
|
56
|
+
|
57
|
+
raise ::TypeError, "Boolean expected, but #{value.class} instance returned."
|
58
|
+
end
|
59
|
+
|
60
|
+
# A string containing a human-readable representation of the matcher.
|
61
|
+
def inspect
|
62
|
+
"#{self.class}(#{@name}, *#{@args.inspect}, **#{@kwargs.inspect}, &#{@block.inspect})"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a string representing the matcher.
|
66
|
+
def to_s
|
67
|
+
(
|
68
|
+
"#{@name.tr('_', ' ')} " + [
|
69
|
+
@args.map(&:inspect).join(", "),
|
70
|
+
@kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(", "),
|
71
|
+
(@block.nil? ? "" : "&block")
|
72
|
+
].reject { |i| i.eql?("") }.join(", ")
|
73
|
+
).strip
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# The name of the method to send to the object.
|
79
|
+
def method_name
|
80
|
+
if @name.start_with?("be_")
|
81
|
+
:"#{@name.gsub("be_", "")}?"
|
82
|
+
else
|
83
|
+
:"#{@name.gsub("have_", "has_")}?"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Verify the matcher name structure.
|
88
|
+
def valid_name?
|
89
|
+
return false if @name.end_with?("?", "!")
|
90
|
+
|
91
|
+
@name.start_with?("be_", "have_")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Expecting errors* matcher.
|
5
5
|
class RaiseException
|
6
|
+
# @return [String] The expected exception name.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with a descendant of class Exception.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -10,9 +13,9 @@ module Matchi
|
|
10
13
|
#
|
11
14
|
# Matchi::RaiseException.new(NameError)
|
12
15
|
#
|
13
|
-
# @param expected [Exception] The
|
16
|
+
# @param expected [Exception, #to_s] The expected exception name.
|
14
17
|
def initialize(expected)
|
15
|
-
@expected = expected
|
18
|
+
@expected = String(expected)
|
16
19
|
end
|
17
20
|
|
18
21
|
# Boolean comparison between the actual value and the expected value.
|
@@ -21,15 +24,17 @@ module Matchi
|
|
21
24
|
# require "matchi/raise_exception"
|
22
25
|
#
|
23
26
|
# matcher = Matchi::RaiseException.new(NameError)
|
27
|
+
#
|
28
|
+
# matcher.expected # => "NameError"
|
24
29
|
# matcher.matches? { Boom } # => true
|
25
30
|
#
|
26
31
|
# @yieldreturn [#object_id] The actual value to compare to the expected
|
27
32
|
# one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
35
|
+
def matches?
|
31
36
|
yield
|
32
|
-
rescue
|
37
|
+
rescue self.class.const_get(expected) => _e
|
33
38
|
true
|
34
39
|
else
|
35
40
|
false
|
@@ -37,12 +42,12 @@ module Matchi
|
|
37
42
|
|
38
43
|
# A string containing a human-readable representation of the matcher.
|
39
44
|
def inspect
|
40
|
-
"#{self.class}(#{
|
45
|
+
"#{self.class}(#{expected})"
|
41
46
|
end
|
42
47
|
|
43
48
|
# Returns a string representing the matcher.
|
44
49
|
def to_s
|
45
|
-
"raise exception #{
|
50
|
+
"raise exception #{expected}"
|
46
51
|
end
|
47
52
|
end
|
48
53
|
end
|
data/lib/matchi/satisfy.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
module Matchi
|
4
4
|
# *Satisfy* matcher.
|
5
5
|
class Satisfy
|
6
|
+
# @return [Proc] A block of code.
|
7
|
+
attr_reader :expected
|
8
|
+
|
6
9
|
# Initialize the matcher with a block.
|
7
10
|
#
|
8
11
|
# @example
|
@@ -21,14 +24,16 @@ module Matchi
|
|
21
24
|
# require "matchi/satisfy"
|
22
25
|
#
|
23
26
|
# matcher = Matchi::Satisfy.new { |value| value == 42 }
|
27
|
+
#
|
28
|
+
# matcher.expected # => #<Proc:0x00007fbaafc65540>
|
24
29
|
# matcher.matches? { 42 } # => true
|
25
30
|
#
|
26
31
|
# @yieldreturn [#object_id] The actual value to compare to the expected
|
27
32
|
# one.
|
28
33
|
#
|
29
34
|
# @return [Boolean] Comparison between actual and expected values.
|
30
|
-
def matches?
|
31
|
-
|
35
|
+
def matches?
|
36
|
+
expected.call(yield)
|
32
37
|
end
|
33
38
|
|
34
39
|
# A string containing a human-readable representation of the matcher.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matchi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -133,6 +133,8 @@ files:
|
|
133
133
|
- lib/matchi.rb
|
134
134
|
- lib/matchi/be.rb
|
135
135
|
- lib/matchi/be_an_instance_of.rb
|
136
|
+
- lib/matchi/be_within.rb
|
137
|
+
- lib/matchi/be_within/of.rb
|
136
138
|
- lib/matchi/change.rb
|
137
139
|
- lib/matchi/change/by.rb
|
138
140
|
- lib/matchi/change/by_at_least.rb
|
@@ -142,6 +144,7 @@ files:
|
|
142
144
|
- lib/matchi/change/to.rb
|
143
145
|
- lib/matchi/eq.rb
|
144
146
|
- lib/matchi/match.rb
|
147
|
+
- lib/matchi/predicate.rb
|
145
148
|
- lib/matchi/raise_exception.rb
|
146
149
|
- lib/matchi/satisfy.rb
|
147
150
|
homepage: https://github.com/fixrb/matchi
|