rubocop 0.20.1 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/README.md +16 -4
- data/config/default.yml +37 -10
- data/config/enabled.yml +25 -7
- data/lib/rubocop.rb +15 -19
- data/lib/rubocop/cli.rb +2 -2
- data/lib/rubocop/config.rb +40 -3
- data/lib/rubocop/config_loader.rb +6 -37
- data/lib/rubocop/config_store.rb +0 -1
- data/lib/rubocop/cop/commissioner.rb +12 -9
- data/lib/rubocop/cop/cop.rb +17 -5
- data/lib/rubocop/cop/force.rb +41 -0
- data/lib/rubocop/cop/ignored_node.rb +10 -10
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -2
- data/lib/rubocop/cop/lint/block_alignment.rb +2 -2
- data/lib/rubocop/cop/lint/condition_position.rb +2 -0
- data/lib/rubocop/cop/lint/debugger.rb +17 -3
- data/lib/rubocop/cop/lint/end_alignment.rb +3 -11
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +11 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -6
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +39 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +81 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +52 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +6 -8
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +6 -0
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +7 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +11 -0
- data/lib/rubocop/cop/mixin/check_methods.rb +12 -0
- data/lib/rubocop/cop/mixin/percent_literal.rb +26 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -2
- data/lib/rubocop/cop/mixin/string_help.rb +0 -4
- data/lib/rubocop/cop/rails/delegate.rb +109 -0
- data/lib/rubocop/cop/style/align_hash.rb +3 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -2
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/dot_position.rb +1 -1
- data/lib/rubocop/cop/style/encoding.rb +44 -16
- data/lib/rubocop/cop/style/indentation_width.rb +29 -19
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -21
- data/lib/rubocop/cop/style/predicate_name.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +18 -2
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +29 -37
- data/lib/rubocop/cop/style/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +37 -23
- data/lib/rubocop/cop/style/trailing_comma.rb +2 -3
- data/lib/rubocop/cop/style/trivial_accessors.rb +40 -4
- data/lib/rubocop/cop/style/unneeded_capital_w.rb +29 -0
- data/lib/rubocop/cop/team.rb +10 -2
- data/lib/rubocop/cop/util.rb +2 -2
- data/lib/rubocop/cop/{variable_inspector.rb → variable_force.rb} +45 -37
- data/lib/rubocop/cop/{variable_inspector → variable_force}/assignment.rb +1 -1
- data/lib/rubocop/cop/{variable_inspector → variable_force}/locatable.rb +1 -1
- data/lib/rubocop/cop/{variable_inspector → variable_force}/reference.rb +13 -1
- data/lib/rubocop/cop/{variable_inspector → variable_force}/scope.rb +9 -1
- data/lib/rubocop/cop/{variable_inspector → variable_force}/variable.rb +14 -4
- data/lib/rubocop/cop/{variable_inspector → variable_force}/variable_table.rb +1 -1
- data/lib/rubocop/file_inspector.rb +3 -1
- data/lib/rubocop/formatter/base_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -2
- data/lib/rubocop/formatter/disabled_lines_formatter.rb +2 -2
- data/lib/rubocop/formatter/offense_count_formatter.rb +11 -10
- data/lib/rubocop/formatter/progress_formatter.rb +2 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
- data/lib/rubocop/options.rb +74 -58
- data/lib/rubocop/path_util.rb +17 -2
- data/lib/rubocop/rake_task.rb +23 -5
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.21.0.md +45 -0
- data/rubocop-todo.yml +6 -6
- data/rubocop.gemspec +1 -1
- data/spec/rubocop/cli_spec.rb +170 -59
- data/spec/rubocop/config_spec.rb +48 -3
- data/spec/rubocop/config_store_spec.rb +3 -3
- data/spec/rubocop/cop/commissioner_spec.rb +9 -7
- data/spec/rubocop/cop/cop_spec.rb +0 -2
- data/spec/rubocop/cop/force_spec.rb +29 -0
- data/spec/rubocop/cop/lint/ambiguous_operator_spec.rb +2 -2
- data/spec/rubocop/cop/lint/ambiguous_regexp_literal_spec.rb +1 -1
- data/spec/rubocop/cop/lint/block_alignment_spec.rb +24 -24
- data/spec/rubocop/cop/lint/condition_position_spec.rb +7 -5
- data/spec/rubocop/cop/lint/debugger_spec.rb +26 -9
- data/spec/rubocop/cop/lint/end_alignment_spec.rb +6 -3
- data/spec/rubocop/cop/lint/invalid_character_literal_spec.rb +7 -6
- data/spec/rubocop/cop/lint/rescue_exception_spec.rb +36 -0
- data/spec/rubocop/cop/lint/shadowing_outer_local_variable_spec.rb +4 -4
- data/spec/rubocop/cop/lint/underscore_prefixed_variable_name_spec.rb +179 -0
- data/spec/rubocop/cop/lint/unused_block_argument_spec.rb +147 -0
- data/spec/rubocop/cop/lint/unused_method_argument_spec.rb +140 -0
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +50 -48
- data/spec/rubocop/cop/lint/useless_else_without_rescue_spec.rb +1 -1
- data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +2 -0
- data/spec/rubocop/cop/rails/delegate_spec.rb +152 -0
- data/spec/rubocop/cop/style/encoding_spec.rb +131 -36
- data/spec/rubocop/cop/style/indentation_width_spec.rb +79 -0
- data/spec/rubocop/cop/style/redundant_begin_spec.rb +32 -0
- data/spec/rubocop/cop/style/regexp_literal_spec.rb +83 -13
- data/spec/rubocop/cop/style/string_literals_spec.rb +9 -3
- data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +65 -25
- data/spec/rubocop/cop/style/trivial_accessors_spec.rb +76 -0
- data/spec/rubocop/cop/style/unneeded_capital_w_spec.rb +85 -0
- data/spec/rubocop/cop/team_spec.rb +43 -0
- data/spec/rubocop/cop/{variable_inspector → variable_force}/assignment_spec.rb +3 -3
- data/spec/rubocop/cop/{variable_inspector → variable_force}/locatable_spec.rb +3 -3
- data/spec/rubocop/cop/{variable_inspector → variable_force}/scope_spec.rb +30 -2
- data/spec/rubocop/cop/{variable_inspector → variable_force}/variable_spec.rb +12 -27
- data/spec/rubocop/cop/{variable_inspector → variable_force}/variable_table_spec.rb +1 -1
- data/spec/rubocop/cop/{variable_inspector_spec.rb → variable_force_spec.rb} +4 -8
- data/spec/rubocop/formatter/base_formatter_spec.rb +2 -2
- data/spec/rubocop/formatter/offense_count_formatter_spec.rb +1 -1
- data/spec/rubocop/formatter/progress_formatter_spec.rb +1 -1
- data/spec/rubocop/options_spec.rb +2 -2
- data/spec/rubocop/path_util_spec.rb +47 -14
- data/spec/spec_helper.rb +9 -3
- data/spec/support/file_helper.rb +2 -0
- metadata +43 -26
- data/lib/rubocop/cop/style/final_newline.rb +0 -29
- data/spec/rubocop/cop/style/final_newline_spec.rb +0 -30
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for unused block arguments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# do_something do |used, unused, _unused_but_allowed|
|
11
|
+
# puts used
|
12
|
+
# end
|
13
|
+
class UnusedBlockArgument < Cop
|
14
|
+
include Util
|
15
|
+
|
16
|
+
def join_force?(force_class)
|
17
|
+
force_class == VariableForce
|
18
|
+
end
|
19
|
+
|
20
|
+
def after_leaving_scope(scope, _variable_table)
|
21
|
+
scope.variables.each_value do |variable|
|
22
|
+
check_argument(variable)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def check_argument(variable)
|
27
|
+
return unless variable.block_argument?
|
28
|
+
return if variable.name.to_s.start_with?('_')
|
29
|
+
return if variable.referenced?
|
30
|
+
|
31
|
+
message = message(variable)
|
32
|
+
add_offense(variable.declaration_node, :name, message)
|
33
|
+
end
|
34
|
+
|
35
|
+
def message(variable)
|
36
|
+
message = "Unused block argument - `#{variable.name}`. "
|
37
|
+
|
38
|
+
scope = variable.scope
|
39
|
+
all_arguments = scope.variables.each_value.select(&:block_argument?)
|
40
|
+
|
41
|
+
if lambda?(scope.node)
|
42
|
+
message << message_for_lambda(variable, all_arguments)
|
43
|
+
else
|
44
|
+
message << message_for_normal_block(variable, all_arguments)
|
45
|
+
end
|
46
|
+
|
47
|
+
message
|
48
|
+
end
|
49
|
+
|
50
|
+
def message_for_normal_block(variable, all_arguments)
|
51
|
+
if all_arguments.none?(&:referenced?)
|
52
|
+
if all_arguments.count > 1
|
53
|
+
"You can omit all the arguments if you don't care about them."
|
54
|
+
else
|
55
|
+
"You can omit the argument if you don't care about it."
|
56
|
+
end
|
57
|
+
else
|
58
|
+
message_for_underscore_prefix(variable)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def message_for_lambda(variable, all_arguments)
|
63
|
+
message = message_for_underscore_prefix(variable)
|
64
|
+
|
65
|
+
if all_arguments.none?(&:referenced?)
|
66
|
+
message << ' Also consider using a proc without arguments ' \
|
67
|
+
'instead of a lambda if you want it ' \
|
68
|
+
"to accept any arguments but don't care about them."
|
69
|
+
end
|
70
|
+
|
71
|
+
message
|
72
|
+
end
|
73
|
+
|
74
|
+
def message_for_underscore_prefix(variable)
|
75
|
+
"If it's necessary, use `_` or `_#{variable.name}` " \
|
76
|
+
"as an argument name to indicate that it won't be used."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for unused method arguments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# def some_method(used, unused, _unused_but_allowed)
|
11
|
+
# puts used
|
12
|
+
# end
|
13
|
+
class UnusedMethodArgument < Cop
|
14
|
+
def join_force?(force_class)
|
15
|
+
force_class == VariableForce
|
16
|
+
end
|
17
|
+
|
18
|
+
def after_leaving_scope(scope, _variable_table)
|
19
|
+
scope.variables.each_value do |variable|
|
20
|
+
check_argument(variable)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_argument(variable)
|
25
|
+
return unless variable.method_argument?
|
26
|
+
return if variable.name.to_s.start_with?('_')
|
27
|
+
return if variable.referenced?
|
28
|
+
|
29
|
+
message = message(variable)
|
30
|
+
add_offense(variable.declaration_node, :name, message)
|
31
|
+
end
|
32
|
+
|
33
|
+
def message(variable)
|
34
|
+
message = "Unused method argument - `#{variable.name}`. " \
|
35
|
+
"If it's necessary, use `_` or `_#{variable.name}` " \
|
36
|
+
"as an argument name to indicate that it won't be used."
|
37
|
+
|
38
|
+
scope = variable.scope
|
39
|
+
all_arguments = scope.variables.each_value.select(&:method_argument?)
|
40
|
+
|
41
|
+
if all_arguments.none?(&:referenced?)
|
42
|
+
message << " You can also write as `#{scope.name}(*)` " \
|
43
|
+
'if you want the method to accept any arguments ' \
|
44
|
+
"but don't care about them."
|
45
|
+
end
|
46
|
+
|
47
|
+
message
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -13,15 +13,13 @@ module Rubocop
|
|
13
13
|
# reassignments and properly handles varied cases such as branch, loop,
|
14
14
|
# rescue, ensure, etc.
|
15
15
|
class UselessAssignment < Cop
|
16
|
-
|
16
|
+
MSG = 'Useless assignment to variable - `%s`.'
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
def investigate(processed_source)
|
21
|
-
inspect_variables(processed_source.ast)
|
18
|
+
def join_force?(force_class)
|
19
|
+
force_class == VariableForce
|
22
20
|
end
|
23
21
|
|
24
|
-
def after_leaving_scope(scope)
|
22
|
+
def after_leaving_scope(scope, _variable_table)
|
25
23
|
scope.variables.each_value do |variable|
|
26
24
|
check_for_unused_assignments(variable)
|
27
25
|
check_for_unused_block_local_variable(variable)
|
@@ -52,13 +50,13 @@ module Rubocop
|
|
52
50
|
message = format(MSG, variable.name)
|
53
51
|
|
54
52
|
if assignment.multiple_assignment?
|
55
|
-
message << "
|
53
|
+
message << " Use `_` or `_#{variable.name}` as a variable name " \
|
56
54
|
"to indicate that it won't be used."
|
57
55
|
elsif assignment.operator_assignment?
|
58
56
|
return_value_node = return_value_node_of_scope(variable.scope)
|
59
57
|
if assignment.meta_assignment_node.equal?(return_value_node)
|
60
58
|
non_assignment_operator = assignment.operator.sub(/=$/, '')
|
61
|
-
message << "
|
59
|
+
message << " Use just operator `#{non_assignment_operator}`."
|
62
60
|
end
|
63
61
|
end
|
64
62
|
|
@@ -14,11 +14,17 @@ module Rubocop
|
|
14
14
|
class UselessElseWithoutRescue < Cop
|
15
15
|
include ParserDiagnostic
|
16
16
|
|
17
|
+
MSG = '`else` without `rescue` is useless.'
|
18
|
+
|
17
19
|
private
|
18
20
|
|
19
21
|
def relevant_diagnostic?(diagnostic)
|
20
22
|
diagnostic.reason == :useless_else
|
21
23
|
end
|
24
|
+
|
25
|
+
def alternative_message(_diagnostic)
|
26
|
+
MSG
|
27
|
+
end
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
@@ -15,7 +15,7 @@ module Rubocop
|
|
15
15
|
class UselessSetterCall < Cop
|
16
16
|
include CheckMethods
|
17
17
|
|
18
|
-
MSG = 'Useless setter call to local variable
|
18
|
+
MSG = 'Useless setter call to local variable `%s`.'
|
19
19
|
ASSIGNMENT_TYPES = [:lvasgn, :ivasgn, :cvasgn, :gvasgn].freeze
|
20
20
|
|
21
21
|
private
|
@@ -8,7 +8,7 @@ module Rubocop
|
|
8
8
|
class Void < Cop
|
9
9
|
OP_MSG = 'Operator `%s` used in void context.'
|
10
10
|
VAR_MSG = 'Variable `%s` used in void context.'
|
11
|
-
LIT_MSG = 'Literal `%s` used in void context'
|
11
|
+
LIT_MSG = 'Literal `%s` used in void context.'
|
12
12
|
|
13
13
|
OPS = %w(* / % + - == === != < > <= >= <=>)
|
14
14
|
VARS = [:ivar, :lvar, :cvar, :const]
|
@@ -29,7 +29,7 @@ module Rubocop
|
|
29
29
|
|
30
30
|
@corrections << lambda do |corrector|
|
31
31
|
expr = node.loc.expression
|
32
|
-
each_line(expr) do |line_begin_pos
|
32
|
+
each_line(expr) do |line_begin_pos|
|
33
33
|
range = calculate_range(expr, line_begin_pos, column_delta)
|
34
34
|
if column_delta > 0
|
35
35
|
unless range.source == "\n"
|
@@ -70,7 +70,7 @@ module Rubocop
|
|
70
70
|
offset = 0
|
71
71
|
expr.source.each_line do |line|
|
72
72
|
line_begin_pos = expr.begin_pos + offset
|
73
|
-
yield line_begin_pos
|
73
|
+
yield line_begin_pos
|
74
74
|
offset += line.length
|
75
75
|
end
|
76
76
|
end
|
@@ -8,13 +8,17 @@ module Rubocop
|
|
8
8
|
module AutocorrectUnlessChangingAST
|
9
9
|
def autocorrect(node)
|
10
10
|
c = correction(node)
|
11
|
-
new_source = rewrite_node(node
|
11
|
+
new_source = rewrite_node(node)
|
12
12
|
|
13
13
|
# Make the correction only if it doesn't change the AST.
|
14
|
-
|
14
|
+
if node != SourceParser.parse(new_source).ast
|
15
|
+
fail CorrectionNotPossible
|
16
|
+
end
|
17
|
+
|
18
|
+
@corrections << c
|
15
19
|
end
|
16
20
|
|
17
|
-
def rewrite_node(node
|
21
|
+
def rewrite_node(node)
|
18
22
|
processed_source = SourceParser.parse(node.loc.expression.source)
|
19
23
|
c = correction(processed_source.ast)
|
20
24
|
Corrector.new(processed_source.buffer, [c]).rewrite
|
@@ -21,6 +21,17 @@ module Rubocop
|
|
21
21
|
_lhs, _op, rhs = *node
|
22
22
|
check_assignment(node, rhs)
|
23
23
|
end
|
24
|
+
|
25
|
+
def on_send(node)
|
26
|
+
_receiver, method_name, *_, rhs = *node
|
27
|
+
|
28
|
+
# we only want to indent relative to the receiver
|
29
|
+
# when the method called looks like a setter
|
30
|
+
return unless method_name.to_s.end_with?('=')
|
31
|
+
|
32
|
+
# This will match if, case, begin, blocks, etc.
|
33
|
+
check_assignment(node, rhs) if rhs.is_a?(AST::Node)
|
34
|
+
end
|
24
35
|
end
|
25
36
|
end
|
26
37
|
end
|
@@ -13,6 +13,18 @@ module Rubocop
|
|
13
13
|
_scope, method_name, args, body = *node
|
14
14
|
check(node, method_name, args, body)
|
15
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Returns true for constructs such as
|
20
|
+
# private def my_method
|
21
|
+
# which are allowed in Ruby 2.1 and later.
|
22
|
+
def visibility_and_def_on_same_line?(receiver, method_name, args)
|
23
|
+
!receiver &&
|
24
|
+
[:public, :protected, :private,
|
25
|
+
:module_function].include?(method_name) &&
|
26
|
+
args.size == 1 && [:def, :defs].include?(args.first.type)
|
27
|
+
end
|
16
28
|
end
|
17
29
|
end
|
18
30
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for handling percent literals.
|
6
|
+
module PercentLiteral
|
7
|
+
def percent_literal?(node)
|
8
|
+
if (begin_source = begin_source(node))
|
9
|
+
begin_source.start_with?('%')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(node, *types)
|
14
|
+
on_percent_literal(node, types) if percent_literal?(node)
|
15
|
+
end
|
16
|
+
|
17
|
+
def begin_source(node)
|
18
|
+
node.loc.begin.source if node.loc.respond_to?(:begin) && node.loc.begin
|
19
|
+
end
|
20
|
+
|
21
|
+
def type(node)
|
22
|
+
node.loc.begin.source[0..-2]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -10,7 +10,7 @@ module Rubocop
|
|
10
10
|
def investigate(processed_source)
|
11
11
|
processed_source.tokens.each_cons(2) do |t1, t2|
|
12
12
|
if kind(t1) && t1.pos.line == t2.pos.line &&
|
13
|
-
t2.pos.column == t1.pos.column + offset
|
13
|
+
t2.pos.column == t1.pos.column + offset &&
|
14
14
|
![:tRPAREN, :tRBRACK].include?(t2.type)
|
15
15
|
add_offense(t1, t1.pos, format(MSG, kind(t1)))
|
16
16
|
end
|
@@ -19,7 +19,7 @@ module Rubocop
|
|
19
19
|
|
20
20
|
# The normal offset, i.e., the distance from the punctuation
|
21
21
|
# token where a space should be, is 1.
|
22
|
-
def offset
|
22
|
+
def offset
|
23
23
|
1
|
24
24
|
end
|
25
25
|
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop looks for delegations, that could have been created
|
7
|
+
# automatically with delegate method.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# def bar
|
12
|
+
# foo.bar
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# delegate :bar, to: :foo
|
17
|
+
#
|
18
|
+
# # bad
|
19
|
+
# def foo_bar
|
20
|
+
# foo.bar
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# delegate :bar, to: :foo, prefix: true
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# private
|
28
|
+
# def bar
|
29
|
+
# foo.bar
|
30
|
+
# end
|
31
|
+
class Delegate < Cop
|
32
|
+
include CheckMethods
|
33
|
+
|
34
|
+
MSG = 'Use `delegate` to define delegations.'
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check(node, method_name, args, body)
|
39
|
+
return unless trivial_delegate?(method_name, args, body)
|
40
|
+
return if private_or_protected_delegation(node)
|
41
|
+
add_offense(node, :keyword, MSG)
|
42
|
+
end
|
43
|
+
|
44
|
+
def autocorrect(node)
|
45
|
+
method_name, args, body = *node
|
46
|
+
return unless trivial_delegate?(method_name, args, body)
|
47
|
+
return if private_or_protected_delegation(node)
|
48
|
+
|
49
|
+
delegation = ["delegate :#{body.children[1]}",
|
50
|
+
"to: :#{body.children[0].children[1]}"]
|
51
|
+
if method_name == prefixed_method_name(body)
|
52
|
+
delegation << ['prefix: true']
|
53
|
+
end
|
54
|
+
|
55
|
+
@corrections << lambda do |corrector|
|
56
|
+
corrector.replace(node.loc.expression, delegation.join(', '))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def trivial_delegate?(method_name, args, body)
|
61
|
+
body && delegate?(body) &&
|
62
|
+
method_name_matches?(method_name, body) &&
|
63
|
+
arguments_match?(args, body)
|
64
|
+
end
|
65
|
+
|
66
|
+
def delegate?(body)
|
67
|
+
receiver, * = *body
|
68
|
+
receiver.children.none? { |n| n.is_a? Parser::AST::Node }
|
69
|
+
end
|
70
|
+
|
71
|
+
def arguments_match?(args, body)
|
72
|
+
_receiver, _method_name, *arguments = *body
|
73
|
+
arg_array = Array(args)
|
74
|
+
argument_array = Array(arguments)
|
75
|
+
arg_array.size == argument_array.size && (
|
76
|
+
arg_array == argument_array ||
|
77
|
+
arg_array.map(&:children) == argument_array.map(&:children)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def method_name_matches?(method_name, body)
|
82
|
+
_receiver, property_name, *_args = *body
|
83
|
+
method_name == property_name ||
|
84
|
+
method_name == prefixed_method_name(body)
|
85
|
+
end
|
86
|
+
|
87
|
+
def prefixed_method_name(body)
|
88
|
+
receiver, property_name, *_args = *body
|
89
|
+
_receiver, target, *_args = *receiver
|
90
|
+
[target, property_name].join('_').to_sym
|
91
|
+
end
|
92
|
+
|
93
|
+
def private_or_protected_delegation(node)
|
94
|
+
line = node.loc.line
|
95
|
+
private_or_protected_before(line) ||
|
96
|
+
private_or_protected_inline(line)
|
97
|
+
end
|
98
|
+
|
99
|
+
def private_or_protected_before(line)
|
100
|
+
(processed_source[0..line].map(&:strip) & %w(private protected)).any?
|
101
|
+
end
|
102
|
+
|
103
|
+
def private_or_protected_inline(line)
|
104
|
+
processed_source[line - 1].strip =~ /\A(private )|(protected )/
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|