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.
- checksums.yaml +7 -0
- data/lib/matcher/assertions.rb +21 -0
- data/lib/matcher/base.rb +189 -0
- data/lib/matcher/builder.rb +74 -0
- data/lib/matcher/chain.rb +60 -0
- data/lib/matcher/debug.rb +48 -0
- data/lib/matcher/errors/and_error.rb +86 -0
- data/lib/matcher/errors/boolean_collector.rb +51 -0
- data/lib/matcher/errors/element_error.rb +24 -0
- data/lib/matcher/errors/empty_error.rb +23 -0
- data/lib/matcher/errors/error.rb +39 -0
- data/lib/matcher/errors/error_collector.rb +99 -0
- data/lib/matcher/errors/nested_error.rb +96 -0
- data/lib/matcher/errors/or_error.rb +86 -0
- data/lib/matcher/expression_cache.rb +57 -0
- data/lib/matcher/expression_labeler.rb +91 -0
- data/lib/matcher/expressions/array_expression.rb +45 -0
- data/lib/matcher/expressions/block.rb +153 -0
- data/lib/matcher/expressions/call.rb +338 -0
- data/lib/matcher/expressions/call_error.rb +45 -0
- data/lib/matcher/expressions/constant.rb +53 -0
- data/lib/matcher/expressions/expression.rb +147 -0
- data/lib/matcher/expressions/expression_building.rb +258 -0
- data/lib/matcher/expressions/expression_walker.rb +73 -0
- data/lib/matcher/expressions/hash_expression.rb +59 -0
- data/lib/matcher/expressions/proc_expression.rb +92 -0
- data/lib/matcher/expressions/range_expression.rb +58 -0
- data/lib/matcher/expressions/recorder.rb +86 -0
- data/lib/matcher/expressions/rescue_last_error_expression.rb +44 -0
- data/lib/matcher/expressions/set_expression.rb +45 -0
- data/lib/matcher/expressions/string_expression.rb +53 -0
- data/lib/matcher/expressions/symbol_proc.rb +53 -0
- data/lib/matcher/expressions/variable.rb +85 -0
- data/lib/matcher/hash_stack.rb +53 -0
- data/lib/matcher/list.rb +102 -0
- data/lib/matcher/markers/optional.rb +80 -0
- data/lib/matcher/markers/others.rb +28 -0
- data/lib/matcher/matcher_cache.rb +18 -0
- data/lib/matcher/matchers/all_matcher.rb +60 -0
- data/lib/matcher/matchers/always_matcher.rb +28 -0
- data/lib/matcher/matchers/any_matcher.rb +70 -0
- data/lib/matcher/matchers/array_matcher.rb +35 -0
- data/lib/matcher/matchers/block_matcher.rb +59 -0
- data/lib/matcher/matchers/boolean_matcher.rb +35 -0
- data/lib/matcher/matchers/dig_matcher.rb +146 -0
- data/lib/matcher/matchers/each_matcher.rb +52 -0
- data/lib/matcher/matchers/each_pair_matcher.rb +119 -0
- data/lib/matcher/matchers/equal_matcher.rb +197 -0
- data/lib/matcher/matchers/equal_set_matcher.rb +99 -0
- data/lib/matcher/matchers/expression_matcher.rb +73 -0
- data/lib/matcher/matchers/filter_matcher.rb +111 -0
- data/lib/matcher/matchers/hash_matcher.rb +223 -0
- data/lib/matcher/matchers/imply_matcher.rb +81 -0
- data/lib/matcher/matchers/imply_some_matcher.rb +112 -0
- data/lib/matcher/matchers/index_by_matcher.rb +175 -0
- data/lib/matcher/matchers/inline_matcher.rb +99 -0
- data/lib/matcher/matchers/keys_matcher.rb +121 -0
- data/lib/matcher/matchers/kind_of_matcher.rb +35 -0
- data/lib/matcher/matchers/lazy_all_matcher.rb +68 -0
- data/lib/matcher/matchers/lazy_any_matcher.rb +68 -0
- data/lib/matcher/matchers/let_matcher.rb +73 -0
- data/lib/matcher/matchers/map_matcher.rb +129 -0
- data/lib/matcher/matchers/matcher_building.rb +5 -0
- data/lib/matcher/matchers/negated_array_matcher.rb +38 -0
- data/lib/matcher/matchers/negated_each_matcher.rb +36 -0
- data/lib/matcher/matchers/negated_each_pair_matcher.rb +38 -0
- data/lib/matcher/matchers/negated_imply_some_matcher.rb +46 -0
- data/lib/matcher/matchers/negated_matcher.rb +23 -0
- data/lib/matcher/matchers/negated_project_matcher.rb +31 -0
- data/lib/matcher/matchers/never_matcher.rb +29 -0
- data/lib/matcher/matchers/one_matcher.rb +70 -0
- data/lib/matcher/matchers/optional_matcher.rb +38 -0
- data/lib/matcher/matchers/parse_float_matcher.rb +86 -0
- data/lib/matcher/matchers/parse_integer_matcher.rb +98 -0
- data/lib/matcher/matchers/parse_iso8601_matcher.rb +92 -0
- data/lib/matcher/matchers/parse_json_matcher.rb +95 -0
- data/lib/matcher/matchers/project_matcher.rb +68 -0
- data/lib/matcher/matchers/raises_matcher.rb +124 -0
- data/lib/matcher/matchers/range_matcher.rb +47 -0
- data/lib/matcher/matchers/reference_matcher.rb +111 -0
- data/lib/matcher/matchers/reference_matcher_collection.rb +57 -0
- data/lib/matcher/matchers/regexp_matcher.rb +84 -0
- data/lib/matcher/messages/expected_phrasing.rb +342 -0
- data/lib/matcher/messages/message.rb +102 -0
- data/lib/matcher/messages/message_builder.rb +35 -0
- data/lib/matcher/messages/message_rules.rb +223 -0
- data/lib/matcher/messages/namespaced_message_builder.rb +19 -0
- data/lib/matcher/messages/phrasing.rb +57 -0
- data/lib/matcher/messages/standard_message_builder.rb +105 -0
- data/lib/matcher/once_before.rb +18 -0
- data/lib/matcher/optional_chain.rb +24 -0
- data/lib/matcher/patterns/ast_mapping.rb +42 -0
- data/lib/matcher/patterns/capture_hole.rb +33 -0
- data/lib/matcher/patterns/constant_hole.rb +14 -0
- data/lib/matcher/patterns/hole.rb +30 -0
- data/lib/matcher/patterns/method_hole.rb +58 -0
- data/lib/matcher/patterns/pattern.rb +92 -0
- data/lib/matcher/patterns/pattern_building.rb +39 -0
- data/lib/matcher/patterns/pattern_capture.rb +11 -0
- data/lib/matcher/patterns/pattern_match.rb +29 -0
- data/lib/matcher/patterns/variable_hole.rb +14 -0
- data/lib/matcher/reporter.rb +98 -0
- data/lib/matcher/rules/message_factory.rb +25 -0
- data/lib/matcher/rules/message_rule.rb +18 -0
- data/lib/matcher/rules/message_rule_context.rb +24 -0
- data/lib/matcher/rules/rule_builder.rb +29 -0
- data/lib/matcher/rules/rule_set.rb +57 -0
- data/lib/matcher/rules/transform_builder.rb +24 -0
- data/lib/matcher/rules/transform_mapping.rb +5 -0
- data/lib/matcher/rules/transform_rule.rb +21 -0
- data/lib/matcher/state.rb +40 -0
- data/lib/matcher/testing/error_builder.rb +62 -0
- data/lib/matcher/testing/error_checker.rb +496 -0
- data/lib/matcher/testing/error_testing.rb +37 -0
- data/lib/matcher/testing/pattern_testing.rb +11 -0
- data/lib/matcher/testing/pattern_testing_scope.rb +34 -0
- data/lib/matcher/testing.rb +102 -0
- data/lib/matcher/undefined.rb +10 -0
- data/lib/matcher/utils/mapping_utils.rb +61 -0
- data/lib/matcher/utils.rb +72 -0
- data/lib/matcher/version.rb +5 -0
- data/lib/matcher.rb +337 -0
- metadata +167 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class MessageFactory
|
|
5
|
+
def initialize(value_paths, expressions, block)
|
|
6
|
+
@value_paths = value_paths
|
|
7
|
+
@expressions = expressions
|
|
8
|
+
@negate = false
|
|
9
|
+
@block = block
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def negate!
|
|
13
|
+
@negate = !@negate
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create(context, value_tree)
|
|
17
|
+
# Using reduce instead of dig so it will fail if an unexpected leaf is encountered.
|
|
18
|
+
values = @value_paths.transform_values { _1.reduce(value_tree, :[]) }
|
|
19
|
+
message = context.instance_exec(values, @expressions, &@block)
|
|
20
|
+
message.negate! if @negate
|
|
21
|
+
|
|
22
|
+
message
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class MessageRule
|
|
5
|
+
def initialize(patterns, block)
|
|
6
|
+
@patterns = patterns
|
|
7
|
+
@block = block
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
attr_reader :patterns
|
|
11
|
+
|
|
12
|
+
def apply(match)
|
|
13
|
+
expressions = @block.arity >= 2 ? match.expressions : nil
|
|
14
|
+
|
|
15
|
+
MessageFactory.new(match.value_paths, expressions, @block)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class MessageRuleContext
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
def initialize(matcher, state)
|
|
8
|
+
@matcher = matcher
|
|
9
|
+
@state = state
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def standard_message
|
|
13
|
+
StandardMessageBuilder.new(!@matcher.negated, @state.actual)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def expression_message
|
|
17
|
+
NamespacedMessageBuilder.new(!@matcher.negated, @state.actual, :expression)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def given
|
|
21
|
+
@matcher.expression.given_for(@state.values)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class RuleBuilder
|
|
5
|
+
include PatternBuilding
|
|
6
|
+
|
|
7
|
+
def initialize(rules = [], build_session: Matcher.build_session)
|
|
8
|
+
ExpressionBuilding.init(self, build_session)
|
|
9
|
+
|
|
10
|
+
@rules = rules
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :rules
|
|
14
|
+
|
|
15
|
+
def transform(*patterns, negate: false, &block)
|
|
16
|
+
patterns.map! { pattern_of(_1) }
|
|
17
|
+
@rules << TransformRule.new(patterns, negate, block)
|
|
18
|
+
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def message(*patterns, &block)
|
|
23
|
+
patterns.map! { pattern_of(_1) }
|
|
24
|
+
@rules << MessageRule.new(patterns, block)
|
|
25
|
+
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class RuleSet
|
|
5
|
+
def initialize(rules = [], &)
|
|
6
|
+
@rules = rules
|
|
7
|
+
|
|
8
|
+
configure(&) if block_given?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def configure(&)
|
|
12
|
+
Matcher.with_build_session do |build_session|
|
|
13
|
+
builder = RuleBuilder.new(@rules, build_session:)
|
|
14
|
+
builder.instance_exec(&)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def apply(expression)
|
|
21
|
+
cur = expression
|
|
22
|
+
mapping = AstMapping.new
|
|
23
|
+
result = nil
|
|
24
|
+
negate = false
|
|
25
|
+
|
|
26
|
+
while (rule, match = find_rule(cur, mapping))
|
|
27
|
+
result = rule.apply(match)
|
|
28
|
+
|
|
29
|
+
if rule.is_a?(MessageRule)
|
|
30
|
+
result.negate! if negate
|
|
31
|
+
|
|
32
|
+
return result
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
cur = result.expression
|
|
36
|
+
mapping = result.mapping
|
|
37
|
+
negate = !negate if rule.negate?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def find_rule(expression, mapping)
|
|
46
|
+
@rules.each do |rule|
|
|
47
|
+
rule.patterns.each do |pattern|
|
|
48
|
+
match = pattern.match(expression, mapping)
|
|
49
|
+
|
|
50
|
+
return [rule, match] if match
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class TransformBuilder
|
|
5
|
+
include Singleton
|
|
6
|
+
|
|
7
|
+
def call(match, receiver, method, *args, **kwargs)
|
|
8
|
+
expression = Call.new(
|
|
9
|
+
receiver.expression,
|
|
10
|
+
method,
|
|
11
|
+
args.map(&:expression),
|
|
12
|
+
kwargs.transform_values(&:expression),
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
mapping = TransformMapping.new
|
|
16
|
+
mapping.path = match.mapping.path
|
|
17
|
+
mapping.receiver = receiver.mapping
|
|
18
|
+
mapping.args = args.map(&:mapping)
|
|
19
|
+
mapping.kwargs = kwargs.transform_values(&:mapping)
|
|
20
|
+
|
|
21
|
+
PatternCapture.new(expression, mapping)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class TransformRule
|
|
5
|
+
def initialize(patterns, negate, block)
|
|
6
|
+
@patterns = patterns
|
|
7
|
+
@negate = negate
|
|
8
|
+
@block = block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_reader :patterns
|
|
12
|
+
|
|
13
|
+
def negate?
|
|
14
|
+
@negate
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def apply(match)
|
|
18
|
+
TransformBuilder.instance.instance_exec(match, &@block)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class State
|
|
5
|
+
def initialize(values, boolean: false)
|
|
6
|
+
@values = values
|
|
7
|
+
@boolean = boolean
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
attr_reader :values
|
|
11
|
+
|
|
12
|
+
def boolean?
|
|
13
|
+
@boolean
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def actual
|
|
17
|
+
@values[:actual]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def errors
|
|
21
|
+
@error_collector ||= new_collector
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def new_collector
|
|
25
|
+
@boolean ? BooleanCollector.new : ErrorCollector.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def result
|
|
29
|
+
@error_collector&.error || EmptyError.instance
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def report(actual = self.actual)
|
|
33
|
+
StandardMessageBuilder.new(false, actual)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def expected(actual = self.actual)
|
|
37
|
+
StandardMessageBuilder.new(true, actual)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class ErrorBuilder
|
|
5
|
+
def self.build(use_or: false, &)
|
|
6
|
+
errors = build_errors(&)
|
|
7
|
+
|
|
8
|
+
if use_or
|
|
9
|
+
OrError.from(errors)
|
|
10
|
+
else
|
|
11
|
+
AndError.from(errors)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.build_errors(&)
|
|
16
|
+
builder = ErrorBuilder.new
|
|
17
|
+
builder.instance_exec(&) if block_given?
|
|
18
|
+
builder.errors
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_reader :errors
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
@errors = []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def _or(*path, &)
|
|
28
|
+
errors = ErrorBuilder.build_errors(&)
|
|
29
|
+
error = OrError.from(errors)
|
|
30
|
+
|
|
31
|
+
@errors << nest(path, error)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def _and(*path, &)
|
|
35
|
+
errors = ErrorBuilder.build_errors(&)
|
|
36
|
+
error = AndError.from(errors)
|
|
37
|
+
|
|
38
|
+
@errors << nest(path, error)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def error(path_or_message, message = nil)
|
|
42
|
+
if message.nil?
|
|
43
|
+
@errors << ElementError.new(path_or_message)
|
|
44
|
+
else
|
|
45
|
+
path = Array(path_or_message)
|
|
46
|
+
element = ElementError.new(message)
|
|
47
|
+
|
|
48
|
+
@errors << nest(path, element)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def msg(actual)
|
|
53
|
+
StandardMessageBuilder.new(false, actual)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def nest(path, error)
|
|
59
|
+
path.reverse_each.reduce(error) { NestedError.from(_2, _1) }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|