matchi 4.1.1 → 4.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.
@@ -1,16 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Matchi
4
- # *Expecting errors* matcher.
4
+ # Exception matcher that verifies if a block of code raises a specific exception.
5
+ #
6
+ # This matcher ensures that code raises an expected exception by executing it within
7
+ # a controlled environment. It supports matching against specific exception classes
8
+ # and their subclasses, providing a reliable way to test error handling.
9
+ #
10
+ # @example Basic usage with standard exceptions
11
+ # matcher = Matchi::RaiseException.new(ArgumentError)
12
+ # matcher.match? { raise ArgumentError } # => true
13
+ # matcher.match? { raise RuntimeError } # => false
14
+ # matcher.match? { "no error" } # => false
15
+ #
16
+ # @example Working with inheritance hierarchy
17
+ # class CustomError < StandardError; end
18
+ # class SpecificError < CustomError; end
19
+ #
20
+ # matcher = Matchi::RaiseException.new(CustomError)
21
+ # matcher.match? { raise CustomError } # => true
22
+ # matcher.match? { raise SpecificError } # => true
23
+ # matcher.match? { raise StandardError } # => false
24
+ #
25
+ # @example Using string class names
26
+ # matcher = Matchi::RaiseException.new("ArgumentError")
27
+ # matcher.match? { raise ArgumentError } # => true
28
+ #
29
+ # @example With custom exception hierarchies
30
+ # module Api
31
+ # class Error < StandardError; end
32
+ # class AuthenticationError < Error; end
33
+ # end
34
+ #
35
+ # matcher = Matchi::RaiseException.new("Api::Error")
36
+ # matcher.match? { raise Api::AuthenticationError } # => true
37
+ #
38
+ # @see https://ruby-doc.org/core/Exception.html
39
+ # @see https://ruby-doc.org/core/StandardError.html
5
40
  class RaiseException
6
- # Initialize the matcher with a descendant of class Exception.
41
+ # Initialize the matcher with an exception class.
7
42
  #
8
- # @example
9
- # require "matchi/raise_exception"
43
+ # @api public
44
+ #
45
+ # @param expected [Exception, #to_s] The expected exception class or its name
46
+ # Can be provided as a Class, String, or Symbol
10
47
  #
11
- # Matchi::RaiseException.new(NameError)
48
+ # @raise [ArgumentError] if the class name doesn't start with an uppercase letter
12
49
  #
13
- # @param expected [Exception, #to_s] The expected exception name.
50
+ # @return [RaiseException] a new instance of the matcher
51
+ #
52
+ # @example
53
+ # RaiseException.new(ArgumentError) # Using class
54
+ # RaiseException.new("ArgumentError") # Using string
55
+ # RaiseException.new(:ArgumentError) # Using symbol
56
+ # RaiseException.new("Api::CustomError") # Using namespaced class
14
57
  def initialize(expected)
15
58
  @expected = String(expected)
16
59
  return if /\A[A-Z]/.match?(@expected)
@@ -19,18 +62,34 @@ module Matchi
19
62
  "expected must start with an uppercase letter (got: #{@expected})"
20
63
  end
21
64
 
22
- # Boolean comparison between the actual value and the expected value.
65
+ # Checks if the yielded block raises the expected exception.
23
66
  #
24
- # @example
25
- # require "matchi/raise_exception"
67
+ # This method executes the provided block within a begin/rescue clause and verifies
68
+ # that it raises an exception of the expected type. It also handles inheritance,
69
+ # allowing subclasses of the expected exception to match.
70
+ #
71
+ # @api public
72
+ #
73
+ # @yield [] Block that should raise an exception
74
+ # @yieldreturn [Object] The result of the block (if it doesn't raise)
26
75
  #
27
- # matcher = Matchi::RaiseException.new(NameError)
28
- # matcher.match? { Boom } # => true
76
+ # @return [Boolean] true if the block raises the expected exception
29
77
  #
30
- # @yieldreturn [#object_id] The actual value to compare to the expected
31
- # one.
78
+ # @raise [ArgumentError] if no block is provided
79
+ # @raise [ArgumentError] if expected exception class doesn't inherit from Exception
80
+ # @raise [NameError] if the expected exception class cannot be found
32
81
  #
