matchers 0.1.0.pre.test

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.

Potentially problematic release.


This version of matchers might be problematic. Click here for more details.

Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/lib/matcher/assertions.rb +21 -0
  3. data/lib/matcher/base.rb +189 -0
  4. data/lib/matcher/builder.rb +74 -0
  5. data/lib/matcher/chain.rb +60 -0
  6. data/lib/matcher/debug.rb +48 -0
  7. data/lib/matcher/errors/and_error.rb +86 -0
  8. data/lib/matcher/errors/boolean_collector.rb +51 -0
  9. data/lib/matcher/errors/element_error.rb +24 -0
  10. data/lib/matcher/errors/empty_error.rb +23 -0
  11. data/lib/matcher/errors/error.rb +39 -0
  12. data/lib/matcher/errors/error_collector.rb +99 -0
  13. data/lib/matcher/errors/nested_error.rb +96 -0
  14. data/lib/matcher/errors/or_error.rb +86 -0
  15. data/lib/matcher/expression_cache.rb +57 -0
  16. data/lib/matcher/expression_labeler.rb +91 -0
  17. data/lib/matcher/expressions/array_expression.rb +45 -0
  18. data/lib/matcher/expressions/block.rb +153 -0
  19. data/lib/matcher/expressions/call.rb +338 -0
  20. data/lib/matcher/expressions/call_error.rb +45 -0
  21. data/lib/matcher/expressions/constant.rb +53 -0
  22. data/lib/matcher/expressions/expression.rb +147 -0
  23. data/lib/matcher/expressions/expression_building.rb +258 -0
  24. data/lib/matcher/expressions/expression_walker.rb +73 -0
  25. data/lib/matcher/expressions/hash_expression.rb +59 -0
  26. data/lib/matcher/expressions/proc_expression.rb +92 -0
  27. data/lib/matcher/expressions/range_expression.rb +58 -0
  28. data/lib/matcher/expressions/recorder.rb +86 -0
  29. data/lib/matcher/expressions/rescue_last_error_expression.rb +44 -0
  30. data/lib/matcher/expressions/set_expression.rb +45 -0
  31. data/lib/matcher/expressions/string_expression.rb +53 -0
  32. data/lib/matcher/expressions/symbol_proc.rb +53 -0
  33. data/lib/matcher/expressions/variable.rb +85 -0
  34. data/lib/matcher/hash_stack.rb +53 -0
  35. data/lib/matcher/list.rb +102 -0
  36. data/lib/matcher/markers/optional.rb +80 -0
  37. data/lib/matcher/markers/others.rb +28 -0
  38. data/lib/matcher/matcher_cache.rb +18 -0
  39. data/lib/matcher/matchers/all_matcher.rb +60 -0
  40. data/lib/matcher/matchers/always_matcher.rb +28 -0
  41. data/lib/matcher/matchers/any_matcher.rb +70 -0
  42. data/lib/matcher/matchers/array_matcher.rb +35 -0
  43. data/lib/matcher/matchers/block_matcher.rb +59 -0
  44. data/lib/matcher/matchers/boolean_matcher.rb +35 -0
  45. data/lib/matcher/matchers/dig_matcher.rb +146 -0
  46. data/lib/matcher/matchers/each_matcher.rb +52 -0
  47. data/lib/matcher/matchers/each_pair_matcher.rb +119 -0
  48. data/lib/matcher/matchers/equal_matcher.rb +197 -0
  49. data/lib/matcher/matchers/equal_set_matcher.rb +99 -0
  50. data/lib/matcher/matchers/expression_matcher.rb +73 -0
  51. data/lib/matcher/matchers/filter_matcher.rb +111 -0
  52. data/lib/matcher/matchers/hash_matcher.rb +223 -0
  53. data/lib/matcher/matchers/imply_matcher.rb +81 -0
  54. data/lib/matcher/matchers/imply_some_matcher.rb +112 -0
  55. data/lib/matcher/matchers/index_by_matcher.rb +175 -0
  56. data/lib/matcher/matchers/inline_matcher.rb +99 -0
  57. data/lib/matcher/matchers/keys_matcher.rb +121 -0
  58. data/lib/matcher/matchers/kind_of_matcher.rb +35 -0
  59. data/lib/matcher/matchers/lazy_all_matcher.rb +68 -0
  60. data/lib/matcher/matchers/lazy_any_matcher.rb +68 -0
  61. data/lib/matcher/matchers/let_matcher.rb +73 -0
  62. data/lib/matcher/matchers/map_matcher.rb +129 -0
  63. data/lib/matcher/matchers/matcher_building.rb +5 -0
  64. data/lib/matcher/matchers/negated_array_matcher.rb +38 -0
  65. data/lib/matcher/matchers/negated_each_matcher.rb +36 -0
  66. data/lib/matcher/matchers/negated_each_pair_matcher.rb +38 -0
  67. data/lib/matcher/matchers/negated_imply_some_matcher.rb +46 -0
  68. data/lib/matcher/matchers/negated_matcher.rb +23 -0
  69. data/lib/matcher/matchers/negated_project_matcher.rb +31 -0
  70. data/lib/matcher/matchers/never_matcher.rb +29 -0
  71. data/lib/matcher/matchers/one_matcher.rb +70 -0
  72. data/lib/matcher/matchers/optional_matcher.rb +38 -0
  73. data/lib/matcher/matchers/parse_float_matcher.rb +86 -0
  74. data/lib/matcher/matchers/parse_integer_matcher.rb +98 -0
  75. data/lib/matcher/matchers/parse_iso8601_matcher.rb +92 -0
  76. data/lib/matcher/matchers/parse_json_matcher.rb +95 -0
  77. data/lib/matcher/matchers/project_matcher.rb +68 -0
  78. data/lib/matcher/matchers/raises_matcher.rb +124 -0
  79. data/lib/matcher/matchers/range_matcher.rb +47 -0
  80. data/lib/matcher/matchers/reference_matcher.rb +111 -0
  81. data/lib/matcher/matchers/reference_matcher_collection.rb +57 -0
  82. data/lib/matcher/matchers/regexp_matcher.rb +84 -0
  83. data/lib/matcher/messages/expected_phrasing.rb +342 -0
  84. data/lib/matcher/messages/message.rb +102 -0
  85. data/lib/matcher/messages/message_builder.rb +35 -0
  86. data/lib/matcher/messages/message_rules.rb +223 -0
  87. data/lib/matcher/messages/namespaced_message_builder.rb +19 -0
  88. data/lib/matcher/messages/phrasing.rb +57 -0
  89. data/lib/matcher/messages/standard_message_builder.rb +105 -0
  90. data/lib/matcher/once_before.rb +18 -0
  91. data/lib/matcher/optional_chain.rb +24 -0
  92. data/lib/matcher/patterns/ast_mapping.rb +42 -0
  93. data/lib/matcher/patterns/capture_hole.rb +33 -0
  94. data/lib/matcher/patterns/constant_hole.rb +14 -0
  95. data/lib/matcher/patterns/hole.rb +30 -0
  96. data/lib/matcher/patterns/method_hole.rb +58 -0
  97. data/lib/matcher/patterns/pattern.rb +92 -0
  98. data/lib/matcher/patterns/pattern_building.rb +39 -0
  99. data/lib/matcher/patterns/pattern_capture.rb +11 -0
  100. data/lib/matcher/patterns/pattern_match.rb +29 -0
  101. data/lib/matcher/patterns/variable_hole.rb +14 -0
  102. data/lib/matcher/reporter.rb +98 -0
  103. data/lib/matcher/rules/message_factory.rb +25 -0
  104. data/lib/matcher/rules/message_rule.rb +18 -0
  105. data/lib/matcher/rules/message_rule_context.rb +24 -0
  106. data/lib/matcher/rules/rule_builder.rb +29 -0
  107. data/lib/matcher/rules/rule_set.rb +57 -0
  108. data/lib/matcher/rules/transform_builder.rb +24 -0
  109. data/lib/matcher/rules/transform_mapping.rb +5 -0
  110. data/lib/matcher/rules/transform_rule.rb +21 -0
  111. data/lib/matcher/state.rb +40 -0
  112. data/lib/matcher/testing/error_builder.rb +62 -0
  113. data/lib/matcher/testing/error_checker.rb +496 -0
  114. data/lib/matcher/testing/error_testing.rb +37 -0
  115. data/lib/matcher/testing/pattern_testing.rb +11 -0
  116. data/lib/matcher/testing/pattern_testing_scope.rb +34 -0
  117. data/lib/matcher/testing.rb +102 -0
  118. data/lib/matcher/undefined.rb +10 -0
  119. data/lib/matcher/utils/mapping_utils.rb +61 -0
  120. data/lib/matcher/utils.rb +72 -0
  121. data/lib/matcher/version.rb +5 -0
  122. data/lib/matcher.rb +337 -0
  123. metadata +167 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Matcher
