rubocop 1.1.0 → 1.4.1
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 +29 -12
- data/config/default.yml +113 -16
- data/exe/rubocop +1 -1
- data/lib/rubocop.rb +9 -0
- data/lib/rubocop/cli/command/execute_runner.rb +26 -11
- data/lib/rubocop/config_loader.rb +14 -5
- data/lib/rubocop/config_regeneration.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/commissioner.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
- data/lib/rubocop/cop/generator.rb +2 -9
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/class_structure.rb +15 -3
- data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +77 -7
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
- data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/line_length.rb +8 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +26 -2
- data/lib/rubocop/cop/lint/debugger.rb +17 -27
- data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
- data/lib/rubocop/cop/lint/else_layout.rb +29 -3
- data/lib/rubocop/cop/lint/empty_block.rb +38 -2
- data/lib/rubocop/cop/lint/empty_class.rb +93 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +22 -4
- data/lib/rubocop/cop/lint/loop.rb +4 -4
- data/lib/rubocop/cop/lint/missing_super.rb +7 -4
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
- data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +6 -15
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +13 -4
- data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
- data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +11 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
- data/lib/rubocop/cop/naming/variable_number.rb +98 -8
- data/lib/rubocop/cop/style/and_or.rb +1 -3
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
- data/lib/rubocop/cop/style/case_like_if.rb +0 -4
- data/lib/rubocop/cop/style/collection_compact.rb +91 -0
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +107 -5
- data/lib/rubocop/cop/style/documentation.rb +12 -1
- data/lib/rubocop/cop/style/double_negation.rb +6 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +7 -3
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +3 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +106 -0
- data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
- data/lib/rubocop/cop/style/raise_args.rb +21 -6
- data/lib/rubocop/cop/style/redundant_argument.rb +73 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +97 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
- data/lib/rubocop/cop/util.rb +5 -1
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +10 -5
- data/lib/rubocop/ext/regexp_parser.rb +9 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
- data/lib/rubocop/options.rb +7 -0
- data/lib/rubocop/rake_task.rb +2 -2
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +65 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +14 -8
- data/bin/console +0 -10
- data/bin/rubocop-profile +0 -32
- data/bin/setup +0 -7
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for the presence of a `return` inside a `begin..end` block
|
7
|
+
# in assignment contexts.
|
8
|
+
# In this situation, the `return` will result in an exit from the current
|
9
|
+
# method, possibly leading to unexpected behavior.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
#
|
15
|
+
# @some_variable ||= begin
|
16
|
+
# return some_value if some_condition_is_met
|
17
|
+
#
|
18
|
+
# do_something
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
#
|
25
|
+
# @some_variable ||= begin
|
26
|
+
# if some_condition_is_met
|
27
|
+
# some_value
|
28
|
+
# else
|
29
|
+
# do_something
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # good
|
34
|
+
#
|
35
|
+
# some_variable = if some_condition_is_met
|
36
|
+
# return if another_condition_is_met
|
37
|
+
#
|
38
|
+
# some_value
|
39
|
+
# else
|
40
|
+
# do_something
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
class NoReturnInBeginEndBlocks < Cop
|
44
|
+
MSG = 'Do not `return` in `begin..end` blocks in assignment contexts.'
|
45
|
+
|
46
|
+
def on_lvasgn(node)
|
47
|
+
node.each_node(:kwbegin) do |kwbegin_node|
|
48
|
+
kwbegin_node.each_node(:return) do |return_node|
|
49
|
+
add_offense(return_node)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias on_or_asgn on_lvasgn
|
54
|
+
alias on_op_asgn on_lvasgn
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -88,31 +88,34 @@ module RuboCop
|
|
88
88
|
begin_pos = reposition(source, begin_pos, -1)
|
89
89
|
end_pos = reposition(source, end_pos, 1)
|
90
90
|
|
91
|
-
|
92
|
-
if source[begin_pos - 1] == ','
|
93
|
-
:before
|
94
|
-
elsif source[end_pos] == ','
|
95
|
-
:after
|
96
|
-
else
|
97
|
-
:none
|
98
|
-
end
|
99
|
-
|
100
|
-
range_to_remove(begin_pos, end_pos, comma_pos, comment)
|
91
|
+
range_to_remove(begin_pos, end_pos, comment)
|
101
92
|
end
|
102
93
|
|
103
|
-
def range_to_remove(begin_pos, end_pos,
|
94
|
+
def range_to_remove(begin_pos, end_pos, comment)
|
104
95
|
start = comment_start(comment)
|
96
|
+
source = comment.loc.expression.source
|
105
97
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
range_between(start + begin_pos, start + end_pos + 1)
|
98
|
+
if source[begin_pos - 1] == ','
|
99
|
+
range_with_comma_before(start, begin_pos, end_pos)
|
100
|
+
elsif source[end_pos] == ','
|
101
|
+
range_with_comma_after(comment, start, begin_pos, end_pos)
|
111
102
|
else
|
112
103
|
range_between(start, comment.loc.expression.end_pos)
|
113
104
|
end
|
114
105
|
end
|
115
106
|
|
107
|
+
def range_with_comma_before(start, begin_pos, end_pos)
|
108
|
+
range_between(start + begin_pos - 1, start + end_pos)
|
109
|
+
end
|
110
|
+
|
111
|
+
# If the list of cops is comma-separated, but without a empty space after the comma,
|
112
|
+
# we should **not** remove the prepending empty space, thus begin_pos += 1
|
113
|
+
def range_with_comma_after(comment, start, begin_pos, end_pos)
|
114
|
+
begin_pos += 1 if comment.loc.expression.source[end_pos + 1] != ' '
|
115
|
+
|
116
|
+
range_between(start + begin_pos, start + end_pos + 1)
|
117
|
+
end
|
118
|
+
|
116
119
|
def all_or_name(name)
|
117
120
|
name == 'all' ? 'all cops' : name
|
118
121
|
end
|
@@ -140,11 +140,10 @@ module RuboCop
|
|
140
140
|
rescued_groups.each_cons(2).all? do |x, y|
|
141
141
|
if x.include?(Exception)
|
142
142
|
false
|
143
|
-
elsif y.include?(Exception)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
# `nil`s
|
143
|
+
elsif y.include?(Exception) ||
|
144
|
+
# consider sorted if a group is empty or only contains
|
145
|
+
# `nil`s
|
146
|
+
x.none? || y.none?
|
148
147
|
true
|
149
148
|
else
|
150
149
|
(x <=> y || 0) <= 0
|
@@ -8,23 +8,14 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
# # bad
|
11
|
-
# def
|
12
|
-
# return to_enum(
|
11
|
+
# def foo(x, y = 1)
|
12
|
+
# return to_enum(__callee__, x) # `y` is missing
|
13
13
|
# end
|
14
14
|
#
|
15
15
|
# # good
|
16
|
-
# def
|
17
|
-
# return to_enum(
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# # bad
|
21
|
-
# def method(required:)
|
22
|
-
# return to_enum(:method, required: something) # `required` has incorrect value
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# # good
|
26
|
-
# def method(required:)
|
27
|
-
# return to_enum(:method, required: required)
|
16
|
+
# def foo(x, y = 1)
|
17
|
+
# return to_enum(__callee__, x, y)
|
18
|
+
# # alternatives to `__callee__` are `__method__` and `:foo`
|
28
19
|
# end
|
29
20
|
#
|
30
21
|
class ToEnumArguments < Base
|
@@ -37,7 +28,7 @@ module RuboCop
|
|
37
28
|
PATTERN
|
38
29
|
|
39
30
|
def_node_matcher :method_name?, <<~PATTERN
|
40
|
-
{(send nil? :__method__) (sym %1)}
|
31
|
+
{(send nil? {:__method__ :__callee__}) (sym %1)}
|
41
32
|
PATTERN
|
42
33
|
|
43
34
|
def_node_matcher :passing_keyword_arg?, <<~PATTERN
|
@@ -54,6 +54,9 @@ module RuboCop
|
|
54
54
|
# value
|
55
55
|
# end
|
56
56
|
#
|
57
|
+
# # good, recursive
|
58
|
+
# keys.reduce(self) { |result, key| result[key] }
|
59
|
+
#
|
57
60
|
# # ignored as the return value cannot be determined
|
58
61
|
# enum.reduce do |acc, el|
|
59
62
|
# x = foo(acc, el)
|
@@ -131,7 +134,7 @@ module RuboCop
|
|
131
134
|
element_name = block_arg_name(block_node, 1)
|
132
135
|
message_opts = { method: block_node.method_name, accum: accumulator_name }
|
133
136
|
|
134
|
-
if (node = returned_accumulator_index(return_values, accumulator_name))
|
137
|
+
if (node = returned_accumulator_index(return_values, accumulator_name, element_name))
|
135
138
|
add_offense(node, message: format(MSG_INDEX, message_opts))
|
136
139
|
elsif potential_offense?(return_values, block_node.body, element_name, accumulator_name)
|
137
140
|
return_values.each do |return_val|
|
@@ -146,11 +149,17 @@ module RuboCop
|
|
146
149
|
node.arguments[index].node_parts[0]
|
147
150
|
end
|
148
151
|
|
149
|
-
# Look for an index of the accumulator being returned
|
152
|
+
# Look for an index of the accumulator being returned, except where the index
|
153
|
+
# is the element.
|
150
154
|
# This is always an offense, in order to try to catch potential exceptions
|
151
155
|
# due to type mismatches
|
152
|
-
def returned_accumulator_index(return_values, accumulator_name)
|
153
|
-
return_values.detect
|
156
|
+
def returned_accumulator_index(return_values, accumulator_name, element_name)
|
157
|
+
return_values.detect do |val|
|
158
|
+
next unless accumulator_index?(val, accumulator_name)
|
159
|
+
next true if val.method?(:[]=)
|
160
|
+
|
161
|
+
val.arguments.none? { |arg| lvar_used?(arg, element_name) }
|
162
|
+
end
|
154
163
|
end
|
155
164
|
|
156
165
|
def potential_offense?(return_values, block_body, element_name, accumulator_name)
|
@@ -54,11 +54,9 @@ module RuboCop
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def delegating?(node, def_node)
|
57
|
-
if node
|
58
|
-
false
|
59
|
-
elsif node.zsuper_type?
|
57
|
+
if node&.zsuper_type?
|
60
58
|
true
|
61
|
-
elsif node
|
59
|
+
elsif node&.super_type?
|
62
60
|
node.arguments.map(&:source) == def_node.arguments.map(&:source)
|
63
61
|
else
|
64
62
|
false
|
@@ -5,6 +5,7 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for setter call to local variable as the final
|
7
7
|
# expression of a function definition.
|
8
|
+
# Its auto-correction is marked as unsafe because return value will be changed.
|
8
9
|
#
|
9
10
|
# NOTE: There are edge cases in which the local variable references a
|
10
11
|
# value that is also accessible outside the local scope. This is not
|
@@ -29,6 +30,8 @@ module RuboCop
|
|
29
30
|
# x
|
30
31
|
# end
|
31
32
|
class UselessSetterCall < Base
|
33
|
+
extend AutoCorrector
|
34
|
+
|
32
35
|
MSG = 'Useless setter call to local variable `%<variable>s`.'
|
33
36
|
ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
|
34
37
|
|
@@ -45,7 +48,9 @@ module RuboCop
|
|
45
48
|
|
46
49
|
loc_name = receiver.loc.name
|
47
50
|
|
48
|
-
add_offense(loc_name, message: format(MSG, variable: loc_name.source))
|
51
|
+
add_offense(loc_name, message: format(MSG, variable: loc_name.source)) do |corrector|
|
52
|
+
corrector.insert_after(last_expr, "\n#{indent(last_expr)}#{loc_name.source}")
|
53
|
+
end
|
49
54
|
end
|
50
55
|
alias on_defs on_def
|
51
56
|
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
|
37
37
|
def on_def(node)
|
38
38
|
excluded_methods = cop_config['ExcludedMethods']
|
39
|
-
return if excluded_methods.
|
39
|
+
return if excluded_methods.any? { |m| m.match? String(node.method_name) }
|
40
40
|
|
41
41
|
check_code_length(node)
|
42
42
|
end
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
103
103
|
# hashes wrapped in a set of curly braces like {foo: 1}.
|
104
104
|
# That is, not a kwargs hash. For method calls, this ensures
|
105
105
|
# the method call is made with parens.
|
106
|
-
starts_with_bracket = node.loc.begin
|
106
|
+
starts_with_bracket = !node.hash_type? || node.loc.begin
|
107
107
|
|
108
108
|
# If the call has a second argument, we can insert a line
|
109
109
|
# break before the second argument and the rest of the
|
@@ -8,9 +8,9 @@ module RuboCop
|
|
8
8
|
include ConfigurableFormatting
|
9
9
|
|
10
10
|
FORMATS = {
|
11
|
-
snake_case: /(
|
12
|
-
normalcase: /(
|
13
|
-
non_integer: /
|
11
|
+
snake_case: /(?:\D|_\d+|\A\d+)\z/,
|
12
|
+
normalcase: /(?:\D|[^_\d]\d+|\A\d+)\z/,
|
13
|
+
non_integer: /(\D|\A\d+)\z/
|
14
14
|
}.freeze
|
15
15
|
end
|
16
16
|
end
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
# b c { block }. <-- b is indented relative to a
|
32
32
|
# d <-- d is indented relative to a
|
33
33
|
def left_hand_side(lhs)
|
34
|
-
lhs = lhs.parent while lhs.parent&.send_type?
|
34
|
+
lhs = lhs.parent while lhs.parent&.send_type? && lhs.parent.loc.dot
|
35
35
|
lhs
|
36
36
|
end
|
37
37
|
|
@@ -19,7 +19,8 @@ module RuboCop
|
|
19
19
|
def non_eligible_node?(node)
|
20
20
|
node.modifier_form? ||
|
21
21
|
node.nonempty_line_count > 3 ||
|
22
|
-
processed_source.line_with_comment?(node.loc.last_line)
|
22
|
+
processed_source.line_with_comment?(node.loc.last_line) ||
|
23
|
+
(first_line_comment(node) && code_after(node))
|
23
24
|
end
|
24
25
|
|
25
26
|
def non_eligible_body?(body)
|
@@ -41,11 +42,9 @@ module RuboCop
|
|
41
42
|
|
42
43
|
def length_in_modifier_form(node)
|
43
44
|
keyword_element = node.loc.keyword
|
44
|
-
end_element = node.loc.end
|
45
45
|
code_before = keyword_element.source_line[0...keyword_element.column]
|
46
|
-
code_after = end_element.source_line[end_element.last_column..-1]
|
47
46
|
expression = to_modifier_form(node)
|
48
|
-
line_length("#{code_before}#{expression}#{code_after}")
|
47
|
+
line_length("#{code_before}#{expression}#{code_after(node)}")
|
49
48
|
end
|
50
49
|
|
51
50
|
def to_modifier_form(node)
|
@@ -64,6 +63,12 @@ module RuboCop
|
|
64
63
|
comment_source unless comment_disables_cop?(comment_source)
|
65
64
|
end
|
66
65
|
|
66
|
+
def code_after(node)
|
67
|
+
end_element = node.loc.end
|
68
|
+
code = end_element.source_line[end_element.last_column..-1]
|
69
|
+
code unless code.empty?
|
70
|
+
end
|
71
|
+
|
67
72
|
def parenthesize?(node)
|
68
73
|
# Parenthesize corrected expression if changing to modifier-if form
|
69
74
|
# would change the meaning of the parent expression
|
@@ -16,9 +16,7 @@ module RuboCop
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def find_visibility_start(node)
|
19
|
-
node.left_siblings
|
20
|
-
.reverse
|
21
|
-
.find(&method(:visibility_block?))
|
19
|
+
node.left_siblings.reverse.find { |sibling| visibility_block?(sibling) }
|
22
20
|
end
|
23
21
|
|
24
22
|
# Navigate to find the last protected method
|
@@ -14,6 +14,8 @@ module RuboCop
|
|
14
14
|
# # good
|
15
15
|
# def +(other); end
|
16
16
|
class BinaryOperatorParameterName < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
17
19
|
MSG = 'When defining the `%<opr>s` operator, ' \
|
18
20
|
'name its argument `other`.'
|
19
21
|
|
@@ -26,7 +28,15 @@ module RuboCop
|
|
26
28
|
|
27
29
|
def on_def(node)
|
28
30
|
op_method_candidate?(node) do |name, arg|
|
29
|
-
add_offense(arg, message: format(MSG, opr: name))
|
31
|
+
add_offense(arg, message: format(MSG, opr: name)) do |corrector|
|
32
|
+
corrector.replace(arg, 'other')
|
33
|
+
node.each_descendant(:lvar, :lvasgn) do |lvar|
|
34
|
+
lvar_location = lvar.loc.name
|
35
|
+
next unless lvar_location.source == arg.source
|
36
|
+
|
37
|
+
corrector.replace(lvar_location, 'other')
|
38
|
+
end
|
39
|
+
end
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
@@ -30,13 +30,19 @@ module RuboCop
|
|
30
30
|
class HeredocDelimiterCase < Base
|
31
31
|
include Heredoc
|
32
32
|
include ConfigurableEnforcedStyle
|
33
|
+
extend AutoCorrector
|
33
34
|
|
34
35
|
MSG = 'Use %<style>s heredoc delimiters.'
|
35
36
|
|
36
37
|
def on_heredoc(node)
|
37
38
|
return if correct_case_delimiters?(node)
|
38
39
|
|
39
|
-
add_offense(node.loc.heredoc_end)
|
40
|
+
add_offense(node.loc.heredoc_end) do |corrector|
|
41
|
+
expr = node.loc.expression
|
42
|
+
|
43
|
+
corrector.replace(expr, correct_delimiters(expr.source))
|
44
|
+
corrector.replace(node.loc.heredoc_end, correct_delimiters(delimiter_string(expr)))
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
48
|
private
|
@@ -46,14 +52,14 @@ module RuboCop
|
|
46
52
|
end
|
47
53
|
|
48
54
|
def correct_case_delimiters?(node)
|
49
|
-
delimiter_string(node) == correct_delimiters(node)
|
55
|
+
delimiter_string(node) == correct_delimiters(delimiter_string(node))
|
50
56
|
end
|
51
57
|
|
52
|
-
def correct_delimiters(
|
58
|
+
def correct_delimiters(source)
|
53
59
|
if style == :uppercase
|
54
|
-
|
60
|
+
source.upcase
|
55
61
|
else
|
56
|
-
|
62
|
+
source.downcase
|
57
63
|
end
|
58
64
|
end
|
59
65
|
end
|
@@ -20,6 +20,11 @@ module RuboCop
|
|
20
20
|
# @something ||= calculate_expensive_thing
|
21
21
|
# end
|
22
22
|
#
|
23
|
+
# def foo
|
24
|
+
# return @something if defined?(@something)
|
25
|
+
# @something = calculate_expensive_thing
|
26
|
+
# end
|
27
|
+
#
|
23
28
|
# # good
|
24
29
|
# def _foo
|
25
30
|
# @foo ||= calculate_expensive_thing
|
@@ -54,6 +59,11 @@ module RuboCop
|
|
54
59
|
# @foo ||= calculate_expensive_thing
|
55
60
|
# end
|
56
61
|
#
|
62
|
+
# def foo
|
63
|
+
# return @foo if defined?(@foo)
|
64
|
+
# @foo = calculate_expensive_thing
|
65
|
+
# end
|
66
|
+
#
|
57
67
|
# # good
|
58
68
|
# def foo
|
59
69
|
# @_foo ||= calculate_expensive_thing
|
@@ -64,6 +74,11 @@ module RuboCop
|
|
64
74
|
# @_foo ||= calculate_expensive_thing
|
65
75
|
# end
|
66
76
|
#
|
77
|
+
# def foo
|
78
|
+
# return @_foo if defined?(@_foo)
|
79
|
+
# @_foo = calculate_expensive_thing
|
80
|
+
# end
|
81
|
+
#
|
67
82
|
# @example EnforcedStyleForLeadingUnderscores :optional
|
68
83
|
# # bad
|
69
84
|
# def foo
|
@@ -84,6 +99,12 @@ module RuboCop
|
|
84
99
|
# def _foo
|
85
100
|
# @_foo ||= calculate_expensive_thing
|
86
101
|
# end
|
102
|
+
#
|
103
|
+
# # good
|
104
|
+
# def foo
|
105
|
+
# return @_foo if defined?(@_foo)
|
106
|
+
# @_foo = calculate_expensive_thing
|
107
|
+
# end
|
87
108
|
class MemoizedInstanceVariableName < Base
|
88
109
|
include ConfigurableEnforcedStyle
|
89
110
|
|
@@ -92,32 +113,60 @@ module RuboCop
|
|
92
113
|
UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
|
93
114
|
'with `_`. Use `@%<suggested_var>s` instead.'
|
94
115
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
class_method =
|
101
|
-
"(defs self $_ _ {#{memo_assign} #{memoized_at_end_of_method}})"
|
102
|
-
"{#{instance_method} #{class_method}}"
|
103
|
-
end
|
116
|
+
# rubocop:disable Metrics/AbcSize
|
117
|
+
def on_or_asgn(node)
|
118
|
+
lhs, _value = *node
|
119
|
+
return unless lhs.ivasgn_type?
|
120
|
+
return unless (method_node = node.each_ancestor(:def, :defs).first)
|
104
121
|
|
105
|
-
|
106
|
-
|
122
|
+
body = method_node.body
|
123
|
+
return unless body == node || body.children.last == node
|
107
124
|
|
108
|
-
|
109
|
-
(method_name,
|
110
|
-
return if matches?(method_name, ivar_assign)
|
125
|
+
method_name = method_node.method_name
|
126
|
+
return if matches?(method_name, lhs)
|
111
127
|
|
112
128
|
msg = format(
|
113
|
-
message(
|
114
|
-
var:
|
129
|
+
message(lhs.children.first.to_s),
|
130
|
+
var: lhs.children.first.to_s,
|
115
131
|
suggested_var: suggested_var(method_name),
|
116
132
|
method: method_name
|
117
133
|
)
|
118
|
-
add_offense(
|
134
|
+
add_offense(lhs, message: msg)
|
135
|
+
end
|
136
|
+
# rubocop:enable Metrics/AbcSize
|
137
|
+
|
138
|
+
def_node_matcher :defined_memoized?, <<~PATTERN
|
139
|
+
(begin
|
140
|
+
(if (defined $(ivar %1)) (return $(ivar %1)) nil?)
|
141
|
+
...
|
142
|
+
$(ivasgn %1 _))
|
143
|
+
PATTERN
|
144
|
+
|
145
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
146
|
+
def on_defined?(node)
|
147
|
+
arg = node.arguments.first
|
148
|
+
return unless arg.ivar_type?
|
149
|
+
|
150
|
+
method_node = node.each_ancestor(:def, :defs).first
|
151
|
+
return unless method_node
|
152
|
+
|
153
|
+
var_name = arg.children.first
|
154
|
+
method_name = method_node.method_name
|
155
|
+
defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
|
156
|
+
return if matches?(method_name, ivar_assign)
|
157
|
+
|
158
|
+
msg = format(
|
159
|
+
message(var_name.to_s),
|
160
|
+
var: var_name.to_s,
|
161
|
+
suggested_var: suggested_var(method_name),
|
162
|
+
method: method_name
|
163
|
+
)
|
164
|
+
add_offense(defined_ivar, message: msg)
|
165
|
+
add_offense(return_ivar, message: msg)
|
166
|
+
add_offense(ivar_assign.loc.name, message: msg)
|
167
|
+
end
|
119
168
|
end
|
120
|
-
|
169
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
121
170
|
|
122
171
|
private
|
123
172
|
|