33
- # @return [Boolean] Comparison between actual and expected values.
82
+ # @example Standard usage
83
+ # matcher = RaiseException.new(ArgumentError)
84
+ # matcher.match? { raise ArgumentError } # => true
85
+ #
86
+ # @example With inheritance
87
+ # matcher = RaiseException.new(StandardError)
88
+ # matcher.match? { raise ArgumentError } # => true
89
+ #
90
+ # @example Without exception
91
+ # matcher = RaiseException.new(StandardError)
92
+ # matcher.match? { "no error" } # => false
34
93
  def match?
35
94
  raise ::ArgumentError, "a block must be provided" unless block_given?
36
95
 
@@ -40,25 +99,33 @@ module Matchi
40
99
  begin
41
100
  yield
42
101
  false
43
- rescue Exception => e # rubocop:disable Lint/RescueException
44
- e.class <= klass # Checks if the class of the thrown exception is klass or one of its subclasses
102
+ rescue ::Exception => e # rubocop:disable Lint/RescueException
103
+ e.class <= klass
45
104
  end
46
105
  end
47
106
 
48
- # Returns a string representing the matcher.
107
+ # Returns a human-readable description of the matcher.
108
+ #
109
+ # @api public
110
+ #
111
+ # @return [String] A string describing what this matcher verifies
49
112
  #
50
- # @return [String] a human-readable description of the matcher
113
+ # @example
114
+ # RaiseException.new(ArgumentError).to_s # => "raise exception ArgumentError"
51
115
  def to_s
52
116
  "raise exception #{@expected}"
53
117
  end
54
118
 
55
119
  private
56
120
 
57
- # Resolves the expected class name to an actual Class object.
58
- # This method handles both string and symbol class names through constant resolution.
121
+ # Resolves the expected class name to an actual Exception class.
122
+ #
123
+ # @api private
124
+ #
125
+ # @return [Class] The resolved exception class
126
+ # @raise [NameError] If the class name cannot be resolved to an actual class
59
127
  #
60
- # @return [Class] the resolved class
61
- # @raise [NameError] if the class doesn't exist
128
+ # @note This method handles both string and symbol class names through constant resolution
62
129
  def expected_class
63
130
  ::Object.const_get(@expected)
64
131
  end
@@ -1,43 +1,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Matchi
4
- # *Satisfy* matcher.
4
+ # Custom predicate matcher that validates values against an arbitrary condition.
5
+ #
6
+ # This matcher provides a flexible way to test values against custom conditions
7
+ # defined in a block. Unlike specific matchers that test for predetermined
8
+ # conditions, Satisfy allows you to define any custom validation logic at runtime.
9
+ # This makes it particularly useful for complex or composite conditions that
10
+ # aren't covered by other matchers.
11
+ #
12
+ # @example Basic numeric validation
13
+ # matcher = Matchi::Satisfy.new { |n| n.positive? && n.even? }
14
+ # matcher.match? { 2 } # => true
15
+ # matcher.match? { -2 } # => false
16
+ # matcher.match? { 3 } # => false
17
+ #
18
+ # @example String pattern validation
19
+ # matcher = Matchi::Satisfy.new { |s| s.start_with?("test") && s.length < 10 }
20
+ # matcher.match? { "test_123" } # => true
21
+ # matcher.match? { "test_12345" } # => false
22
+ # matcher.match? { "other" } # => false
23
+ #
24
+ # @example Complex object validation
25
+ # class User
26
+ # attr_reader :age, :name
27
+ # def initialize(name, age)
28
+ # @name, @age = name, age
29
+ # end
30
+ # end
31
+ #
32
+ # matcher = Matchi::Satisfy.new { |user|
33
+ # user.age >= 18 && user.name.length >= 2
34
+ # }
35
+ # matcher.match? { User.new("Alice", 25) } # => true
36
+ # matcher.match? { User.new("B", 20) } # => false
37
+ #
38
+ # @example Using with collections
39
+ # matcher = Matchi::Satisfy.new { |arr|
40
+ # arr.all? { |x| x.is_a?(Integer) } && arr.sum.even?
41
+ # }
42
+ # matcher.match? { [2, 4, 6] } # => true
43
+ # matcher.match? { [1, 3, 5] } # => false
44
+ # matcher.match? { [1, "2", 3] } # => false
45
+ #
46
+ # @see https://ruby-doc.org/core/Proc.html
47
+ # @see Matchi::Predicate For testing existing predicate methods
5
48
  class Satisfy
