dry-validation 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +42 -0
- data/Gemfile +8 -1
- data/README.md +13 -89
- data/config/errors.yml +35 -29
- data/dry-validation.gemspec +2 -2
- data/examples/basic.rb +3 -7
- data/examples/each.rb +3 -8
- data/examples/form.rb +3 -6
- data/examples/nested.rb +7 -15
- data/lib/dry/validation.rb +33 -5
- data/lib/dry/validation/error.rb +10 -26
- data/lib/dry/validation/error_compiler.rb +69 -99
- data/lib/dry/validation/error_compiler/input.rb +148 -0
- data/lib/dry/validation/hint_compiler.rb +83 -33
- data/lib/dry/validation/input_processor_compiler.rb +98 -0
- data/lib/dry/validation/input_processor_compiler/form.rb +46 -0
- data/lib/dry/validation/input_processor_compiler/sanitizer.rb +46 -0
- data/lib/dry/validation/messages/abstract.rb +30 -10
- data/lib/dry/validation/messages/i18n.rb +2 -1
- data/lib/dry/validation/messages/namespaced.rb +1 -0
- data/lib/dry/validation/messages/yaml.rb +8 -5
- data/lib/dry/validation/result.rb +33 -25
- data/lib/dry/validation/schema.rb +168 -61
- data/lib/dry/validation/schema/attr.rb +5 -27
- data/lib/dry/validation/schema/check.rb +24 -0
- data/lib/dry/validation/schema/dsl.rb +97 -0
- data/lib/dry/validation/schema/form.rb +2 -26
- data/lib/dry/validation/schema/key.rb +32 -28
- data/lib/dry/validation/schema/rule.rb +88 -32
- data/lib/dry/validation/schema/value.rb +77 -27
- data/lib/dry/validation/schema_compiler.rb +38 -0
- data/lib/dry/validation/version.rb +1 -1
- data/spec/fixtures/locales/pl.yml +1 -1
- data/spec/integration/attr_spec.rb +122 -0
- data/spec/integration/custom_error_messages_spec.rb +9 -11
- data/spec/integration/custom_predicates_spec.rb +68 -18
- data/spec/integration/error_compiler_spec.rb +259 -65
- data/spec/integration/hints_spec.rb +28 -9
- data/spec/integration/injecting_rules_spec.rb +11 -12
- data/spec/integration/localized_error_messages_spec.rb +16 -16
- data/spec/integration/messages/i18n_spec.rb +9 -5
- data/spec/integration/optional_keys_spec.rb +9 -11
- data/spec/integration/schema/array_schema_spec.rb +23 -0
- data/spec/integration/schema/check_rules_spec.rb +39 -31
- data/spec/integration/schema/check_with_nth_el_spec.rb +25 -0
- data/spec/integration/schema/each_with_set_spec.rb +23 -24
- data/spec/integration/schema/form_spec.rb +122 -0
- data/spec/integration/schema/inheriting_schema_spec.rb +31 -0
- data/spec/integration/schema/input_processor_spec.rb +46 -0
- data/spec/integration/schema/macros/confirmation_spec.rb +33 -0
- data/spec/integration/schema/macros/maybe_spec.rb +32 -0
- data/spec/integration/schema/macros/required_spec.rb +59 -0
- data/spec/integration/schema/macros/when_spec.rb +65 -0
- data/spec/integration/schema/nested_values_spec.rb +41 -0
- data/spec/integration/schema/not_spec.rb +14 -14
- data/spec/integration/schema/option_with_default_spec.rb +30 -0
- data/spec/integration/schema/reusing_schema_spec.rb +33 -0
- data/spec/integration/schema/using_types_spec.rb +29 -0
- data/spec/integration/schema/xor_spec.rb +17 -14
- data/spec/integration/schema_spec.rb +75 -245
- data/spec/shared/rule_compiler.rb +8 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/unit/hint_compiler_spec.rb +10 -10
- data/spec/unit/{input_type_compiler_spec.rb → input_processor_compiler/form_spec.rb} +88 -73
- data/spec/unit/schema/key_spec.rb +33 -0
- data/spec/unit/schema/rule_spec.rb +7 -6
- data/spec/unit/schema/value_spec.rb +187 -54
- metadata +53 -31
- data/.rubocop.yml +0 -16
- data/.rubocop_todo.yml +0 -7
- data/lib/dry/validation/input_type_compiler.rb +0 -83
- data/lib/dry/validation/schema/definition.rb +0 -74
- data/lib/dry/validation/schema/result.rb +0 -68
- data/rakelib/rubocop.rake +0 -18
- data/spec/integration/rule_groups_spec.rb +0 -94
- data/spec/integration/schema/attrs_spec.rb +0 -38
- data/spec/integration/schema/default_key_behavior_spec.rb +0 -23
- data/spec/integration/schema/grouped_rules_spec.rb +0 -57
- data/spec/integration/schema/nested_spec.rb +0 -31
- data/spec/integration/schema_form_spec.rb +0 -97
data/lib/dry/validation/error.rb
CHANGED
@@ -1,39 +1,23 @@
|
|
1
1
|
module Dry
|
2
2
|
module Validation
|
3
3
|
class Error
|
4
|
-
|
5
|
-
include Enumerable
|
4
|
+
include Dry::Equalizer(:name, :result)
|
6
5
|
|
7
|
-
|
6
|
+
attr_reader :name, :result
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def each(&block)
|
14
|
-
errors.each(&block)
|
15
|
-
end
|
16
|
-
|
17
|
-
def empty?
|
18
|
-
errors.empty?
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_ary
|
22
|
-
errors.map { |error| error.to_ary }
|
23
|
-
end
|
24
|
-
alias_method :to_a, :to_ary
|
8
|
+
def initialize(name, result)
|
9
|
+
@name = name
|
10
|
+
@result = result
|
25
11
|
end
|
26
12
|
|
27
|
-
|
28
|
-
|
29
|
-
def initialize(result)
|
30
|
-
@result = result
|
13
|
+
def schema?
|
14
|
+
result.response.is_a?(Validation::Result)
|
31
15
|
end
|
32
16
|
|
33
|
-
def
|
34
|
-
[:error, result.
|
17
|
+
def to_ast
|
18
|
+
node = [:error, [name, result.to_ast]]
|
19
|
+
schema? ? [:schema, node] : node
|
35
20
|
end
|
36
|
-
alias_method :to_a, :to_ary
|
37
21
|
end
|
38
22
|
end
|
39
23
|
end
|
@@ -1,18 +1,25 @@
|
|
1
1
|
module Dry
|
2
2
|
module Validation
|
3
3
|
class ErrorCompiler
|
4
|
-
attr_reader :messages, :options
|
4
|
+
attr_reader :messages, :hints, :options
|
5
5
|
|
6
6
|
DEFAULT_RESULT = {}.freeze
|
7
|
+
EMPTY_HINTS = [].freeze
|
7
8
|
KEY_SEPARATOR = '.'.freeze
|
8
9
|
|
9
10
|
def initialize(messages, options = {})
|
10
11
|
@messages = messages
|
11
|
-
@options = options
|
12
|
+
@options = Hash[options]
|
13
|
+
@hints = @options.fetch(:hints, {})
|
14
|
+
@full = options.fetch(:full, false)
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
15
|
-
|
17
|
+
def full?
|
18
|
+
@full
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(ast, *args)
|
22
|
+
merge(ast.map { |node| visit(node, *args) }) || DEFAULT_RESULT
|
16
23
|
end
|
17
24
|
|
18
25
|
def with(new_options)
|
@@ -23,135 +30,98 @@ module Dry
|
|
23
30
|
__send__(:"visit_#{node[0]}", node[1], *args)
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def visit_input(input, *)
|
31
|
-
name = normalize_name(input[0])
|
32
|
-
_, value, rules = input
|
33
|
-
errors = [rules.map { |rule| visit(rule, name, value) }, value]
|
34
|
-
|
35
|
-
if input[0].is_a?(Hash)
|
36
|
-
root, sub = input[0].to_a.flatten
|
37
|
-
{ root => { sub => errors } }
|
38
|
-
else
|
39
|
-
{ input[0] => errors }
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def visit_group(_, name, _)
|
44
|
-
messages[name, rule: name]
|
45
|
-
end
|
46
|
-
|
47
|
-
def visit_check(node, *)
|
48
|
-
name = normalize_name(node[0])
|
49
|
-
messages[name, rule: name]
|
50
|
-
end
|
51
|
-
|
52
|
-
def visit_key(rule, name, value)
|
53
|
-
_, predicate = rule
|
54
|
-
visit(predicate, value, name)
|
55
|
-
end
|
56
|
-
|
57
|
-
def visit_attr(rule, name, value)
|
58
|
-
_, predicate = rule
|
59
|
-
visit(predicate, value, name)
|
60
|
-
end
|
61
|
-
|
62
|
-
def visit_val(rule, name, value)
|
63
|
-
name, predicate = rule
|
64
|
-
visit(predicate, value, name)
|
65
|
-
end
|
66
|
-
|
67
|
-
def visit_predicate(predicate, value, name)
|
68
|
-
predicate_name, args = predicate
|
69
|
-
|
70
|
-
lookup_options = options.merge(
|
71
|
-
rule: name, val_type: value.class, arg_type: args[0].class
|
72
|
-
)
|
73
|
-
|
74
|
-
template = messages[predicate_name, lookup_options]
|
75
|
-
tokens = visit(predicate, value).merge(name: name)
|
76
|
-
|
77
|
-
template % tokens
|
33
|
+
def visit_schema(node, *args)
|
34
|
+
visit_error(node[1], true)
|
78
35
|
end
|
79
36
|
|
80
|
-
def
|
81
|
-
|
37
|
+
def visit_set(node, *args)
|
38
|
+
call(node, *args)
|
82
39
|
end
|
83
40
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def visit_exclusion?(*args, _value)
|
89
|
-
{ list: args[0][0].join(', ') }
|
90
|
-
end
|
41
|
+
def visit_error(error, schema = false)
|
42
|
+
name, other = error
|
43
|
+
message = messages[name]
|
91
44
|
|
92
|
-
|
93
|
-
|
94
|
-
|
45
|
+
if message
|
46
|
+
{ name => [message] }
|
47
|
+
else
|
48
|
+
result = schema ? visit(other, name) : visit(other)
|
95
49
|
|
96
|
-
|
97
|
-
|
50
|
+
if result.is_a?(Array)
|
51
|
+
merge(result)
|
52
|
+
else
|
53
|
+
merge_hints(result)
|
54
|
+
end
|
55
|
+
end
|
98
56
|
end
|
99
57
|
|
100
|
-
def
|
101
|
-
|
58
|
+
def visit_input(node, path = nil)
|
59
|
+
name, result = node
|
60
|
+
visit(result, path || name)
|
102
61
|
end
|
103
62
|
|
104
|
-
def
|
105
|
-
|
63
|
+
def visit_result(node, name = nil)
|
64
|
+
value, other = node
|
65
|
+
input_visitor(name, value).visit(other)
|
106
66
|
end
|
107
67
|
|
108
|
-
def
|
109
|
-
|
68
|
+
def visit_implication(node)
|
69
|
+
_, right = node
|
70
|
+
visit(right)
|
110
71
|
end
|
111
72
|
|
112
|
-
def
|
113
|
-
|
73
|
+
def visit_key(rule)
|
74
|
+
_, predicate = rule
|
75
|
+
visit(predicate)
|
114
76
|
end
|
115
77
|
|
116
|
-
def
|
117
|
-
|
78
|
+
def visit_attr(rule)
|
79
|
+
_, predicate = rule
|
80
|
+
visit(predicate)
|
118
81
|
end
|
119
82
|
|
120
|
-
def
|
121
|
-
|
83
|
+
def visit_val(node)
|
84
|
+
visit(node)
|
122
85
|
end
|
123
86
|
|
124
|
-
|
125
|
-
{ eql_value: args[0][0], value: value }
|
126
|
-
end
|
87
|
+
private
|
127
88
|
|
128
|
-
def
|
129
|
-
|
89
|
+
def merge_hints(messages)
|
90
|
+
messages.each_with_object({}) do |(name, msgs), res|
|
91
|
+
if msgs.is_a?(Hash)
|
92
|
+
res[name] = merge_hints(msgs)
|
93
|
+
else
|
94
|
+
all_msgs = msgs + (hints[name] || EMPTY_HINTS)
|
95
|
+
all_msgs.uniq!
|
130
96
|
|
131
|
-
|
132
|
-
|
133
|
-
else
|
134
|
-
{ num: args[0][0], value: value }
|
97
|
+
res[name] = all_msgs
|
98
|
+
end
|
135
99
|
end
|
136
100
|
end
|
137
101
|
|
138
|
-
private
|
139
|
-
|
140
102
|
def normalize_name(name)
|
141
|
-
Array(name).join(
|
103
|
+
Array(name).join('.').to_sym
|
142
104
|
end
|
143
105
|
|
144
106
|
def merge(result)
|
145
|
-
result.reduce
|
146
|
-
|
147
|
-
|
107
|
+
result.reduce { |a, e| deep_merge(a, e) } || DEFAULT_RESULT
|
108
|
+
end
|
109
|
+
|
110
|
+
def deep_merge(left, right)
|
111
|
+
left.merge(right) do |_, a, e|
|
112
|
+
if a.is_a?(Hash)
|
113
|
+
deep_merge(a, e)
|
114
|
+
else
|
115
|
+
a + e
|
148
116
|
end
|
149
117
|
end
|
150
118
|
end
|
151
119
|
|
152
|
-
def
|
153
|
-
|
120
|
+
def input_visitor(name, input)
|
121
|
+
Input.new(messages, options.merge(name: name, input: input))
|
154
122
|
end
|
155
123
|
end
|
156
124
|
end
|
157
125
|
end
|
126
|
+
|
127
|
+
require 'dry/validation/error_compiler/input'
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module Dry
|
2
|
+
module Validation
|
3
|
+
class ErrorCompiler::Input < ErrorCompiler
|
4
|
+
attr_reader :name, :input, :rule, :val_type
|
5
|
+
|
6
|
+
def initialize(messages, options)
|
7
|
+
super
|
8
|
+
@name = options.fetch(:name)
|
9
|
+
@input = options.fetch(:input)
|
10
|
+
@rule = Array(name).last
|
11
|
+
@val_type = input.class
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_each(node)
|
15
|
+
node.map { |el| visit(el) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_set(node)
|
19
|
+
result = node.map do |input|
|
20
|
+
visit(input)
|
21
|
+
end
|
22
|
+
merge(result)
|
23
|
+
end
|
24
|
+
|
25
|
+
def visit_el(node)
|
26
|
+
idx, el = node
|
27
|
+
name = [*Array(name), idx]
|
28
|
+
visit(el, name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_check(node)
|
32
|
+
_, other = node
|
33
|
+
visit(other)
|
34
|
+
end
|
35
|
+
|
36
|
+
def visit_predicate(node)
|
37
|
+
predicate, args = node
|
38
|
+
|
39
|
+
lookup_options = options.merge(
|
40
|
+
rule: rule, val_type: val_type, arg_type: args[0].class
|
41
|
+
)
|
42
|
+
|
43
|
+
tokens = options_for(predicate, args)
|
44
|
+
template = messages[predicate, lookup_options.merge(tokens)]
|
45
|
+
|
46
|
+
unless template
|
47
|
+
raise MissingMessageError.new("message for #{predicate} was not found")
|
48
|
+
end
|
49
|
+
|
50
|
+
rule_name =
|
51
|
+
if rule.is_a?(Symbol)
|
52
|
+
messages.rule(rule, lookup_options) || rule
|
53
|
+
else
|
54
|
+
rule
|
55
|
+
end
|
56
|
+
|
57
|
+
message =
|
58
|
+
if full?
|
59
|
+
"#{rule_name} #{template % tokens}"
|
60
|
+
else
|
61
|
+
template % tokens
|
62
|
+
end
|
63
|
+
|
64
|
+
path = [[message], *[tokens[:name], *Array(name).reverse].uniq]
|
65
|
+
|
66
|
+
path.reduce { |a, e| { e => a } }
|
67
|
+
end
|
68
|
+
|
69
|
+
def options_for_type?(*args)
|
70
|
+
{ type: args[0][0] }
|
71
|
+
end
|
72
|
+
|
73
|
+
def options_for_key?(*args)
|
74
|
+
{ name: args[0][0] }
|
75
|
+
end
|
76
|
+
|
77
|
+
def options_for_attr?(*args)
|
78
|
+
{ name: args[0][0] }
|
79
|
+
end
|
80
|
+
|
81
|
+
def options_for_exclusion?(*args)
|
82
|
+
{ list: args[0][0].join(', ') }
|
83
|
+
end
|
84
|
+
|
85
|
+
def options_for_inclusion?(*args)
|
86
|
+
{ list: args[0][0].join(', ') }
|
87
|
+
end
|
88
|
+
|
89
|
+
def options_for_gt?(*args)
|
90
|
+
{ num: args[0][0], value: input }
|
91
|
+
end
|
92
|
+
|
93
|
+
def options_for_gteq?(*args)
|
94
|
+
{ num: args[0][0], value: input }
|
95
|
+
end
|
96
|
+
|
97
|
+
def options_for_lt?(*args)
|
98
|
+
{ num: args[0][0], value: input }
|
99
|
+
end
|
100
|
+
|
101
|
+
def options_for_lteq?(*args)
|
102
|
+
{ num: args[0][0], value: input }
|
103
|
+
end
|
104
|
+
|
105
|
+
def options_for_int?(*args)
|
106
|
+
{ num: args[0][0], value: input }
|
107
|
+
end
|
108
|
+
|
109
|
+
def options_for_max_size?(*args)
|
110
|
+
{ num: args[0][0], value: input }
|
111
|
+
end
|
112
|
+
|
113
|
+
def options_for_min_size?(*args)
|
114
|
+
{ num: args[0][0], value: input }
|
115
|
+
end
|
116
|
+
|
117
|
+
def options_for_eql?(*args)
|
118
|
+
{ eql_value: args[0][0], value: input }
|
119
|
+
end
|
120
|
+
|
121
|
+
def options_for_size?(*args)
|
122
|
+
num = args[0][0]
|
123
|
+
|
124
|
+
if num.is_a?(Range)
|
125
|
+
{ left: num.first, right: num.last, value: input }
|
126
|
+
else
|
127
|
+
{ num: args[0][0], value: input }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def options_for(predicate, args)
|
132
|
+
meth = :"options_for_#{predicate}"
|
133
|
+
|
134
|
+
defaults = { name: rule, rule: rule, value: input }
|
135
|
+
|
136
|
+
if respond_to?(meth)
|
137
|
+
defaults.merge!(__send__(meth, args))
|
138
|
+
end
|
139
|
+
|
140
|
+
defaults
|
141
|
+
end
|
142
|
+
|
143
|
+
def input_visitor(new_name, value)
|
144
|
+
self.class.new(messages, options.merge(name: [*name, *new_name].uniq, input: value))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -1,14 +1,37 @@
|
|
1
|
-
require 'dry/validation/error_compiler'
|
1
|
+
require 'dry/validation/error_compiler/input'
|
2
2
|
|
3
3
|
module Dry
|
4
4
|
module Validation
|
5
|
-
class HintCompiler < ErrorCompiler
|
6
|
-
|
5
|
+
class HintCompiler < ErrorCompiler::Input
|
6
|
+
include Dry::Equalizer(:messages, :rules, :options)
|
7
|
+
|
8
|
+
attr_reader :rules, :excluded
|
9
|
+
|
10
|
+
TYPES = {
|
11
|
+
none?: NilClass,
|
12
|
+
bool?: TrueClass,
|
13
|
+
str?: String,
|
14
|
+
int?: Fixnum,
|
15
|
+
float?: Float,
|
16
|
+
decimal?: BigDecimal,
|
17
|
+
date?: Date,
|
18
|
+
date_time?: DateTime,
|
19
|
+
time?: Time,
|
20
|
+
hash?: Hash,
|
21
|
+
array?: Array
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
EXCLUDED = [:none?, :filled?, :key?].freeze
|
25
|
+
|
26
|
+
def self.cache
|
27
|
+
@cache ||= ThreadSafe::Cache.new
|
28
|
+
end
|
7
29
|
|
8
30
|
def initialize(messages, options = {})
|
9
|
-
|
10
|
-
@options = Hash[options]
|
31
|
+
super(messages, { name: nil, input: nil }.merge(options))
|
11
32
|
@rules = @options.delete(:rules)
|
33
|
+
@excluded = @options.fetch(:excluded, EXCLUDED)
|
34
|
+
@val_type = options[:val_type]
|
12
35
|
end
|
13
36
|
|
14
37
|
def with(new_options)
|
@@ -16,58 +39,85 @@ module Dry
|
|
16
39
|
end
|
17
40
|
|
18
41
|
def call
|
19
|
-
|
42
|
+
self.class.cache.fetch_or_store(hash) do
|
43
|
+
super(rules)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_predicate(node)
|
48
|
+
predicate, _ = node
|
49
|
+
|
50
|
+
val_type = TYPES[predicate]
|
51
|
+
|
52
|
+
return with(val_type: val_type) if val_type
|
53
|
+
return {} if excluded.include?(predicate)
|
20
54
|
|
21
|
-
|
22
|
-
|
23
|
-
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
def visit_set(node)
|
59
|
+
result = node.map do |el|
|
60
|
+
visit(el)
|
24
61
|
end
|
62
|
+
merge(result)
|
63
|
+
end
|
25
64
|
|
26
|
-
|
65
|
+
def visit_each(node)
|
66
|
+
visit(node)
|
27
67
|
end
|
28
68
|
|
29
69
|
def visit_or(node)
|
30
70
|
left, right = node
|
31
|
-
[visit(left),
|
71
|
+
merge([visit(left), visit(right)])
|
32
72
|
end
|
33
73
|
|
34
74
|
def visit_and(node)
|
35
75
|
left, right = node
|
36
|
-
[visit(left), Array(visit(right)).flatten.compact].compact
|
37
|
-
end
|
38
76
|
|
39
|
-
|
40
|
-
name, predicate = node
|
41
|
-
visit(predicate, name)
|
42
|
-
end
|
77
|
+
result = visit(left)
|
43
78
|
|
44
|
-
|
45
|
-
|
79
|
+
if result.is_a?(self.class)
|
80
|
+
result.visit(right)
|
81
|
+
else
|
82
|
+
visit(right)
|
83
|
+
end
|
84
|
+
end
|
46
85
|
|
47
|
-
|
86
|
+
def visit_implication(node)
|
87
|
+
_, right = node
|
88
|
+
visit(right)
|
89
|
+
end
|
48
90
|
|
49
|
-
|
50
|
-
|
91
|
+
def visit_key(node)
|
92
|
+
name, predicate = node
|
93
|
+
with(name: Array([*self.name, name])).visit(predicate)
|
94
|
+
end
|
95
|
+
alias_method :visit_attr, :visit_key
|
51
96
|
|
52
|
-
|
97
|
+
def visit_val(node)
|
98
|
+
visit(node)
|
99
|
+
end
|
53
100
|
|
54
|
-
|
101
|
+
def visit_schema(node)
|
102
|
+
DEFAULT_RESULT
|
103
|
+
end
|
55
104
|
|
56
|
-
|
105
|
+
def visit_check(node)
|
106
|
+
DEFAULT_RESULT
|
57
107
|
end
|
58
108
|
|
59
|
-
def
|
60
|
-
|
61
|
-
name
|
109
|
+
def visit_xor(node)
|
110
|
+
DEFAULT_RESULT
|
62
111
|
end
|
63
112
|
|
64
|
-
def
|
65
|
-
|
66
|
-
name
|
113
|
+
def visit_not(node)
|
114
|
+
DEFAULT_RESULT
|
67
115
|
end
|
68
116
|
|
69
|
-
|
70
|
-
|
117
|
+
private
|
118
|
+
|
119
|
+
def merge(result)
|
120
|
+
super(result.reject { |el| el.is_a?(self.class) })
|
71
121
|
end
|
72
122
|
end
|
73
123
|
end
|