4
+ module MappingUtils
5
+ def unary_call?(expression)
6
+ expression.unary? && expression.receiver == Variable.actual
7
+ end
8
+
9
+ def index_call?(expression)
10
+ expression.binary? &&
11
+ expression.receiver == Variable.actual &&
12
+ expression.args[0].is_a?(Constant)
13
+ end
14
+
15
+ def operand_of(expression)
16
+ expression.args[0].value
17
+ end
18
+
19
+ def index_call_to(operand)
20
+ Call.new(Variable.actual, :[], [Constant.new(operand)])
21
+ end
22
+
23
+ def map_errors(error, &)
24
+ case error
25
+ when EmptyError
26
+ error
27
+ when AndError, OrError
28
+ children = error.children.map { map_errors(_1, &) }
29
+ error.class.new(children)
30
+ when NestedError
31
+ yield(error) || error
32
+ when ElementError
33
+ NestedError.new(mapped_base, error)
34
+ else
35
+ raise "Unexpected error: #{error.inspect}"
36
+ end
37
+ end
38
+
39
+ def map_base(method, expression)
40
+ with_index = expression.variables.include?(:index)
41
+
42
+ block = if unary_call?(expression)
43
+ SymbolProc.new(expression.method)
44
+ else
45
+ element = expression.free_symbol(:e)
46
+ parameters = [[:opt, element]]
47
+ parameters << %i[opt index] if with_index
48
+ substituted = expression.substitute(actual: element, original: :actual)
49
+
50
+ Block.new(parameters, substituted)
51
+ end
52
+
53
+ if with_index
54
+ enum_for = Call.new(Variable.actual, method)
55
+ Call.new(enum_for, :with_index, [], {}, block)
56
+ else
57
+ Call.new(Variable.actual, method, [], {}, block)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Matcher
4
+ module Utils
5
+ def self.to_string(obj)
6
+ case obj
7
+ when Hash
8
+ return '{}' if obj.empty?
9
+
10
+ body = obj.map do |k, v|
11
+ if k.is_a?(Symbol)
12
+ "#{k}: #{to_string(v)}"
13
+ else
14
+ "#{k.inspect} => #{to_string(v)}"
15
+ end
16
+ end
17
+
18
+ "{ #{body.join(', ')} }"
19
+ when Array
20
+ "[#{obj.map { |v| to_string(v) }.join(', ')}]"
21
+ else
22
+ obj.inspect
23
+ end
24
+ end
25
+
26
+ def self.call_block(block, values, parameters: block.parameters)
27
+ args = []
28
+ kwargs = {}
29
+
30
+ parameters.each do |type, name|
31
+ case type
32
+ when :req, :opt, :rest
33
+ args << values[:actual] if args.length == 0
34
+ when :keyreq
35
+ kwargs[name] = values[name]
36
+ when :key
37
+ value = values[name]
38
+ kwargs[name] = value if !value.nil? || values.key?(name)
39
+ when :keyrest
40
+ kwargs.merge!(values.except(*kwargs.keys))
41
+ end
42
+ end
43
+
44
+ block.call(*args, **kwargs)
45
+ end
46
+
47
+ def self.inspect_block_params(block)
48
+ arg_names = []
49
+ kwarg_names = []
50
+
51
+ block.parameters.each do |type, name|
52
+ case type
53
+ when :req, :opt, :rest
54
+ arg_names << name
55
+ when :keyreq, :key, :keyrest
56
+ kwarg_names << name
57
+ end
58
+ end
59
+
60
+ arg_parts = arg_names.all? { _1.match?(/^_[1-9]$/) } ? [] : arg_names
61
+ kwarg_parts = kwarg_names.map { "#{_1}:"}
62
+
63
+ (arg_parts + kwarg_parts).join(', ')
64
+ end
65
+
66
+ def self.block_location(block)
67
+ file, line = block.source_location
68
+
69
+ "#{File.basename(file)}:#{line}"
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Matcher
4
+ VERSION = "0.1.0.pre.test"
5
+ end
data/lib/matcher.rb ADDED
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "matcher/version"
4
+
5
+ require 'singleton'
6
+ require 'forwardable'
7
+
8
+ module Matcher
9
+ module NoMatcher end
10
+ module NoExpression end
11
+ module NoKey end
12
+ end
13
+
14
+ require_relative 'matcher/once_before'
15
+ require_relative 'matcher/expressions/expression_building'
16
+ require_relative 'matcher/matchers/matcher_building'
17
+ require_relative 'matcher/patterns/pattern_building'
18
+ require_relative 'matcher/utils/mapping_utils'
19
+
20
+ require_relative 'matcher/assertions'
21
+ require_relative 'matcher/base'
22
+ require_relative 'matcher/builder'
23
+ require_relative 'matcher/debug'
24
+ require_relative 'matcher/expression_labeler'
25
+ require_relative 'matcher/expression_cache'
26
+ require_relative 'matcher/hash_stack'
27
+ require_relative 'matcher/list'
28
+ require_relative 'matcher/matcher_cache'
29
+ require_relative 'matcher/optional_chain'
30
+ require_relative 'matcher/chain'
31
+ require_relative 'matcher/reporter'
32
+ require_relative 'matcher/state'
33
+ require_relative 'matcher/undefined'
34
+ require_relative 'matcher/utils'
35
+
36
+ require_relative 'matcher/errors/error'
37
+ require_relative 'matcher/errors/and_error'
38
+ require_relative 'matcher/errors/element_error'
39
+ require_relative 'matcher/errors/empty_error'
40
+ require_relative 'matcher/errors/error_collector'
41
+ require_relative 'matcher/errors/nested_error'
42
+ require_relative 'matcher/errors/or_error'
43
+ require_relative 'matcher/errors/boolean_collector'
44
+
45
+ require_relative 'matcher/expressions/expression'
46
+ require_relative 'matcher/expressions/array_expression'
47
+ require_relative 'matcher/expressions/block'
48
+ require_relative 'matcher/expressions/call'
49
+ require_relative 'matcher/expressions/call_error'
50
+ require_relative 'matcher/expressions/constant'
51
+ require_relative 'matcher/expressions/expression_walker'
52
+ require_relative 'matcher/expressions/hash_expression'
53
+ require_relative 'matcher/expressions/proc_expression'
54
+ require_relative 'matcher/expressions/range_expression'
55
+ require_relative 'matcher/expressions/recorder'
56
+ require_relative 'matcher/expressions/rescue_last_error_expression'
57
+ require_relative 'matcher/expressions/set_expression'
58
+ require_relative 'matcher/expressions/string_expression'
59
+ require_relative 'matcher/expressions/symbol_proc'
60
+ require_relative 'matcher/expressions/variable'
61
+
62
+ require_relative 'matcher/markers/optional'
63
+ require_relative 'matcher/markers/others'
64
+
65
+ require_relative 'matcher/matchers/all_matcher'
66
+ require_relative 'matcher/matchers/always_matcher'
67
+ require_relative 'matcher/matchers/any_matcher'
68
+ require_relative 'matcher/matchers/array_matcher'
69
+ require_relative 'matcher/matchers/block_matcher'
70
+ require_relative 'matcher/matchers/boolean_matcher'
71
+ require_relative 'matcher/matchers/dig_matcher'
72
+ require_relative 'matcher/matchers/each_matcher'
73
+ require_relative 'matcher/matchers/each_pair_matcher'
74
+ require_relative 'matcher/matchers/equal_matcher'
75
+ require_relative 'matcher/matchers/equal_set_matcher'
76
+ require_relative 'matcher/matchers/expression_matcher'
77
+ require_relative 'matcher/matchers/filter_matcher'
78
+ require_relative 'matcher/matchers/hash_matcher'
79
+ require_relative 'matcher/matchers/index_by_matcher'
80
+ require_relative 'matcher/matchers/inline_matcher'
81
+ require_relative 'matcher/matchers/imply_matcher'
82
+ require_relative 'matcher/matchers/imply_some_matcher'
83
+ require_relative 'matcher/matchers/keys_matcher'
84
+ require_relative 'matcher/matchers/kind_of_matcher'
85
+ require_relative 'matcher/matchers/lazy_all_matcher'
86
+ require_relative 'matcher/matchers/lazy_any_matcher'
87
+ require_relative 'matcher/matchers/let_matcher'
88
+ require_relative 'matcher/matchers/map_matcher'
89
+ require_relative 'matcher/matchers/negated_array_matcher'
90
+ require_relative 'matcher/matchers/negated_each_matcher'
91
+ require_relative 'matcher/matchers/negated_each_pair_matcher'
92
+ require_relative 'matcher/matchers/negated_imply_some_matcher'
93
+ require_relative 'matcher/matchers/negated_matcher'
94
+ require_relative 'matcher/matchers/negated_project_matcher'
95
+ require_relative 'matcher/matchers/never_matcher'
96
+ require_relative 'matcher/matchers/one_matcher'
97
+ require_relative 'matcher/matchers/optional_matcher'
98
+ require_relative 'matcher/matchers/parse_float_matcher'
99
+ require_relative 'matcher/matchers/parse_integer_matcher'
100
+ require_relative 'matcher/matchers/parse_iso8601_matcher'
101
+ require_relative 'matcher/matchers/parse_json_matcher'
102
+ require_relative 'matcher/matchers/project_matcher'
103
+ require_relative 'matcher/matchers/raises_matcher'
104
+ require_relative 'matcher/matchers/range_matcher'
105
+ require_relative 'matcher/matchers/reference_matcher'
106
+ require_relative 'matcher/matchers/reference_matcher_collection'
107
+ require_relative 'matcher/matchers/regexp_matcher'
108
+
109
+ require_relative 'matcher/messages/phrasing'
110
+ require_relative 'matcher/messages/message_builder'
111
+ require_relative 'matcher/messages/expected_phrasing'
112
+ require_relative 'matcher/messages/message'
113
+ require_relative 'matcher/messages/namespaced_message_builder'
114
+ require_relative 'matcher/messages/standard_message_builder'
115
+
116
+ require_relative 'matcher/patterns/hole'
117
+ require_relative 'matcher/patterns/ast_mapping'
118
+ require_relative 'matcher/patterns/capture_hole'
119
+ require_relative 'matcher/patterns/constant_hole'
120
+ require_relative 'matcher/patterns/method_hole'
121
+ require_relative 'matcher/patterns/pattern'
122
+ require_relative 'matcher/patterns/pattern_capture'
123
+ require_relative 'matcher/patterns/pattern_match'
124
+ require_relative 'matcher/patterns/variable_hole'
125
+
126
+ require_relative 'matcher/rules/message_factory'
127
+ require_relative 'matcher/rules/message_rule'
128
+ require_relative 'matcher/rules/message_rule_context'
129
+ require_relative 'matcher/rules/rule_builder'
130
+ require_relative 'matcher/rules/rule_set'
131
+ require_relative 'matcher/rules/transform_builder'
132
+ require_relative 'matcher/rules/transform_mapping'
133
+ require_relative 'matcher/rules/transform_rule'
134
+
135
+ require_relative 'matcher/testing/error_builder'
136
+ require_relative 'matcher/testing/error_checker'
137
+ require_relative 'matcher/testing/error_testing'
138
+ require_relative 'matcher/testing/pattern_testing'
139
+ require_relative 'matcher/testing/pattern_testing_scope'
140
+
141
+ module Matcher
142
+ UNDEFINED = Undefined.instance
143
+
144
+ def self.undefined?(object)
145
+ # Note that for an ExpressionRecorder object == UNDEFINED won't work.
146
+ UNDEFINED == object
147
+ end
148
+
149
+ ##
150
+ # Builds a matcher from a block
151
+ #
152
+ # Inside the block all matcher and expression building helpers are available.
153
+ # The return value of the block is converted to a matcher via +Matcher.of+.
154
+ # @example
155
+ # m = Matcher.build do
156
+ # { name: String, count: 1..10 }
157
+ # end
158
+ # m.match?({ name: 'test', count: 5 }) # => true
159
+ # @return [Base]
160
+ # @see Matcher.of
161
+ def self.build(&block)
162
+ with_build_session do |build_session|
163
+ builder = Builder.new(block.binding.receiver, build_session:)
164
+ object = builder.instance_exec(&block)
165
+ builder.refs.finalize
166
+
167
+ matcher = if builder.refs? && builder.refs.last_object_id == object.__id__
168
+ builder.refs.last_matcher
169
+ else
170
+ builder.matcher_of(object)
171
+ end
172
+
173
+ if (assigns = builder.assigns)
174
+ LetMatcher.new(assigns, matcher)
175
+ else
176
+ matcher
177
+ end
178
+ end
179
+ end
180
+
181
+ def self.max_reference_depth
182
+ @max_reference_depth ||= 100
183
+ end
184
+
185
+ def self.max_reference_depth=(value)
186
+ @max_reference_depth = value
187
+ end
188
+
189
+ ##
190
+ # Converts a value into a matcher
191
+ #
192
+ # The conversion depends on the type of the value:
193
+ # - +Module+/+Class+ -> KindOfMatcher
194
+ # - +Range+ -> RangeMatcher
195
+ # - +Regexp+ -> RegexpMatcher
196
+ # - +Hash+ -> HashMatcher
197
+ # - +Array+ -> ArrayMatcher
198
+ # - +Expression+ -> ExpressionMatcher
199
+ # - +Proc+ -> BlockMatcher
200
+ # - +Optional+ -> OptionalMatcher
201
+ # - other -> EqualMatcher
202
+ # @example
203
+ # Matcher.of(String).class # => Matcher::KindOfMatcher
204
+ # Matcher.of(1..10).class # => Matcher::RangeMatcher
205
+ # Matcher.of(/foo/).class # => Matcher::RegexpMatcher
206
+ # @param object the value to convert
207
+ # @return [Base]
208
+ def self.of(object, matcher_cache: nil, expression_cache: nil)
209
+ object = Expression.try_recorder(object)
210
+
211
+ case object
212
+ when NoMatcher
213
+ raise ArgumentError, "Cannot use #{object.class} as matcher"
214
+ when Module
215
+ KindOfMatcher.cache(object, matcher_cache)
216
+ when OptionalChain
217
+ object.fallback
218
+ when Base
219
+ object
220
+ when Expression
221
+ ExpressionMatcher.cache(object, matcher_cache, expression_cache)
222
+ when Proc
223
+ BlockMatcher.new(object)
224
+ when Range
225
+ RangeMatcher.cache(object, matcher_cache)
226
+ when Regexp
227
+ RegexpMatcher.cache(object, matcher_cache)
228
+ when Hash
229
+ hash = object.to_h do |k, v|
230
+ case k
231
+ when -> { Recorder.recorder?(_1) }
232
+ k = Recorder.to_expression(k)
233
+ when Optional
234
+ k = Optional.cache(k.value, matcher_cache)
235
+ when Base
236
+ raise 'Cannot use matcher as key for hash matcher'
237
+ when NoKey
238
+ raise "Cannot use #{k.class} as key for hash matcher"
239
+ when Others
240
+ # keep k
241
+ else
242
+ k = Expression.expression_or_value(k)
243
+ end
244
+
245
+ [k, of(v, matcher_cache:, expression_cache:)]
246
+ end
247
+
248
+ HashMatcher.new(hash)
249
+ when Array
250
+ ArrayMatcher.new(object.map { of(_1, matcher_cache:, expression_cache:) })
251
+ when Optional
252
+ matcher = of(object.value, matcher_cache:, expression_cache:)
253
+
254
+ OptionalMatcher.cache(matcher, matcher_cache)
255
+ else
256
+ EqualMatcher.cache(object, matcher_cache)
257
+ end
258
+ end
259
+
260
+ def self.cache(object)
261
+ build_session = Matcher.build_session
262
+ matcher_cache = MatcherCache.current(build_session)
263
+ expression_cache = ExpressionCache.current(build_session)
264
+
265
+ of(object, matcher_cache:, expression_cache:)
266
+ end
267
+
268
+ def self.parenthesize(matcher)
269
+ matcher_to_s = matcher.to_s
270
+
271
+ matcher_to_s = "(#{matcher_to_s})" if
272
+ case matcher
273
+ when ExpressionMatcher
274
+ !matcher.negated && matcher.expression.precedence > Call::OPERATOR_PRECEDENCE[:^]
275
+ when EqualMatcher, KindOfMatcher, RangeMatcher, RegexpMatcher, ArrayMatcher, HashMatcher
276
+ false
277
+ else
278
+ matcher_to_s !~ /\A(~?\w+(\(.*\)|\[.*\])?|-> \{.*})\z/
279
+ end
280
+
281
+ matcher_to_s
282
+ end
283
+
284
+ def self.settings
285
+ Thread.current[:matcher_settings_stack] || {}
286
+ end
287
+
288
+ def self.with_settings(**settings)
289
+ stack = (Thread.current[:matcher_settings_stack] ||= HashStack.new)
290
+ stack.push(settings)
291
+
292
+ begin
293
+ yield
294
+ ensure
295
+ stack.pop(settings)
296
+ Thread.current[:matcher_settings_stack] = nil if stack.empty?
297
+ end
298
+ end
299
+
300
+ def self.session
301
+ Thread.current[:matcher_session]
302
+ end
303
+
304
+ def self.with_session(initial = {})
305
+ return yield if Thread.current[:matcher_session]
306
+
307
+ begin
308
+ Thread.current[:matcher_session] = initial
309
+
310
+ yield
311
+ ensure
312
+ Thread.current[:matcher_session] = nil
313
+ end
314
+ end
315
+
316
+ def self.build_session
317
+ Thread.current[:matcher_build_session]
318
+ end
319
+
320
+ def self.with_build_session(initial = {})
321
+ build_session = Thread.current[:matcher_build_session]
322
+
323
+ return yield build_session if build_session
324
+
325
+ begin
326
+ Thread.current[:matcher_build_session] = initial
327
+
328
+ yield initial
329
+ ensure
330
+ Thread.current[:matcher_build_session] = nil
331
+ end
332
+ end
333
+
334
+ Debug.init
335
+ end
336
+
337
+ require_relative 'matcher/messages/message_rules'
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: matchers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.test
5
+ platform: ruby
6
+ authors:
7
+ - Rico Jasper
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - jasper.rico@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/matcher.rb
21
+ - lib/matcher/assertions.rb
22
+ - lib/matcher/base.rb
23
+ - lib/matcher/builder.rb
24
+ - lib/matcher/chain.rb
25
+ - lib/matcher/debug.rb
26
+ - lib/matcher/errors/and_error.rb
27
+ - lib/matcher/errors/boolean_collector.rb
28
+ - lib/matcher/errors/element_error.rb
29
+ - lib/matcher/errors/empty_error.rb
30
+ - lib/matcher/errors/error.rb
31
+ - lib/matcher/errors/error_collector.rb
32
+ - lib/matcher/errors/nested_error.rb
33
+ - lib/matcher/errors/or_error.rb
34
+ - lib/matcher/expression_cache.rb
35
+ - lib/matcher/expression_labeler.rb
36
+ - lib/matcher/expressions/array_expression.rb
37
+ - lib/matcher/expressions/block.rb
38
+ - lib/matcher/expressions/call.rb
39
+ - lib/matcher/expressions/call_error.rb
40
+ - lib/matcher/expressions/constant.rb
41
+ - lib/matcher/expressions/expression.rb
42
+ - lib/matcher/expressions/expression_building.rb
43
+ - lib/matcher/expressions/expression_walker.rb
44
+ - lib/matcher/expressions/hash_expression.rb
45
+ - lib/matcher/expressions/proc_expression.rb
46
+ - lib/matcher/expressions/range_expression.rb
47
+ - lib/matcher/expressions/recorder.rb
48
+ - lib/matcher/expressions/rescue_last_error_expression.rb
49
+ - lib/matcher/expressions/set_expression.rb
50
+ - lib/matcher/expressions/string_expression.rb
51
+ - lib/matcher/expressions/symbol_proc.rb
52
+ - lib/matcher/expressions/variable.rb
53
+ - lib/matcher/hash_stack.rb
54
+ - lib/matcher/list.rb
55
+ - lib/matcher/markers/optional.rb
56
+ - lib/matcher/markers/others.rb
57
+ - lib/matcher/matcher_cache.rb
58
+ - lib/matcher/matchers/all_matcher.rb
59
+ - lib/matcher/matchers/always_matcher.rb
60
+ - lib/matcher/matchers/any_matcher.rb
61
+ - lib/matcher/matchers/array_matcher.rb
62
+ - lib/matcher/matchers/block_matcher.rb
63
+ - lib/matcher/matchers/boolean_matcher.rb
64
+ - lib/matcher/matchers/dig_matcher.rb
65
+ - lib/matcher/matchers/each_matcher.rb
66
+ - lib/matcher/matchers/each_pair_matcher.rb
67
+ - lib/matcher/matchers/equal_matcher.rb
68
+ - lib/matcher/matchers/equal_set_matcher.rb
69
+ - lib/matcher/matchers/expression_matcher.rb
70
+ - lib/matcher/matchers/filter_matcher.rb
71
+ - lib/matcher/matchers/hash_matcher.rb
72
+ - lib/matcher/matchers/imply_matcher.rb
73
+ - lib/matcher/matchers/imply_some_matcher.rb
74
+ - lib/matcher/matchers/index_by_matcher.rb
75
+ - lib/matcher/matchers/inline_matcher.rb
76
+ - lib/matcher/matchers/keys_matcher.rb
77
+ - lib/matcher/matchers/kind_of_matcher.rb
78
+ - lib/matcher/matchers/lazy_all_matcher.rb
79
+ - lib/matcher/matchers/lazy_any_matcher.rb
80
+ - lib/matcher/matchers/let_matcher.rb
81
+ - lib/matcher/matchers/map_matcher.rb
82
+ - lib/matcher/matchers/matcher_building.rb
83
+ - lib/matcher/matchers/negated_array_matcher.rb
84
+ - lib/matcher/matchers/negated_each_matcher.rb
85
+ - lib/matcher/matchers/negated_each_pair_matcher.rb
86
+ - lib/matcher/matchers/negated_imply_some_matcher.rb
87
+ - lib/matcher/matchers/negated_matcher.rb
88
+ - lib/matcher/matchers/negated_project_matcher.rb
89
+ - lib/matcher/matchers/never_matcher.rb
90
+ - lib/matcher/matchers/one_matcher.rb
91
+ - lib/matcher/matchers/optional_matcher.rb
92
+ - lib/matcher/matchers/parse_float_matcher.rb
93
+ - lib/matcher/matchers/parse_integer_matcher.rb
94
+ - lib/matcher/matchers/parse_iso8601_matcher.rb
95
+ - lib/matcher/matchers/parse_json_matcher.rb
96
+ - lib/matcher/matchers/project_matcher.rb
97
+ - lib/matcher/matchers/raises_matcher.rb
98
+ - lib/matcher/matchers/range_matcher.rb
99
+ - lib/matcher/matchers/reference_matcher.rb
100
+ - lib/matcher/matchers/reference_matcher_collection.rb
101
+ - lib/matcher/matchers/regexp_matcher.rb
102
+ - lib/matcher/messages/expected_phrasing.rb
103
+ - lib/matcher/messages/message.rb
104
+ - lib/matcher/messages/message_builder.rb
105
+ - lib/matcher/messages/message_rules.rb
106
+ - lib/matcher/messages/namespaced_message_builder.rb
107
+ - lib/matcher/messages/phrasing.rb
108
+ - lib/matcher/messages/standard_message_builder.rb
109
+ - lib/matcher/once_before.rb
110
+ - lib/matcher/optional_chain.rb
111
+ - lib/matcher/patterns/ast_mapping.rb
112
+ - lib/matcher/patterns/capture_hole.rb
113
+ - lib/matcher/patterns/constant_hole.rb
114
+ - lib/matcher/patterns/hole.rb
115
+ - lib/matcher/patterns/method_hole.rb
116
+ - lib/matcher/patterns/pattern.rb
117
+ - lib/matcher/patterns/pattern_building.rb
118
+ - lib/matcher/patterns/pattern_capture.rb
119
+ - lib/matcher/patterns/pattern_match.rb
120
+ - lib/matcher/patterns/variable_hole.rb
121
+ - lib/matcher/reporter.rb
122
+ - lib/matcher/rules/message_factory.rb
123
+ - lib/matcher/rules/message_rule.rb
124
+ - lib/matcher/rules/message_rule_context.rb
125
+ - lib/matcher/rules/rule_builder.rb
126
+ - lib/matcher/rules/rule_set.rb
127
+ - lib/matcher/rules/transform_builder.rb
128
+ - lib/matcher/rules/transform_mapping.rb
129
+ - lib/matcher/rules/transform_rule.rb
130
+ - lib/matcher/state.rb
131
+ - lib/matcher/testing.rb
132
+ - lib/matcher/testing/error_builder.rb
133
+ - lib/matcher/testing/error_checker.rb
134
+ - lib/matcher/testing/error_testing.rb
135
+ - lib/matcher/testing/pattern_testing.rb
136
+ - lib/matcher/testing/pattern_testing_scope.rb
137
+ - lib/matcher/undefined.rb
138
+ - lib/matcher/utils.rb
139
+ - lib/matcher/utils/mapping_utils.rb
140
+ - lib/matcher/version.rb
141
+ homepage: https://github.com/rjasper/ruby-matcher
142
+ licenses:
143
+ - MIT
144
+ metadata:
145
+ homepage_uri: https://github.com/rjasper/ruby-matcher
146
+ source_code_uri: https://github.com/rjasper/ruby-matcher
147
+ changelog_uri: https://github.com/rjasper/ruby-matcher/blob/master/CHANGELOG.md
148
+ post_install_message:
149
+ rdoc_options: []
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: 2.6.0
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ requirements: []
163
+ rubygems_version: 3.5.11
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: A matcher library.
167
+ test_files: []