6
- # Initialize the matcher with a block.
49
+ # Initialize the matcher with a validation block.
7
50
  #
8
- # @example
9
- # require "matchi/satisfy"
51
+ # @api public
52
+ #
53
+ # @yield [Object] Block that defines the validation condition
54
+ # @yieldparam value The value to validate
55
+ # @yieldreturn [Boolean] true if the value meets the condition
56
+ #
57
+ # @raise [ArgumentError] if no block is provided
10
58
  #
11
- # Matchi::Satisfy.new { |value| value == 42 }
59
+ # @return [Satisfy] a new instance of the matcher
12
60
  #
13
- # @param block [Proc] A block of code.
61
+ # @example Simple numeric validation
62
+ # Satisfy.new { |n| n > 0 }
63
+ #
64
+ # @example Complex condition
65
+ # Satisfy.new { |obj|
66
+ # obj.respond_to?(:length) && obj.length.between?(2, 10)
67
+ # }
14
68
  def initialize(&block)
15
69
  raise ::ArgumentError, "a block must be provided" unless block_given?
16
70
 
17
71
  @expected = block
18
72
  end
19
73
 
20
- # Boolean comparison between the actual value and the expected value.
74
+ # Checks if the yielded value satisfies the validation block.
21
75
  #
22
- # @example
23
- # require "matchi/satisfy"
76
+ # This method passes the value returned by the provided block to the
77
+ # validation block defined at initialization. The matcher succeeds if
78
+ # the validation block returns a truthy value.
79
+ #
80
+ # @api public
24
81
  #
25
- # matcher = Matchi::Satisfy.new { |value| value == 42 }
26
- # matcher.match? { 42 } # => true
82
+ # @yield [] Block that returns the value to validate
83
+ # @yieldreturn [Object] The value to check against the condition
27
84
  #
28
- # @yieldreturn [#object_id] The actual value to compare to the expected
29
- # one.
85
+ # @return [Boolean] true if the value satisfies the condition
30
86
  #
31
- # @return [Boolean] Comparison between actual and expected values.
87
+ # @raise [ArgumentError] if no block is provided
88
+ #
89
+ # @example Using with direct values
90
+ # matcher = Satisfy.new { |n| n.positive? }
91
+ # matcher.match? { 42 } # => true
92
+ # matcher.match? { -1 } # => false
93
+ #
94
+ # @example Using with computed values
95
+ # matcher = Satisfy.new { |s| s.length.even? }
96
+ # matcher.match? { "test".upcase } # => true
97
+ # matcher.match? { "a" * 3 } # => false
32
98
  def match?
33
99
  raise ::ArgumentError, "a block must be provided" unless block_given?
34
100
 
35
101
  @expected.call(yield)
36
102
  end
37
103
 
38
- # Returns a string representing the matcher.
104
+ # Returns a human-readable description of the matcher.
105
+ #
106
+ # @api public
39
107
  #
40
- # @return [String] a human-readable description of the matcher
108
+ # @return [String] A string describing what this matcher verifies
109
+ #
110
+ # @example
111
+ # Satisfy.new { |n| n > 0 }.to_s # => "satisfy &block"
41
112
  def to_s
42
113
  "satisfy &block"
43
114
  end
data/lib/matchi.rb CHANGED
@@ -1,311 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # A collection of damn simple expectation matchers.
3
+ # Main namespace for the Matchi gem, providing a collection of expectation matchers.
4
4
  #
5
- # The Matchi module provides two ways to create and use matchers:
5
+ # Matchi is a framework-agnostic Ruby library that offers a comprehensive set of
6
+ # matchers for testing and verification purposes. Each matcher follows a consistent
7
+ # interface pattern, making them easy to use and extend.
6
8
  #
7
- # 1. Direct instantiation through classes:
8
- # ```ruby
9
- # matcher = Matchi::Eq.new("foo")
10
- # matcher.match? { "foo" } # => true
11
- # ```
9
+ # @example Basic usage with equality matcher
10
+ # Matchi::Eq.new("hello").match? { "hello" } # => true
11
+ # Matchi::Eq.new("hello").match? { "world" } # => false
12
12
  #
