matchi 4.1.1 → 4.2.0

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