rubocop 0.67.2 → 0.68.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +86 -233
- data/exe/rubocop +0 -12
- data/lib/rubocop.rb +13 -30
- data/lib/rubocop/ast/builder.rb +4 -0
- data/lib/rubocop/ast/node/alias_node.rb +24 -0
- data/lib/rubocop/ast/node/class_node.rb +31 -0
- data/lib/rubocop/ast/node/module_node.rb +24 -0
- data/lib/rubocop/ast/node/range_node.rb +7 -0
- data/lib/rubocop/ast/node/resbody_node.rb +12 -0
- data/lib/rubocop/ast/node/self_class_node.rb +24 -0
- data/lib/rubocop/cli.rb +40 -4
- data/lib/rubocop/config.rb +9 -7
- data/lib/rubocop/config_loader.rb +48 -7
- data/lib/rubocop/config_loader_resolver.rb +5 -4
- data/lib/rubocop/cop/commissioner.rb +24 -0
- data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +18 -6
- data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +12 -14
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +9 -20
- data/lib/rubocop/cop/layout/align_arguments.rb +93 -0
- data/lib/rubocop/cop/layout/align_parameters.rb +57 -33
- data/lib/rubocop/cop/layout/class_structure.rb +5 -5
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -8
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +3 -6
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +1 -2
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +292 -0
- data/lib/rubocop/cop/layout/{first_parameter_indentation.rb → indent_first_argument.rb} +11 -12
- data/lib/rubocop/cop/layout/{indent_array.rb → indent_first_array_element.rb} +2 -2
- data/lib/rubocop/cop/layout/{indent_hash.rb → indent_first_hash_element.rb} +2 -2
- data/lib/rubocop/cop/layout/indent_first_parameter.rb +96 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -16
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -4
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -16
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +6 -8
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +4 -8
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +157 -0
- data/lib/rubocop/cop/lint/inherit_exception.rb +3 -4
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -5
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +25 -5
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -6
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -2
- data/lib/rubocop/cop/message_annotator.rb +1 -0
- data/lib/rubocop/cop/metrics/line_length.rb +139 -28
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +3 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +190 -0
- data/lib/rubocop/cop/mixin/{array_hash_indentation.rb → multiline_element_indentation.rb} +3 -2
- data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -7
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +33 -4
- data/lib/rubocop/cop/rails/active_record_override.rb +23 -8
- data/lib/rubocop/cop/rails/delegate.rb +5 -8
- data/lib/rubocop/cop/rails/environment_comparison.rb +5 -3
- data/lib/rubocop/cop/rails/find_each.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
- data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/skips_model_validations.rb +6 -7
- data/lib/rubocop/cop/rails/time_zone.rb +3 -10
- data/lib/rubocop/cop/rails/validation.rb +3 -0
- data/lib/rubocop/cop/registry.rb +3 -3
- data/lib/rubocop/cop/style/alias.rb +13 -7
- data/lib/rubocop/cop/style/block_delimiters.rb +20 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -21
- data/lib/rubocop/cop/style/class_methods.rb +16 -24
- data/lib/rubocop/cop/style/conditional_assignment.rb +20 -49
- data/lib/rubocop/cop/style/documentation.rb +3 -7
- data/lib/rubocop/cop/style/format_string.rb +18 -21
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +4 -0
- data/lib/rubocop/cop/style/lambda.rb +12 -8
- data/lib/rubocop/cop/style/mixin_grouping.rb +8 -10
- data/lib/rubocop/cop/style/module_function.rb +2 -3
- data/lib/rubocop/cop/style/next.rb +10 -14
- data/lib/rubocop/cop/style/one_line_conditional.rb +5 -3
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -4
- data/lib/rubocop/cop/style/random_with_offset.rb +44 -47
- data/lib/rubocop/cop/style/redundant_return.rb +6 -14
- data/lib/rubocop/cop/style/redundant_sort_by.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +3 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +2 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +20 -40
- data/lib/rubocop/cop/style/unless_else.rb +1 -2
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -7
- data/lib/rubocop/cop/util.rb +2 -4
- data/lib/rubocop/file_finder.rb +5 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -0
- data/lib/rubocop/node_pattern.rb +304 -170
- data/lib/rubocop/options.rb +4 -1
- data/lib/rubocop/rspec/shared_contexts.rb +3 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +1 -1
- metadata +26 -50
- data/lib/rubocop/cop/performance/caller.rb +0 -69
- data/lib/rubocop/cop/performance/case_when_splat.rb +0 -177
- data/lib/rubocop/cop/performance/casecmp.rb +0 -108
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +0 -78
- data/lib/rubocop/cop/performance/compare_with_block.rb +0 -122
- data/lib/rubocop/cop/performance/count.rb +0 -102
- data/lib/rubocop/cop/performance/detect.rb +0 -110
- data/lib/rubocop/cop/performance/double_start_end_with.rb +0 -94
- data/lib/rubocop/cop/performance/end_with.rb +0 -56
- data/lib/rubocop/cop/performance/fixed_size.rb +0 -97
- data/lib/rubocop/cop/performance/flat_map.rb +0 -78
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +0 -99
- data/lib/rubocop/cop/performance/open_struct.rb +0 -46
- data/lib/rubocop/cop/performance/range_include.rb +0 -50
- data/lib/rubocop/cop/performance/redundant_block_call.rb +0 -93
- data/lib/rubocop/cop/performance/redundant_match.rb +0 -56
- data/lib/rubocop/cop/performance/redundant_merge.rb +0 -183
- data/lib/rubocop/cop/performance/regexp_match.rb +0 -265
- data/lib/rubocop/cop/performance/reverse_each.rb +0 -42
- data/lib/rubocop/cop/performance/size.rb +0 -77
- data/lib/rubocop/cop/performance/start_with.rb +0 -59
- data/lib/rubocop/cop/performance/string_replacement.rb +0 -173
- data/lib/rubocop/cop/performance/times_map.rb +0 -71
- data/lib/rubocop/cop/performance/unfreeze_string.rb +0 -50
- data/lib/rubocop/cop/performance/uri_default_parser.rb +0 -47
@@ -90,6 +90,8 @@ module RuboCop
|
|
90
90
|
|
91
91
|
# rubocop:disable Metrics/CyclomaticComplexity
|
92
92
|
def check_branch(node)
|
93
|
+
return unless node
|
94
|
+
|
93
95
|
case node.type
|
94
96
|
when :return then check_return_node(node)
|
95
97
|
when :case then check_case_node(node)
|
@@ -111,25 +113,15 @@ module RuboCop
|
|
111
113
|
end
|
112
114
|
|
113
115
|
def check_case_node(node)
|
114
|
-
|
115
|
-
|
116
|
-
check_branch(else_node) if else_node
|
117
|
-
end
|
118
|
-
|
119
|
-
def check_when_node(node)
|
120
|
-
return unless node
|
121
|
-
|
122
|
-
_cond, body = *node
|
123
|
-
check_branch(body) if body
|
116
|
+
node.when_branches.each { |when_node| check_branch(when_node.body) }
|
117
|
+
check_branch(node.else_branch)
|
124
118
|
end
|
125
119
|
|
126
120
|
def check_if_node(node)
|
127
121
|
return if node.modifier_form? || node.ternary?
|
128
122
|
|
129
|
-
|
130
|
-
|
131
|
-
check_branch(if_node) if if_node
|
132
|
-
check_branch(else_node) if else_node
|
123
|
+
check_branch(node.if_branch)
|
124
|
+
check_branch(node.else_branch)
|
133
125
|
end
|
134
126
|
|
135
127
|
def check_rescue_node(node)
|
@@ -65,6 +65,8 @@ module RuboCop
|
|
65
65
|
|
66
66
|
MSG = 'Use safe navigation (`&.`) instead of checking if an object ' \
|
67
67
|
'exists before calling the method.'.freeze
|
68
|
+
LOGIC_JUMP_KEYWORDS = %i[break fail next raise
|
69
|
+
return throw yield].freeze
|
68
70
|
|
69
71
|
minimum_target_ruby_version 2.3
|
70
72
|
|
@@ -149,6 +151,7 @@ module RuboCop
|
|
149
151
|
|
150
152
|
checked_variable, matching_receiver, method =
|
151
153
|
extract_common_parts(receiver, variable)
|
154
|
+
matching_receiver = nil if LOGIC_JUMP_KEYWORDS.include?(receiver.type)
|
152
155
|
[checked_variable, matching_receiver, receiver, method]
|
153
156
|
end
|
154
157
|
|
@@ -24,10 +24,9 @@ module RuboCop
|
|
24
24
|
'Use a block to customize the struct.'.freeze
|
25
25
|
|
26
26
|
def on_class(node)
|
27
|
-
|
28
|
-
return unless struct_constructor?(superclass)
|
27
|
+
return unless struct_constructor?(node.parent_class)
|
29
28
|
|
30
|
-
add_offense(node, location:
|
29
|
+
add_offense(node, location: node.parent_class.source_range)
|
31
30
|
end
|
32
31
|
|
33
32
|
def_node_matcher :struct_constructor?, <<-PATTERN
|
@@ -32,46 +32,38 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def on_block(node)
|
35
|
-
symbol_proc?(node) do |
|
36
|
-
block_method_name = resolve_block_method_name(send_or_super)
|
37
|
-
|
35
|
+
symbol_proc?(node) do |dispatch_node, arguments_node, method_name|
|
38
36
|
# TODO: Rails-specific handling that we should probably make
|
39
37
|
# configurable - https://github.com/rubocop-hq/rubocop/issues/1485
|
40
38
|
# we should ignore lambdas & procs
|
41
|
-
return if proc_node?(
|
42
|
-
return if %i[lambda proc].include?(
|
43
|
-
return if ignored_method?(
|
44
|
-
return if
|
45
|
-
block_args.source.include?(',')
|
39
|
+
return if proc_node?(dispatch_node)
|
40
|
+
return if %i[lambda proc].include?(dispatch_node.method_name)
|
41
|
+
return if ignored_method?(dispatch_node.method_name)
|
42
|
+
return if destructuring_block_argument?(arguments_node)
|
46
43
|
|
47
|
-
|
44
|
+
register_offense(node, method_name, dispatch_node.method_name)
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
48
|
+
def destructuring_block_argument?(argument_node)
|
49
|
+
argument_node.one? && argument_node.source.include?(',')
|
50
|
+
end
|
51
|
+
|
51
52
|
def autocorrect(node)
|
52
53
|
lambda do |corrector|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
args = *block_send_or_super
|
54
|
+
if node.send_node.arguments?
|
55
|
+
autocorrect_with_args(corrector, node,
|
56
|
+
node.send_node.arguments,
|
57
|
+
node.body.method_name)
|
58
58
|
else
|
59
|
-
|
59
|
+
autocorrect_without_args(corrector, node)
|
60
60
|
end
|
61
|
-
autocorrect_method(corrector, node, args, method_name)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
64
|
private
|
66
65
|
|
67
|
-
def
|
68
|
-
return :super if super?(block_send_or_super)
|
69
|
-
|
70
|
-
_receiver, method_name, _args = *block_send_or_super
|
71
|
-
method_name
|
72
|
-
end
|
73
|
-
|
74
|
-
def offense(node, method_name, block_method_name)
|
66
|
+
def register_offense(node, method_name, block_method_name)
|
75
67
|
block_start = node.loc.begin.begin_pos
|
76
68
|
block_end = node.loc.end.end_pos
|
77
69
|
range = range_between(block_start, block_end)
|
@@ -83,16 +75,9 @@ module RuboCop
|
|
83
75
|
block_method: block_method_name))
|
84
76
|
end
|
85
77
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
else
|
90
|
-
autocorrect_with_args(corrector, node, args, method_name)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def autocorrect_no_args(corrector, node, method_name)
|
95
|
-
corrector.replace(block_range_with_space(node), "(&:#{method_name})")
|
78
|
+
def autocorrect_without_args(corrector, node)
|
79
|
+
corrector.replace(block_range_with_space(node),
|
80
|
+
"(&:#{node.body.method_name})")
|
96
81
|
end
|
97
82
|
|
98
83
|
def autocorrect_with_args(corrector, node, args, method_name)
|
@@ -111,8 +96,7 @@ module RuboCop
|
|
111
96
|
end
|
112
97
|
|
113
98
|
def begin_pos_for_replacement(node)
|
114
|
-
|
115
|
-
expr = block_send_or_super.source_range
|
99
|
+
expr = node.send_node.source_range
|
116
100
|
|
117
101
|
if (paren_pos = (expr.source =~ /\(\s*\)$/))
|
118
102
|
expr.begin_pos + paren_pos
|
@@ -120,10 +104,6 @@ module RuboCop
|
|
120
104
|
node.loc.begin.begin_pos
|
121
105
|
end
|
122
106
|
end
|
123
|
-
|
124
|
-
def super?(node)
|
125
|
-
SUPER_TYPES.include?(node.type)
|
126
|
-
end
|
127
107
|
end
|
128
108
|
end
|
129
109
|
end
|
@@ -32,8 +32,7 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def autocorrect(node)
|
35
|
-
|
36
|
-
body_range = range_between_condition_and_else(node, condition)
|
35
|
+
body_range = range_between_condition_and_else(node, node.condition)
|
37
36
|
else_range = range_between_else_and_end(node)
|
38
37
|
|
39
38
|
lambda do |corrector|
|
@@ -98,7 +98,8 @@ module RuboCop
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def valid_yoda?(node)
|
101
|
-
lhs
|
101
|
+
lhs = node.receiver
|
102
|
+
rhs = node.first_argument
|
102
103
|
|
103
104
|
return true if lhs.literal? && rhs.literal? ||
|
104
105
|
!lhs.literal? && !rhs.literal?
|
@@ -111,8 +112,10 @@ module RuboCop
|
|
111
112
|
end
|
112
113
|
|
113
114
|
def corrected_code(node)
|
114
|
-
lhs
|
115
|
-
|
115
|
+
lhs = node.receiver
|
116
|
+
rhs = node.first_argument
|
117
|
+
|
118
|
+
"#{rhs.source} #{reverse_comparison(node.method_name)} #{lhs.source}"
|
116
119
|
end
|
117
120
|
|
118
121
|
def actual_code_range(node)
|
@@ -126,13 +129,11 @@ module RuboCop
|
|
126
129
|
end
|
127
130
|
|
128
131
|
def non_equality_operator?(node)
|
129
|
-
|
130
|
-
!EQUALITY_OPERATORS.include?(operator)
|
132
|
+
!EQUALITY_OPERATORS.include?(node.method_name)
|
131
133
|
end
|
132
134
|
|
133
135
|
def noncommutative_operator?(node)
|
134
|
-
|
135
|
-
NONCOMMUTATIVE_OPERATORS.include?(operator)
|
136
|
+
NONCOMMUTATIVE_OPERATORS.include?(node.method_name)
|
136
137
|
end
|
137
138
|
end
|
138
139
|
end
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -45,11 +45,9 @@ module RuboCop
|
|
45
45
|
while node
|
46
46
|
case node.type
|
47
47
|
when :send
|
48
|
-
|
49
|
-
node = receiver
|
48
|
+
node = node.receiver
|
50
49
|
when :block
|
51
|
-
|
52
|
-
node = method
|
50
|
+
node = node.send_node
|
53
51
|
else
|
54
52
|
break
|
55
53
|
end
|
data/lib/rubocop/file_finder.rb
CHANGED
@@ -13,16 +13,16 @@ module RuboCop
|
|
13
13
|
@root_level == path.to_s
|
14
14
|
end
|
15
15
|
|
16
|
-
def find_file_upwards(filename, start_dir
|
17
|
-
traverse_files_upwards(filename, start_dir
|
16
|
+
def find_file_upwards(filename, start_dir)
|
17
|
+
traverse_files_upwards(filename, start_dir) do |file|
|
18
18
|
# minimize iteration for performance
|
19
19
|
return file if file
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def find_files_upwards(filename, start_dir
|
23
|
+
def find_files_upwards(filename, start_dir)
|
24
24
|
files = []
|
25
|
-
traverse_files_upwards(filename, start_dir
|
25
|
+
traverse_files_upwards(filename, start_dir) do |file|
|
26
26
|
files << file
|
27
27
|
end
|
28
28
|
files
|
@@ -30,18 +30,13 @@ module RuboCop
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
def traverse_files_upwards(filename, start_dir
|
33
|
+
def traverse_files_upwards(filename, start_dir)
|
34
34
|
Pathname.new(start_dir).expand_path.ascend do |dir|
|
35
35
|
break if FileFinder.root_level?(dir)
|
36
36
|
|
37
37
|
file = dir + filename
|
38
38
|
yield(file.to_s) if file.exist?
|
39
39
|
end
|
40
|
-
|
41
|
-
return unless use_home && ENV.key?('HOME')
|
42
|
-
|
43
|
-
file = File.join(Dir.home, filename)
|
44
|
-
yield(file) if File.exist?(file)
|
45
40
|
end
|
46
41
|
end
|
47
42
|
end
|
data/lib/rubocop/node_pattern.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'delegate'
|
4
|
+
require 'erb'
|
5
|
+
|
3
6
|
# rubocop:disable Metrics/ClassLength, Metrics/CyclomaticComplexity
|
4
7
|
module RuboCop
|
5
8
|
# This class performs a pattern-matching operation on an AST node.
|
@@ -38,6 +41,12 @@ module RuboCop
|
|
38
41
|
# '$(send const ...)' # arbitrary matching can be performed on a capture
|
39
42
|
# '(send _recv _msg)' # wildcards can be named (for readability)
|
40
43
|
# '(send ... :new)' # you can match against the last children
|
44
|
+
# '(array <str sym>)' # you can match children in any order. This
|
45
|
+
# # would match `['x', :y]` as well as `[:y, 'x']
|
46
|
+
# '(_ <str sym ...>)' # will match if arguments have at least a `str` and
|
47
|
+
# # a `sym` node, but can have more.
|
48
|
+
# '(array <$str $_>)' # captures are in the order of the pattern,
|
49
|
+
# # irrespective of the actual order of the children
|
41
50
|
# '(send $...)' # capture all the children as an array
|
42
51
|
# '(send $... int)' # capture all children but the last as an array
|
43
52
|
# '(send _x :+ _x)' # unification is performed on named wildcards
|
@@ -97,7 +106,7 @@ module RuboCop
|
|
97
106
|
class Compiler
|
98
107
|
SYMBOL = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
|
99
108
|
IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
|
100
|
-
META =
|
109
|
+
META = Regexp.union(%w"( ) { } [ ] $< < > $... $ ! ^ ...").freeze
|
101
110
|
NUMBER = /-?\d+(?:\.\d+)?/.freeze
|
102
111
|
STRING = /".+?"/.freeze
|
103
112
|
METHOD_NAME = /\#?#{IDENTIFIER}[\!\?]?\(?/.freeze
|
@@ -121,10 +130,36 @@ module RuboCop
|
|
121
130
|
REST = '...'.freeze
|
122
131
|
CAPTURED_REST = '$...'.freeze
|
123
132
|
|
124
|
-
attr_reader :match_code
|
133
|
+
attr_reader :match_code, :tokens, :captures
|
125
134
|
|
126
135
|
SEQ_HEAD_INDEX = -1
|
127
136
|
|
137
|
+
# Placeholders while compiling, see with_..._context methods
|
138
|
+
CUR_PLACEHOLDER = '@@@cur'.freeze
|
139
|
+
CUR_NODE = "#{CUR_PLACEHOLDER} node@@@".freeze
|
140
|
+
CUR_ELEMENT = "#{CUR_PLACEHOLDER} element@@@".freeze
|
141
|
+
SEQ_HEAD_GUARD = '@@@seq guard head@@@'.freeze
|
142
|
+
|
143
|
+
line = __LINE__
|
144
|
+
ANY_ORDER_TEMPLATE = ERB.new <<-RUBY.strip_indent.gsub("-%>\n", '%>')
|
145
|
+
<% if capture_rest %>(<%= capture_rest %> = []) && <% end -%>
|
146
|
+
<% if capture_all %>(<%= capture_all %> = <% end -%>
|
147
|
+
<%= CUR_NODE %>.children[<%= range %>]<% if capture_all %>)<% end -%>
|
148
|
+
.each_with_object({}) { |<%= child %>, <%= matched %>|
|
149
|
+
case
|
150
|
+
<% patterns.each_with_index do |pattern, i| -%>
|
151
|
+
when !<%= matched %>[<%= i %>] && <%=
|
152
|
+
with_context(pattern, child, use_temp_node: false)
|
153
|
+
%> then <%= matched %>[<%= i %>] = true
|
154
|
+
<% end -%>
|
155
|
+
<% if !rest %> else break({})
|
156
|
+
<% elsif capture_rest %> else <%= capture_rest %> << <%= child %>
|
157
|
+
<% end -%>
|
158
|
+
end
|
159
|
+
}.size == <%= patterns.size -%>
|
160
|
+
RUBY
|
161
|
+
ANY_ORDER_TEMPLATE.location = [__FILE__, line + 1]
|
162
|
+
|
128
163
|
def initialize(str, node_var = 'node0')
|
129
164
|
@string = str
|
130
165
|
@root = node_var
|
@@ -133,40 +168,45 @@ module RuboCop
|
|
133
168
|
@captures = 0 # number of captures seen
|
134
169
|
@unify = {} # named wildcard -> temp variable number
|
135
170
|
@params = 0 # highest % (param) number seen
|
136
|
-
|
137
171
|
run(node_var)
|
138
172
|
end
|
139
173
|
|
140
174
|
def run(node_var)
|
141
|
-
tokens = Compiler.tokens(@string)
|
175
|
+
@tokens = Compiler.tokens(@string)
|
142
176
|
|
143
|
-
@match_code = compile_expr
|
177
|
+
@match_code = with_context(compile_expr, node_var, use_temp_node: false)
|
178
|
+
@match_code.prepend("(captures = Array.new(#{@captures})) && ") \
|
179
|
+
if @captures > 0
|
144
180
|
|
145
181
|
fail_due_to('unbalanced pattern') unless tokens.empty?
|
146
182
|
end
|
147
183
|
|
148
184
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
149
|
-
def compile_expr(
|
185
|
+
def compile_expr(token = tokens.shift)
|
150
186
|
# read a single pattern-matching expression from the token stream,
|
151
187
|
# return Ruby code which performs the corresponding matching operation
|
152
|
-
# on 'cur_node' (which is Ruby code which evaluates to an AST node)
|
153
188
|
#
|
154
189
|
# the 'pattern-matching' expression may be a composite which
|
155
|
-
# contains an arbitrary number of sub-expressions
|
156
|
-
|
190
|
+
# contains an arbitrary number of sub-expressions, but that composite
|
191
|
+
# must all have precedence higher or equal to that of `&&`
|
192
|
+
#
|
193
|
+
# Expressions may use placeholders like:
|
194
|
+
# CUR_NODE: Ruby code that evaluates to an AST node
|
195
|
+
# CUR_ELEMENT: Either the node or the type if in first element of
|
196
|
+
# a sequence (aka seq_head, e.g. "(seq_head first_node_arg ...")
|
157
197
|
case token
|
158
|
-
when '(' then compile_seq
|
159
|
-
when '{' then compile_union
|
160
|
-
when '[' then compile_intersect
|
161
|
-
when '!' then compile_negation
|
162
|
-
when '$' then compile_capture
|
163
|
-
when '^' then compile_ascend
|
164
|
-
when WILDCARD then compile_wildcard(
|
165
|
-
when FUNCALL then compile_funcall(
|
166
|
-
when LITERAL then compile_literal(
|
167
|
-
when PREDICATE then compile_predicate(
|
168
|
-
when NODE then compile_nodetype(
|
169
|
-
when PARAM then compile_param(
|
198
|
+
when '(' then compile_seq
|
199
|
+
when '{' then compile_union
|
200
|
+
when '[' then compile_intersect
|
201
|
+
when '!' then compile_negation
|
202
|
+
when '$' then compile_capture
|
203
|
+
when '^' then compile_ascend
|
204
|
+
when WILDCARD then compile_wildcard(token[1..-1])
|
205
|
+
when FUNCALL then compile_funcall(token)
|
206
|
+
when LITERAL then compile_literal(token)
|
207
|
+
when PREDICATE then compile_predicate(token)
|
208
|
+
when NODE then compile_nodetype(token)
|
209
|
+
when PARAM then compile_param(token[1..-1])
|
170
210
|
when CLOSING then fail_due_to("#{token} in invalid position")
|
171
211
|
when nil then fail_due_to('pattern ended prematurely')
|
172
212
|
else fail_due_to("invalid token #{token.inspect}")
|
@@ -174,211 +214,260 @@ module RuboCop
|
|
174
214
|
end
|
175
215
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
176
216
|
|
177
|
-
def
|
178
|
-
|
179
|
-
fail_due_to('parentheses at sequence head') if seq_head
|
217
|
+
def tokens_until(stop, what)
|
218
|
+
return to_enum __method__, stop, what unless block_given?
|
180
219
|
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
with_temp_node(cur_node) do |init, temp_node|
|
186
|
-
terms = compile_seq_terms(tokens, temp_node)
|
187
|
-
terms.unshift(compile_guard_clause(temp_node))
|
220
|
+
fail_due_to("empty #{what}") if tokens.first == stop && what
|
221
|
+
yield until tokens.first == stop
|
222
|
+
tokens.shift
|
223
|
+
end
|
188
224
|
|
189
|
-
|
190
|
-
|
225
|
+
def compile_seq
|
226
|
+
terms = tokens_until(')', 'sequence').map { variadic_seq_term }
|
227
|
+
Sequence.new(self, *terms).compile
|
191
228
|
end
|
192
229
|
|
193
|
-
def compile_guard_clause
|
194
|
-
"#{
|
230
|
+
def compile_guard_clause
|
231
|
+
"#{CUR_NODE}.is_a?(RuboCop::AST::Node)"
|
195
232
|
end
|
196
233
|
|
197
|
-
def
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
ret << "(#{cur_node}.children.size == #{ret.size - 1})"
|
234
|
+
def variadic_seq_term
|
235
|
+
token = tokens.shift
|
236
|
+
case token
|
237
|
+
when CAPTURED_REST then compile_captured_ellipsis
|
238
|
+
when REST then compile_ellipsis
|
239
|
+
when '$<' then compile_any_order(next_capture)
|
240
|
+
when '<' then compile_any_order
|
241
|
+
else [1, compile_expr(token)]
|
242
|
+
end
|
207
243
|
end
|
208
244
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
245
|
+
# @private
|
246
|
+
# Builds Ruby code for a sequence
|
247
|
+
# (head *first_terms variadic_term *last_terms)
|
248
|
+
class Sequence < SimpleDelegator
|
249
|
+
def initialize(compiler, *arity_term_list)
|
250
|
+
@arities, @terms = arity_term_list.transpose
|
251
|
+
|
252
|
+
super(compiler)
|
253
|
+
@variadic_index = @arities.find_index { |a| a.is_a?(Range) }
|
254
|
+
fail_due_to 'multiple variable patterns in same sequence' \
|
255
|
+
if @variadic_index && !@arities.one? { |a| a.is_a?(Range) }
|
217
256
|
end
|
218
257
|
|
219
|
-
|
220
|
-
|
221
|
-
|
258
|
+
def compile
|
259
|
+
[
|
260
|
+
compile_guard_clause,
|
261
|
+
compile_child_nb_guard,
|
262
|
+
compile_seq_head,
|
263
|
+
*compile_first_terms,
|
264
|
+
compile_variadic_term,
|
265
|
+
*compile_last_terms
|
266
|
+
].compact.join(" &&\n") << SEQ_HEAD_GUARD
|
267
|
+
end
|
222
268
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
# grep for seq_head to see where it makes a difference
|
228
|
-
compile_expr(tokens, cur_node, true)
|
229
|
-
else
|
230
|
-
child_node = "#{cur_node}.children[#{index}]"
|
231
|
-
compile_expr(tokens, child_node, false)
|
269
|
+
private
|
270
|
+
|
271
|
+
def first_terms_arity
|
272
|
+
first_terms_range { |r| @arities[r].inject(0, :+) } || 0
|
232
273
|
end
|
233
|
-
end
|
234
274
|
|
235
|
-
|
236
|
-
|
237
|
-
tail = compile_seq_tail(tokens, cur_node)
|
238
|
-
terms << "(#{cur_node}.children.size >= #{index + tail.size})"
|
239
|
-
terms.concat tail
|
240
|
-
if capture
|
241
|
-
range = index..-tail.size - 1
|
242
|
-
terms << "(#{capture} = #{cur_node}.children[#{range}])"
|
275
|
+
def last_terms_arity
|
276
|
+
last_terms_range { |r| @arities[r].inject(0, :+) } || 0
|
243
277
|
end
|
244
|
-
terms
|
245
|
-
end
|
246
278
|
|
247
|
-
|
248
|
-
|
249
|
-
terms = []
|
250
|
-
until tokens.first == ')'
|
251
|
-
terms << compile_expr(tokens, child_node, false)
|
279
|
+
def first_terms_range
|
280
|
+
yield 1..(@variadic_index || @terms.size) - 1 if seq_head?
|
252
281
|
end
|
253
|
-
tokens.shift # drop ')'
|
254
|
-
# E.g. for terms.size == 3, we want to replace the three [%<revindex>i]
|
255
|
-
# with [-3], [-2] and [-1]
|
256
|
-
terms.map.with_index { |term, i| format term, revindex: i - terms.size }
|
257
|
-
end
|
258
282
|
|
259
|
-
|
260
|
-
|
283
|
+
def last_terms_range
|
284
|
+
yield @variadic_index + 1...@terms.size if @variadic_index
|
285
|
+
end
|
261
286
|
|
262
|
-
|
263
|
-
|
264
|
-
join_terms(init, terms, ' || ')
|
287
|
+
def seq_head?
|
288
|
+
@variadic_index != 0
|
265
289
|
end
|
266
|
-
end
|
267
290
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
291
|
+
def compile_child_nb_guard
|
292
|
+
min = first_terms_arity + last_terms_arity
|
293
|
+
"#{CUR_NODE}.children.size #{@variadic_index ? '>' : '='}= #{min}"
|
294
|
+
end
|
295
|
+
|
296
|
+
def term(index, range)
|
297
|
+
t = @terms[index]
|
298
|
+
if t.respond_to? :call
|
299
|
+
t.call(range)
|
300
|
+
else
|
301
|
+
with_child_context(t, range.begin)
|
279
302
|
end
|
280
|
-
|
303
|
+
end
|
304
|
+
|
305
|
+
def compile_seq_head
|
306
|
+
return unless seq_head?
|
307
|
+
|
308
|
+
fail_due_to 'sequences can not start with <' \
|
309
|
+
if @terms[0].respond_to? :call
|
281
310
|
|
282
|
-
terms
|
311
|
+
with_seq_head_context(@terms[0])
|
283
312
|
end
|
284
|
-
end
|
285
313
|
|
286
|
-
|
287
|
-
|
288
|
-
|
314
|
+
def compile_first_terms
|
315
|
+
first_terms_range { |range| compile_terms(range, 0) }
|
316
|
+
end
|
289
317
|
|
290
|
-
|
291
|
-
|
318
|
+
def compile_last_terms
|
319
|
+
last_terms_range { |r| compile_terms(r, -last_terms_arity) }
|
320
|
+
end
|
292
321
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
322
|
+
def compile_terms(index_range, start)
|
323
|
+
index_range.map do |i|
|
324
|
+
current = start
|
325
|
+
start += @arities.fetch(i)
|
326
|
+
term(i, current..start - 1)
|
327
|
+
end
|
299
328
|
end
|
300
329
|
|
301
|
-
|
302
|
-
|
330
|
+
def compile_variadic_term
|
331
|
+
variadic_arity { |arity| term(@variadic_index, arity) }
|
332
|
+
end
|
303
333
|
|
304
|
-
|
305
|
-
|
334
|
+
def variadic_arity
|
335
|
+
return unless @variadic_index
|
306
336
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
337
|
+
first = @variadic_index > 0 ? first_terms_arity : SEQ_HEAD_INDEX
|
338
|
+
yield first..-last_terms_arity - 1
|
339
|
+
end
|
340
|
+
end
|
341
|
+
private_constant :Sequence
|
342
|
+
|
343
|
+
def compile_captured_ellipsis
|
344
|
+
capture = next_capture
|
345
|
+
block = lambda { |range|
|
346
|
+
# Consider ($...) like (_ $...):
|
347
|
+
range = 0..range.end if range.begin == SEQ_HEAD_INDEX
|
348
|
+
"(#{capture} = #{CUR_NODE}.children[#{range}])"
|
349
|
+
}
|
350
|
+
[0..Float::INFINITY, block]
|
351
|
+
end
|
352
|
+
|
353
|
+
def compile_ellipsis
|
354
|
+
[0..Float::INFINITY, 'true']
|
355
|
+
end
|
356
|
+
|
357
|
+
# rubocop:disable Metrics/MethodLength
|
358
|
+
def compile_any_order(capture_all = nil)
|
359
|
+
rest = capture_rest = nil
|
360
|
+
patterns = []
|
361
|
+
with_temp_variables do |child, matched|
|
362
|
+
tokens_until('>', 'any child').each do
|
363
|
+
fail_due_to 'ellipsis must be at the end of <>' if rest
|
364
|
+
token = tokens.shift
|
365
|
+
case token
|
366
|
+
when CAPTURED_REST then rest = capture_rest = next_capture
|
367
|
+
when REST then rest = true
|
368
|
+
else patterns << compile_expr(token)
|
369
|
+
end
|
311
370
|
end
|
312
|
-
|
371
|
+
[rest ? patterns.size..Float::INFINITY : patterns.size,
|
372
|
+
->(range) { ANY_ORDER_TEMPLATE.result(binding) }]
|
373
|
+
end
|
374
|
+
end
|
375
|
+
# rubocop:enable Metrics/MethodLength
|
376
|
+
|
377
|
+
def insure_same_captures(enum, what)
|
378
|
+
return to_enum __method__, enum, what unless block_given?
|
313
379
|
|
314
|
-
|
380
|
+
captures_before = captures_after = nil
|
381
|
+
enum.each do
|
382
|
+
captures_before ||= @captures
|
383
|
+
@captures = captures_before
|
384
|
+
yield
|
385
|
+
captures_after ||= @captures
|
386
|
+
if captures_after != @captures
|
387
|
+
fail_due_to("each #{what} must have same # of captures")
|
388
|
+
end
|
315
389
|
end
|
316
390
|
end
|
317
391
|
|
318
|
-
def
|
319
|
-
|
320
|
-
|
392
|
+
def compile_union
|
393
|
+
# we need to ensure that each branch of the {} contains the same
|
394
|
+
# number of captures (since only one branch of the {} can actually
|
395
|
+
# match, the same variables are used to hold the captures for each
|
396
|
+
# branch)
|
397
|
+
enum = tokens_until('}', 'union')
|
398
|
+
terms = insure_same_captures(enum, 'branch of {}')
|
399
|
+
.map { compile_expr }
|
400
|
+
|
401
|
+
"(#{terms.join(' || ')})"
|
402
|
+
end
|
403
|
+
|
404
|
+
def compile_intersect
|
405
|
+
tokens_until(']', 'intersection')
|
406
|
+
.map { compile_expr }
|
407
|
+
.join(' && ')
|
321
408
|
end
|
322
409
|
|
323
|
-
def
|
324
|
-
"(
|
410
|
+
def compile_capture
|
411
|
+
"(#{next_capture} = #{CUR_ELEMENT}; #{compile_expr})"
|
325
412
|
end
|
326
413
|
|
327
|
-
def
|
328
|
-
"(#{
|
329
|
-
"#{compile_expr(tokens, "#{cur_node}.parent", seq_head)})"
|
414
|
+
def compile_negation
|
415
|
+
"!(#{compile_expr})"
|
330
416
|
end
|
331
417
|
|
332
|
-
def
|
418
|
+
def compile_ascend
|
419
|
+
with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
|
420
|
+
end
|
421
|
+
|
422
|
+
def compile_wildcard(name)
|
333
423
|
if name.empty?
|
334
424
|
'true'
|
335
425
|
elsif @unify.key?(name)
|
336
426
|
# we have already seen a wildcard with this name before
|
337
427
|
# so the value it matched the first time will already be stored
|
338
428
|
# in a temp. check if this value matches the one stored in the temp
|
339
|
-
"
|
429
|
+
"#{CUR_ELEMENT} == temp#{@unify[name]}"
|
340
430
|
else
|
341
431
|
n = @unify[name] = next_temp_value
|
342
432
|
# double assign to temp#{n} to avoid "assigned but unused variable"
|
343
|
-
"(temp#{n} = #{
|
433
|
+
"(temp#{n} = #{CUR_ELEMENT}; " \
|
344
434
|
"temp#{n} = temp#{n}; true)"
|
345
435
|
end
|
346
436
|
end
|
347
437
|
|
348
|
-
def compile_literal(
|
349
|
-
"
|
438
|
+
def compile_literal(literal)
|
439
|
+
"#{CUR_ELEMENT} == #{literal}"
|
350
440
|
end
|
351
441
|
|
352
|
-
def compile_predicate(
|
442
|
+
def compile_predicate(predicate)
|
353
443
|
if predicate.end_with?('(') # is there an arglist?
|
354
444
|
args = compile_args(tokens)
|
355
445
|
predicate = predicate[0..-2] # drop the trailing (
|
356
|
-
"
|
446
|
+
"#{CUR_ELEMENT}.#{predicate}(#{args.join(',')})"
|
357
447
|
else
|
358
|
-
"
|
448
|
+
"#{CUR_ELEMENT}.#{predicate}"
|
359
449
|
end
|
360
450
|
end
|
361
451
|
|
362
|
-
def compile_funcall(
|
452
|
+
def compile_funcall(method)
|
363
453
|
# call a method in the context which this pattern-matching
|
364
454
|
# code is used in. pass target value as an argument
|
365
455
|
method = method[1..-1] # drop the leading #
|
366
456
|
if method.end_with?('(') # is there an arglist?
|
367
457
|
args = compile_args(tokens)
|
368
458
|
method = method[0..-2] # drop the trailing (
|
369
|
-
"
|
459
|
+
"#{method}(#{CUR_ELEMENT},#{args.join(',')})"
|
370
460
|
else
|
371
|
-
"
|
461
|
+
"#{method}(#{CUR_ELEMENT})"
|
372
462
|
end
|
373
463
|
end
|
374
464
|
|
375
|
-
def compile_nodetype(
|
376
|
-
"
|
377
|
-
"#{cur_node}.#{type.tr('-', '_')}_type?)"
|
465
|
+
def compile_nodetype(type)
|
466
|
+
"#{compile_guard_clause} && #{CUR_NODE}.#{type.tr('-', '_')}_type?"
|
378
467
|
end
|
379
468
|
|
380
|
-
def compile_param(
|
381
|
-
"
|
469
|
+
def compile_param(number)
|
470
|
+
"#{CUR_ELEMENT} == #{get_param(number)}"
|
382
471
|
end
|
383
472
|
|
384
473
|
def compile_args(tokens)
|
@@ -406,7 +495,9 @@ module RuboCop
|
|
406
495
|
end
|
407
496
|
|
408
497
|
def next_capture
|
409
|
-
|
498
|
+
index = @captures
|
499
|
+
@captures += 1
|
500
|
+
"captures[#{index}]"
|
410
501
|
end
|
411
502
|
|
412
503
|
def get_param(number)
|
@@ -415,21 +506,24 @@ module RuboCop
|
|
415
506
|
number.zero? ? @root : "param#{number}"
|
416
507
|
end
|
417
508
|
|
418
|
-
def
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
509
|
+
def emit_yield_capture(when_no_capture = '')
|
510
|
+
yield_val = if @captures.zero?
|
511
|
+
when_no_capture
|
512
|
+
elsif @captures == 1
|
513
|
+
'captures[0]' # Circumvent https://github.com/jruby/jruby/issues/5710
|
514
|
+
else
|
515
|
+
'*captures'
|
516
|
+
end
|
517
|
+
"yield(#{yield_val})"
|
424
518
|
end
|
425
519
|
|
426
520
|
def emit_retval
|
427
521
|
if @captures.zero?
|
428
522
|
'true'
|
429
523
|
elsif @captures == 1
|
430
|
-
'
|
524
|
+
'captures[0]'
|
431
525
|
else
|
432
|
-
|
526
|
+
'captures'
|
433
527
|
end
|
434
528
|
end
|
435
529
|
|
@@ -445,7 +539,7 @@ module RuboCop
|
|
445
539
|
def emit_method_code
|
446
540
|
<<-RUBY
|
447
541
|
return unless #{@match_code}
|
448
|
-
block_given? ?
|
542
|
+
block_given? ? #{emit_yield_capture} : (return #{emit_retval})
|
449
543
|
RUBY
|
450
544
|
end
|
451
545
|
|
@@ -454,20 +548,62 @@ module RuboCop
|
|
454
548
|
end
|
455
549
|
|
456
550
|
def with_temp_node(cur_node)
|
457
|
-
|
458
|
-
#
|
459
|
-
yield "#{temp_var} = #{cur_node}; #{temp_var} = #{temp_var}", temp_var
|
551
|
+
with_temp_variables do |node|
|
552
|
+
yield "(#{node} = #{cur_node})", node
|
460
553
|
end
|
554
|
+
.gsub("\n", "\n ") # Nicer indent for debugging
|
461
555
|
end
|
462
556
|
|
463
|
-
def
|
464
|
-
|
557
|
+
def with_temp_variables(&block)
|
558
|
+
names = block.parameters.map { |_, name| "#{name}#{next_temp_value}" }
|
559
|
+
yield(*names)
|
465
560
|
end
|
466
561
|
|
467
562
|
def next_temp_value
|
468
563
|
@temps += 1
|
469
564
|
end
|
470
565
|
|
566
|
+
def auto_use_temp_node?(code)
|
567
|
+
code.scan(CUR_PLACEHOLDER).count > 1
|
568
|
+
end
|
569
|
+
|
570
|
+
# with_<...>_context methods are used whenever the context,
|
571
|
+
# i.e the current node or the current element can be determined.
|
572
|
+
|
573
|
+
def with_child_context(code, child_index)
|
574
|
+
with_context(code, "#{CUR_NODE}.children[#{child_index}]")
|
575
|
+
end
|
576
|
+
|
577
|
+
def with_context(code, cur_node,
|
578
|
+
use_temp_node: auto_use_temp_node?(code))
|
579
|
+
if use_temp_node
|
580
|
+
with_temp_node(cur_node) do |init, temp_var|
|
581
|
+
substitute_cur_node(code, temp_var, first_cur_node: init)
|
582
|
+
end
|
583
|
+
else
|
584
|
+
substitute_cur_node(code, cur_node)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
def with_seq_head_context(code)
|
589
|
+
if code.include?(SEQ_HEAD_GUARD)
|
590
|
+
fail_due_to('parentheses at sequence head')
|
591
|
+
end
|
592
|
+
|
593
|
+
code.gsub CUR_ELEMENT, "#{CUR_NODE}.type"
|
594
|
+
end
|
595
|
+
|
596
|
+
def substitute_cur_node(code, cur_node, first_cur_node: cur_node)
|
597
|
+
iter = 0
|
598
|
+
code
|
599
|
+
.gsub(CUR_ELEMENT, CUR_NODE)
|
600
|
+
.gsub(CUR_NODE) do
|
601
|
+
iter += 1
|
602
|
+
iter == 1 ? first_cur_node : cur_node
|
603
|
+
end
|
604
|
+
.gsub(SEQ_HEAD_GUARD, '')
|
605
|
+
end
|
606
|
+
|
471
607
|
def self.tokens(pattern)
|
472
608
|
pattern.scan(TOKEN).reject { |token| token =~ /\A#{SEPARATORS}\Z/ }
|
473
609
|
end
|
@@ -515,13 +651,11 @@ module RuboCop
|
|
515
651
|
end
|
516
652
|
|
517
653
|
def node_search_all(method_name, compiler, called_from)
|
518
|
-
|
519
|
-
yieldval = 'node' if yieldval.empty?
|
654
|
+
yield_code = compiler.emit_yield_capture('node')
|
520
655
|
prelude = "return enum_for(:#{method_name}, node0" \
|
521
656
|
"#{compiler.emit_trailing_params}) unless block_given?"
|
522
657
|
|
523
|
-
node_search(method_name, compiler,
|
524
|
-
called_from)
|
658
|
+
node_search(method_name, compiler, yield_code, prelude, called_from)
|
525
659
|
end
|
526
660
|
|
527
661
|
def node_search(method_name, compiler, on_match, prelude, called_from)
|