13
- # 2. Helper methods by including/extending the Matchi module:
14
- # ```ruby
15
- # # Via include in a class
16
- # class MyTestFramework
17
- # include Matchi
13
+ # @example Type checking with inheritance awareness
14
+ # Matchi::BeAKindOf.new(Numeric).match? { 42 } # => true
15
+ # Matchi::BeAKindOf.new(String).match? { 42 } # => false
18
16
  #
19
- # def test_something
20
- # # Helpers are now available as instance methods
21
- # matcher = eq("foo")
22
- # matcher.match? { "foo" } # => true
17
+ # @example Verifying state changes
18
+ # array = []
19
+ # Matchi::Change.new(array, :length).by(2).match? { array.push(1, 2) } # => true
23
20
  #
24
- # # Multiple helpers can be chained
25
- # change(@array, :length).by(1).match? { @array << 1 }
26
- # end
27
- # end
21
+ # @example Pattern matching with regular expressions
22
+ # Matchi::Match.new(/^test/).match? { "test_string" } # => true
28
23
  #
29
- # # Or via extend for direct usage
30
- # class MyOtherFramework
31
- # extend Matchi
24
+ # Each matcher in the Matchi ecosystem implements a consistent interface:
25
+ # - An initializer that sets up the expected values or conditions
26
+ # - A #match? method that takes a block and returns a boolean
27
+ # - An optional #to_s method that provides a human-readable description
32
28
  #
33
- # def self.assert_equals(expected, actual)
34
- # eq(expected).match? { actual }
35
- # end
36
- # end
37
- # ```
29
+ # @example Creating a custom matcher
30
+ # module Matchi
31
+ # class BePositive
32
+ # def match?
33
+ # raise ArgumentError, "a block must be provided" unless block_given?
34
+ # yield.positive?
35
+ # end
38
36
  #
39
- # The helper method approach provides a more readable and fluent interface,
40
- # making tests easier to write and understand. It's particularly useful when
41
- # integrating with testing frameworks or creating custom assertions.
37
+ # def to_s
38
+ # "be positive"
39
+ # end
40
+ # end
41
+ # end
42
42
  #
43
- # Available helpers include:
44
- # - eq/eql : Equivalence matching
45
- # - be/equal : Identity matching
46
- # - be_within : Delta comparison
47
- # - match : Regular expression matching
48
- # - change : State change verification
49
- # - be_true/be_false/be_nil : State verification
50
- # - be_an_instance_of : Exact type matching
51
- # - be_a_kind_of : Type hierarchy matching
52
- # - satisfy : Custom block-based matching
53
- # - be_* & have_* : Dynamic predicate matching
54
- #
55
- # @api public
43
+ # @see Matchi::Be
44
+ # @see Matchi::BeAKindOf
45
+ # @see Matchi::BeAnInstanceOf
46
+ # @see Matchi::BeWithin
47
+ # @see Matchi::Change
48
+ # @see Matchi::Eq
49
+ # @see Matchi::Match
50
+ # @see Matchi::Predicate
51
+ # @see Matchi::RaiseException
52
+ # @see Matchi::Satisfy
56
53
  module Matchi
57
- # Equivalence matcher
58
- #
59
- # @example
60
- # matcher = eq("foo")
61
- # matcher.match? { "foo" } # => true
62
- # matcher.match? { "bar" } # => false
63
- #
64
- # @param expected [#eql?] An expected equivalent object.
65
- #
66
- # @return [#match?] An equivalence matcher.
67
- #
68
- # @api public
69
- def eq(expected)
70
- ::Matchi::Eq.new(expected)
71
- end
72
-
73
- alias eql eq
74
-
75
- # Identity matcher
76
- #
77
- # @example
78
- # object = "foo"
79
- # matcher = be(object)
80
- # matcher.match? { object } # => true
81
- # matcher.match? { "foo" } # => false
82
- #
83
- # @param expected [#equal?] The expected identical object.
84
- #
85
- # @return [#match?] An identity matcher.
86
- #
87
- # @api public
88
- def be(expected)
89
- ::Matchi::Be.new(expected)
90
- end
91
-
92
- alias equal be
93
-
94
- # Comparisons matcher
95
- #
96
- # @example
97
- # matcher = be_within(1).of(41)
98
- # matcher.match? { 42 } # => true
99
- # matcher.match? { 43 } # => false
100
- #
101
- # @param delta [Numeric] A numeric value.
102
- #
103
- # @return [#match?] A comparison matcher.
104
- #
105
- # @api public
106
- def be_within(delta)
107
- ::Matchi::BeWithin.new(delta)
108
- end
109
-
110
- # Regular expressions matcher
111
- #
112
- # @example
113
- # matcher = match(/^foo$/)
114
- # matcher.match? { "foo" } # => true
115
- # matcher.match? { "bar" } # => false
116
- #
117
- # @param expected [#match] A regular expression.
118
- #
119
- # @return [#match?] A regular expression matcher.
120
- #
121
- # @api public
122
- def match(expected)
123
- ::Matchi::Match.new(expected)
124
- end
125
-
126
- # Expecting errors matcher
127
- #
128
- # @example
129
- # matcher = raise_exception(NameError)
130
- # matcher.match? { Boom } # => true
131
- # matcher.match? { true } # => false
132
- #
133
- # @param expected [Exception, #to_s] The expected exception name.
134
- #
135
- # @return [#match?] An error matcher.
136
- #
137
- # @api public
138
- def raise_exception(expected)
139
- ::Matchi::RaiseException.new(expected)
140
- end
141
-
142
- # True matcher
143
- #
144
- # @example
145
- # matcher = be_true
146
- # matcher.match? { true } # => true
147
- # matcher.match? { false } # => false
148
- # matcher.match? { nil } # => false
149
- # matcher.match? { 4 } # => false
150
- #
151
- # @return [#match?] A `true` matcher.
152
- #
153
- # @api public
154
- def be_true
155
- be(true)
156
- end
157
-
158
- # False matcher
159
- #
160
- # @example
161
- # matcher = be_false
162
- # matcher.match? { false } # => true
163
- # matcher.match? { true } # => false
164
- # matcher.match? { nil } # => false
165
- # matcher.match? { 4 } # => false
166
- #
167
- # @return [#match?] A `false` matcher.
168
- #
169
- # @api public
170
- def be_false
171
- be(false)
172
- end
173
-
174
- # Nil matcher
175
- #
176
- # @example
177
- # matcher = be_nil
178
- # matcher.match? { nil } # => true
179
- # matcher.match? { false } # => false
180
- # matcher.match? { true } # => false
181
- # matcher.match? { 4 } # => false
182
- #
183
- # @return [#match?] A `nil` matcher.
184
- #
185
- # @api public
186
- def be_nil
187
- be(nil)
188
- end
189
-
190
- # Type/class matcher
191
- #
192
- # Verifies exact class matching (no inheritance).
193
- #
194
- # @example
195
- # matcher = be_an_instance_of(String)
196
- # matcher.match? { "foo" } # => true
197
- # matcher.match? { 4 } # => false
198
- #
199
- # @param expected [Class, #to_s] The expected class name.
200
- #
201
- # @return [#match?] A type/class matcher.
202
- #
203
- # @api public
204
- def be_an_instance_of(expected)
205
- ::Matchi::BeAnInstanceOf.new(expected)
206
- end
207
-
208
- # Type/class matcher
209
- #
210
- # Verifies class inheritance and module inclusion.
211
- #
212
- # @example
213
- # matcher = be_a_kind_of(Numeric)
214
- # matcher.match? { 42 } # => true (Integer inherits from Numeric)
215
- # matcher.match? { 42.0 } # => true (Float inherits from Numeric)
216
- #
217
- # @param expected [Class, #to_s] The expected class name.
218
- #
219
- # @return [#match?] A type/class matcher.
220
- #
221
- # @api public
222
- def be_a_kind_of(expected)
223
- ::Matchi::BeAKindOf.new(expected)
224
- end
225
-
226
- # Change matcher
227
- #
228
- # @example
229
- # object = []
230
- # matcher = change(object, :length).by(1)
231
- # matcher.match? { object << 1 } # => true
232
- #
233
- # object = []
234
- # matcher = change(object, :length).by_at_least(1)
235
- # matcher.match? { object << 1 } # => true
236
- #
237
- # object = []
238
- # matcher = change(object, :length).by_at_most(1)
239
- # matcher.match? { object << 1 } # => true
240
- #
241
- # object = "foo"
242
- # matcher = change(object, :to_s).from("foo").to("FOO")
243
- # matcher.match? { object.upcase! } # => true
244
- #
245
- # object = "foo"
246
- # matcher = change(object, :to_s).to("FOO")
247
- # matcher.match? { object.upcase! } # => true
248
- #
249
- # @param object [#object_id] An object.
250
- # @param method [Symbol] The name of a method.
251
- #
252
- # @return [#match?] A change matcher.
253
- #
254
- # @api public
255
- def change(object, method, ...)
256
- ::Matchi::Change.new(object, method, ...)
257
- end
258
-
259
- # Satisfy matcher
260
- #
261
- # @example
262
- # matcher = satisfy { |value| value == 42 }
263
- # matcher.match? { 42 } # => true
264
- #
265
- # @yield [value] A block that defines the satisfaction criteria
266
- # @yieldparam value The value to test
267
- # @yieldreturn [Boolean] true if the value satisfies the criteria
268
- #
269
- # @return [#match?] A satisfy matcher.
270
- #
271
- # @api public
272
- def satisfy(&)
273
- ::Matchi::Satisfy.new(&)
274
- end
275
-
276
- private
277
-
278
- # Predicate matcher, or default method missing behavior.
279
- #
280
- # @example Empty predicate matcher
281
- # matcher = be_empty
282
- # matcher.match? { [] } # => true
283
- # matcher.match? { [4] } # => false
284
- def method_missing(name, ...)
285
- return super unless predicate_matcher_name?(name)
286
-
287
- ::Matchi::Predicate.new(name, ...)
288
- end
289
-
290
- # :nocov:
291
-
292
- # Hook method to return whether the obj can respond to id method or not.
293
- def respond_to_missing?(name, include_private = false)
294
- predicate_matcher_name?(name) || super
295
- end
296
-
297
- # :nocov:
298
-
299
- # Predicate matcher name detector.
300
- #
301
- # @param name [Array, Symbol] The name of a potential predicate matcher.
302
- #
303
- # @return [Boolean] Indicates if it is a predicate matcher name or not.
304
- def predicate_matcher_name?(name)
305
- name.start_with?("be_", "have_") && !name.end_with?("!", "?")
306
- end
307
54
  end
308
55
 
309
- Dir[File.join(File.dirname(__FILE__), "matchi", "*.rb")].each do |fname|
310
- require_relative fname
311
- end
56
+ require "matchi/be"
57
+ require "matchi/be_a_kind_of"
58
+ require "matchi/be_an_instance_of"
59
+ require "matchi/be_within"
60
+ require "matchi/change"
61
+ require "matchi/eq"
62
+ require "matchi/match"
63
+ require "matchi/predicate"
64
+ require "matchi/raise_exception"
65
+ require "matchi/satisfy"
metadata CHANGED
@@ -1,16 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matchi
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.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: 2024-12-31 00:00:00.000000000 Z
11
+ date: 2025-01-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: "Collection of expectation matchers for Rubyists \U0001F939"
13
+ description: 'Matchi is a framework-agnostic Ruby library that provides a comprehensive
14
+ set of expectation matchers for elegant and secure testing. Its design focuses on
15
+ simplicity, security, and extensibility, making it easy to integrate with any testing
16
+ framework. The library offers a rich collection of built-in matchers for common
17
+ testing scenarios while maintaining a clear, consistent API that follows Ruby best
18
+ practices. With minimal setup required and support for custom matchers, Matchi enables
19
+ developers to write more reliable and maintainable tests.
20
+
21
+ '
14
22
  email: contact@cyril.email
15
23
  executables: []
16
24
  extensions: []
@@ -23,7 +31,6 @@ files:
23
31
  - lib/matchi/be_a_kind_of.rb
24
32
  - lib/matchi/be_an_instance_of.rb
25
33
  - lib/matchi/be_within.rb
26
- - lib/matchi/be_within/of.rb
27
34
  - lib/matchi/change.rb
28
35
  - lib/matchi/change/by.rb
29
36
  - lib/matchi/change/by_at_least.rb
@@ -59,5 +66,5 @@ requirements: []
59
66
  rubygems_version: 3.3.27
60
67
  signing_key:
61
68
  specification_version: 4
62
- summary: "Collection of expectation matchers for Rubyists \U0001F939"
69
+ summary: "Framework-agnostic matchers for secure, elegant Ruby testing \U0001F939"
63
70
  test_files: []