rubocop 0.25.0 → 0.26.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/.rubocop.yml +3 -0
- data/CHANGELOG.md +37 -0
- data/README.md +2 -2
- data/assets/output.html.erb +190 -0
- data/config/default.yml +14 -2
- data/config/disabled.yml +7 -0
- data/config/enabled.yml +132 -5
- data/lib/rubocop.rb +5 -0
- data/lib/rubocop/cop/commissioner.rb +4 -10
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/end_in_method.rb +3 -8
- data/lib/rubocop/cop/lint/ensure_return.rb +2 -2
- data/lib/rubocop/cop/lint/space_before_first_arg.rb +8 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +35 -0
- data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -3
- data/lib/rubocop/cop/metrics/block_nesting.rb +3 -3
- data/lib/rubocop/cop/metrics/class_length.rb +1 -2
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -1
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/configurable_naming.rb +2 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +2 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -3
- data/lib/rubocop/cop/rails/delegate.rb +1 -1
- data/lib/rubocop/cop/rails/validation.rb +25 -2
- data/lib/rubocop/cop/style/alias.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +12 -2
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -12
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/dot_position.rb +20 -0
- data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +5 -1
- data/lib/rubocop/cop/style/encoding.rb +4 -4
- data/lib/rubocop/cop/style/format_string.rb +12 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +8 -11
- data/lib/rubocop/cop/style/infinite_loop.rb +57 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +15 -16
- data/lib/rubocop/cop/style/multiline_if_then.rb +10 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -3
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -1
- data/lib/rubocop/cop/style/predicate_name.rb +23 -5
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +4 -8
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +9 -11
- data/lib/rubocop/cop/style/space_inside_range_literal.rb +58 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +71 -0
- data/lib/rubocop/cop/style/tab.rb +11 -3
- data/lib/rubocop/cop/style/unneeded_capital_w.rb +6 -2
- data/lib/rubocop/cop/style/variable_name.rb +4 -14
- data/lib/rubocop/cop/style/while_until_modifier.rb +12 -8
- data/lib/rubocop/cop/variable_force.rb +17 -30
- data/lib/rubocop/cop/variable_force/assignment.rb +15 -23
- data/lib/rubocop/cop/variable_force/locatable.rb +29 -8
- data/lib/rubocop/cop/variable_force/scope.rb +34 -23
- data/lib/rubocop/cop/variable_force/variable.rb +7 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +3 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +90 -0
- data/lib/rubocop/formatter/progress_formatter.rb +1 -1
- data/lib/rubocop/options.rb +1 -0
- data/lib/rubocop/processed_source.rb +10 -1
- data/lib/rubocop/string_util.rb +153 -0
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.26.0.md +89 -0
- data/rubocop.gemspec +1 -0
- data/spec/rubocop/cli_spec.rb +60 -34
- data/spec/rubocop/config_loader_spec.rb +19 -15
- data/spec/rubocop/cop/commissioner_spec.rb +2 -2
- data/spec/rubocop/cop/lint/block_alignment_spec.rb +74 -58
- data/spec/rubocop/cop/lint/space_before_first_arg_spec.rb +7 -0
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +173 -0
- data/spec/rubocop/cop/rails/validation_spec.rb +9 -2
- data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +26 -0
- data/spec/rubocop/cop/style/and_or_spec.rb +52 -61
- data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +26 -8
- data/spec/rubocop/cop/style/case_indentation_spec.rb +8 -8
- data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +6 -2
- data/spec/rubocop/cop/style/dot_position_spec.rb +39 -0
- data/spec/rubocop/cop/style/empty_lines_around_access_modifier_spec.rb +12 -2
- data/spec/rubocop/cop/style/encoding_spec.rb +16 -28
- data/spec/rubocop/cop/style/format_string_spec.rb +12 -0
- data/spec/rubocop/cop/style/infinite_loop_spec.rb +48 -0
- data/spec/rubocop/cop/style/method_def_parentheses_spec.rb +3 -1
- data/spec/rubocop/cop/style/multiline_if_then_spec.rb +9 -0
- data/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb +21 -1
- data/spec/rubocop/cop/style/predicate_name_spec.rb +44 -13
- data/spec/rubocop/cop/style/redundant_begin_spec.rb +32 -0
- data/spec/rubocop/cop/style/space_inside_range_literal_spec.rb +52 -0
- data/spec/rubocop/cop/style/symbol_proc_spec.rb +76 -0
- data/spec/rubocop/cop/style/tab_spec.rb +30 -0
- data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +2 -1
- data/spec/rubocop/cop/style/unneeded_capital_w_spec.rb +18 -5
- data/spec/rubocop/cop/style/variable_name_spec.rb +5 -5
- data/spec/rubocop/cop/style/when_then_spec.rb +3 -1
- data/spec/rubocop/cop/style/while_until_do_spec.rb +4 -2
- data/spec/rubocop/cop/util_spec.rb +1 -9
- data/spec/rubocop/cop/variable_force/assignment_spec.rb +2 -15
- data/spec/rubocop/cop/variable_force/locatable_spec.rb +2 -37
- data/spec/rubocop/cop/variable_force/scope_spec.rb +156 -49
- data/spec/rubocop/cop/variable_force/variable_spec.rb +2 -1
- data/spec/rubocop/cop/variable_force_spec.rb +2 -1
- data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +2 -1
- data/spec/rubocop/formatter/html_formatter_spec.rb +145 -0
- data/spec/rubocop/formatter/simple_text_formatter_spec.rb +18 -6
- data/spec/rubocop/options_spec.rb +1 -0
- data/spec/rubocop/path_util_spec.rb +6 -4
- data/spec/rubocop/processed_source_spec.rb +17 -1
- data/spec/rubocop/string_util_spec.rb +46 -0
- metadata +33 -4
- data/spec/support/ast_helper.rb +0 -15
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def next_line_empty?(next_line)
|
49
|
-
next_line.blank?
|
49
|
+
body_end?(next_line.lstrip) || next_line.blank?
|
50
50
|
end
|
51
51
|
|
52
52
|
def empty_lines_around?(node)
|
@@ -61,6 +61,10 @@ module RuboCop
|
|
61
61
|
%w(class module).any? { |keyword| line.start_with?(keyword) }
|
62
62
|
end
|
63
63
|
|
64
|
+
def body_end?(line)
|
65
|
+
line.start_with?('end')
|
66
|
+
end
|
67
|
+
|
64
68
|
def message(node)
|
65
69
|
format(MSG, node.loc.selector.source)
|
66
70
|
end
|
@@ -3,9 +3,10 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop checks whether the source file has a utf-8 encoding
|
7
|
-
# not. This check makes sense only
|
8
|
-
#
|
6
|
+
# This cop checks whether the source file has a utf-8 encoding
|
7
|
+
# comment or not. This check makes sense only for code that
|
8
|
+
# should support Ruby 1.9, since in 2.0+ utf-8 is the default
|
9
|
+
# source file encoding. There are two style:
|
9
10
|
#
|
10
11
|
# when_needed - only enforce an encoding comment if there are non ASCII
|
11
12
|
# characters, otherwise report an offense
|
@@ -17,7 +18,6 @@ module RuboCop
|
|
17
18
|
MSG_UNNECESSARY = 'Unnecessary utf-8 encoding comment.'
|
18
19
|
|
19
20
|
def investigate(processed_source)
|
20
|
-
return if RUBY_VERSION >= '2.0.0'
|
21
21
|
return if processed_source.buffer.source.empty?
|
22
22
|
|
23
23
|
line_number = encoding_line_number(processed_source)
|
@@ -30,12 +30,22 @@ module RuboCop
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def format_method?(name, node)
|
34
|
+
receiver, method_name, args = *node
|
35
|
+
|
36
|
+
# we do an argument count check to reduce false positives
|
37
|
+
return false if args && args.children.size < 2
|
38
|
+
|
39
|
+
# commands have no explicit receiver
|
40
|
+
!receiver && method_name == name
|
41
|
+
end
|
42
|
+
|
33
43
|
def format?(node)
|
34
|
-
|
44
|
+
format_method?(:format, node)
|
35
45
|
end
|
36
46
|
|
37
47
|
def sprintf?(node)
|
38
|
-
|
48
|
+
format_method?(:sprintf, node)
|
39
49
|
end
|
40
50
|
|
41
51
|
def percent?(node)
|
@@ -14,17 +14,14 @@ module RuboCop
|
|
14
14
|
' Another good alternative is the usage of control flow `&&`/`||`.'
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
next unless fit_within_line_as_modifier_form?(node)
|
26
|
-
add_offense(node, :keyword, message(node.loc.keyword.source))
|
27
|
-
end
|
17
|
+
def on_if(node)
|
18
|
+
# discard ternary ops, if/else and modifier if/unless nodes
|
19
|
+
return if ternary_op?(node)
|
20
|
+
return if modifier_if?(node)
|
21
|
+
return if elsif?(node)
|
22
|
+
return if if_else?(node)
|
23
|
+
return unless fit_within_line_as_modifier_form?(node)
|
24
|
+
add_offense(node, :keyword, message(node.loc.keyword.source))
|
28
25
|
end
|
29
26
|
end
|
30
27
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Use `Kernel#loop` for infinite loops.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# while true
|
11
|
+
# work
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# loop do
|
16
|
+
# work
|
17
|
+
# end
|
18
|
+
class InfiniteLoop < Cop
|
19
|
+
MSG = 'Use `Kernel#loop` for infinite loops.'
|
20
|
+
|
21
|
+
TRUTHY_LITERALS = [:str, :dstr, :int, :float, :array,
|
22
|
+
:hash, :regexp, :true]
|
23
|
+
|
24
|
+
FALSEY_LITERALS = [:nil, :false]
|
25
|
+
|
26
|
+
def on_while(node)
|
27
|
+
condition, = *node
|
28
|
+
|
29
|
+
return unless TRUTHY_LITERALS.include?(condition.type)
|
30
|
+
|
31
|
+
add_offense(node, :keyword)
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_until(node)
|
35
|
+
condition, = *node
|
36
|
+
|
37
|
+
return unless FALSEY_LITERALS.include?(condition.type)
|
38
|
+
|
39
|
+
add_offense(node, :keyword)
|
40
|
+
end
|
41
|
+
|
42
|
+
def autocorrect(node)
|
43
|
+
@corrections << lambda do |corrector|
|
44
|
+
condition_node, = *node
|
45
|
+
start_range = node.loc.keyword.begin
|
46
|
+
end_range = if node.loc.begin
|
47
|
+
node.loc.begin.end
|
48
|
+
else
|
49
|
+
condition_node.loc.expression.end
|
50
|
+
end
|
51
|
+
corrector.replace(start_range.join(end_range), 'loop do')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -18,24 +18,23 @@ module RuboCop
|
|
18
18
|
|
19
19
|
def on_block(node)
|
20
20
|
method, _args, _body = *node
|
21
|
-
|
21
|
+
method.each_node(:send) do |send_node|
|
22
22
|
receiver, _method_name, *_args = *send_node
|
23
|
-
|
24
|
-
# The begin and end could also be braces, but we call the
|
25
|
-
# variables do... and end...
|
26
|
-
do_kw_loc, end_kw_loc = receiver.loc.begin, receiver.loc.end
|
23
|
+
next unless receiver && receiver.type == :block
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
25
|
+
# The begin and end could also be braces, but we call the
|
26
|
+
# variables do... and end...
|
27
|
+
do_kw_loc, end_kw_loc = receiver.loc.begin, receiver.loc.end
|
28
|
+
next if do_kw_loc.line == end_kw_loc.line
|
29
|
+
|
30
|
+
range =
|
31
|
+
Parser::Source::Range.new(end_kw_loc.source_buffer,
|
32
|
+
end_kw_loc.begin_pos,
|
33
|
+
method.loc.expression.end_pos)
|
34
|
+
add_offense(nil, range)
|
35
|
+
# Done. If there are more blocks in the chain, they will be
|
36
|
+
# found by subsequent calls to on_block.
|
37
|
+
break
|
39
38
|
end
|
40
39
|
end
|
41
40
|
end
|
@@ -44,6 +44,16 @@ module RuboCop
|
|
44
44
|
def message(node)
|
45
45
|
"Never use `then` for multi-line `#{node.loc.keyword.source}`."
|
46
46
|
end
|
47
|
+
|
48
|
+
def autocorrect(node)
|
49
|
+
@corrections << lambda do |corrector|
|
50
|
+
condition_node, = *node
|
51
|
+
end_of_condition_range = condition_node.loc.expression.end
|
52
|
+
then_range = node.loc.begin
|
53
|
+
whitespaces_and_then_range = end_of_condition_range.join(then_range)
|
54
|
+
corrector.remove(whitespaces_and_then_range)
|
55
|
+
end
|
56
|
+
end
|
47
57
|
end
|
48
58
|
end
|
49
59
|
end
|
@@ -14,9 +14,9 @@ module RuboCop
|
|
14
14
|
# discard non-ternary ops
|
15
15
|
return unless loc.respond_to?(:question)
|
16
16
|
|
17
|
-
node.
|
18
|
-
|
19
|
-
add_offense(
|
17
|
+
node.each_descendant(:if) do |nested_if_node|
|
18
|
+
if nested_if_node.loc.respond_to?(:question)
|
19
|
+
add_offense(nested_if_node, :expression)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -80,7 +80,9 @@ module RuboCop
|
|
80
80
|
when String
|
81
81
|
''
|
82
82
|
when Parser::AST::Node
|
83
|
-
|
83
|
+
part_range = object.loc.send(part)
|
84
|
+
left_of_part = part_range.source_line[0...part_range.column]
|
85
|
+
/^(\s*)$/.match(left_of_part) ? left_of_part : ''
|
84
86
|
else
|
85
87
|
fail "Unsupported object #{object}"
|
86
88
|
end
|
@@ -23,21 +23,39 @@ module RuboCop
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def on_method(node, method_name, _args, _body)
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
predicate_prefices.each do |prefix|
|
27
|
+
method_name = method_name.to_s
|
28
|
+
next unless method_name.start_with?(prefix)
|
29
|
+
next if method_name == expected_name(method_name, prefix)
|
30
|
+
add_offense(
|
31
|
+
node,
|
32
|
+
:name,
|
33
|
+
message(method_name, expected_name(method_name, prefix))
|
34
|
+
)
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
33
|
-
new_name =
|
38
|
+
def expected_name(method_name, prefix)
|
39
|
+
new_name = if prefix_blacklist.include?(prefix)
|
40
|
+
method_name.sub(prefix, '')
|
41
|
+
else
|
42
|
+
method_name.dup
|
43
|
+
end
|
34
44
|
new_name << '?' unless method_name.end_with?('?')
|
45
|
+
new_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def message(method_name, new_name)
|
35
49
|
"Rename `#{method_name}` to `#{new_name}`."
|
36
50
|
end
|
37
51
|
|
38
52
|
def prefix_blacklist
|
39
53
|
cop_config['NamePrefixBlacklist']
|
40
54
|
end
|
55
|
+
|
56
|
+
def predicate_prefices
|
57
|
+
cop_config['NamePrefix']
|
58
|
+
end
|
41
59
|
end
|
42
60
|
end
|
43
61
|
end
|
@@ -9,14 +9,10 @@ module RuboCop
|
|
9
9
|
include SurroundingSpace
|
10
10
|
include ConfigurableEnforcedStyle
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
index = index_of_first_token(optarg)
|
17
|
-
arg, equals, value = processed_source.tokens[index, 3]
|
18
|
-
check_optarg(arg, equals, value)
|
19
|
-
end
|
12
|
+
def on_optarg(node)
|
13
|
+
index = index_of_first_token(node)
|
14
|
+
arg, equals, value = processed_source.tokens[index, 3]
|
15
|
+
check_optarg(arg, equals, value)
|
20
16
|
end
|
21
17
|
|
22
18
|
private
|
@@ -11,18 +11,16 @@ module RuboCop
|
|
11
11
|
|
12
12
|
MSG = 'Space inside %s.'
|
13
13
|
|
14
|
-
def
|
15
|
-
|
14
|
+
def on_hash(node)
|
15
|
+
b_ix = index_of_first_token(node)
|
16
16
|
tokens = processed_source.tokens
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
18
|
+
# Hash literal with braces?
|
19
|
+
return unless tokens[b_ix].type == :tLBRACE
|
20
|
+
|
21
|
+
e_ix = index_of_last_token(node)
|
22
|
+
check(tokens[b_ix], tokens[b_ix + 1])
|
23
|
+
check(tokens[e_ix - 1], tokens[e_ix]) unless b_ix == e_ix - 1
|
26
24
|
end
|
27
25
|
|
28
26
|
private
|
@@ -69,7 +67,7 @@ module RuboCop
|
|
69
67
|
@corrections << lambda do |corrector|
|
70
68
|
# It is possible that BracesAroundHashParameters will remove the
|
71
69
|
# braces while this cop inserts spaces. This can lead to unwanted
|
72
|
-
# changes to the inspected code.
|
70
|
+
# changes to the inspected code. If we replace the brace with a
|
73
71
|
# brace plus space (rather than just inserting a space), then any
|
74
72
|
# removal of the same brace will give us a clobbering error. This
|
75
73
|
# in turn will make RuboCop fall back on cop-by-cop
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for spaces inside range literals.
|
7
|
+
# @example
|
8
|
+
# # bad
|
9
|
+
# 1 .. 3
|
10
|
+
#
|
11
|
+
# # good
|
12
|
+
# 1..3
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# 'a' .. 'z'
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# 'a'..'z'
|
19
|
+
class SpaceInsideRangeLiteral < Cop
|
20
|
+
MSG = 'Space inside range literal.'
|
21
|
+
|
22
|
+
def on_irange(node)
|
23
|
+
check(node)
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_erange(node)
|
27
|
+
check(node)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def check(node)
|
33
|
+
expression = node.loc.expression.source
|
34
|
+
operator = node.loc.operator.source.gsub(/\./, '\.')
|
35
|
+
|
36
|
+
return unless expression =~ /(\s#{operator})|(#{operator}\s)/
|
37
|
+
|
38
|
+
add_offense(node, :expression)
|
39
|
+
end
|
40
|
+
|
41
|
+
def autocorrect(node)
|
42
|
+
expression = node.loc.expression.source
|
43
|
+
operator = node.loc.operator.source
|
44
|
+
operator_escaped = operator.gsub(/\./, '\.')
|
45
|
+
|
46
|
+
@corrections << lambda do |corrector|
|
47
|
+
corrector.replace(
|
48
|
+
node.loc.expression,
|
49
|
+
expression
|
50
|
+
.sub(/\s+#{operator_escaped}/, operator)
|
51
|
+
.sub(/#{operator_escaped}\s+/, operator)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -55,7 +55,7 @@ module RuboCop
|
|
55
55
|
NON_ENGLISH_VARS.include? var
|
56
56
|
end
|
57
57
|
|
58
|
-
# For now, we assume that lists are 2 items or less.
|
58
|
+
# For now, we assume that lists are 2 items or less. Easy grammar!
|
59
59
|
regular_msg = regular.join('` or `')
|
60
60
|
english_msg = english.join('` or `')
|
61
61
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Use symbols as procs when possible.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# something.map { |s| s.upcase }
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# something.map(&:upcase)
|
14
|
+
class SymbolProc < Cop
|
15
|
+
MSG = 'Pass `&:%s` as an argument to `%s` instead of a block.'
|
16
|
+
|
17
|
+
def on_block(node)
|
18
|
+
block_send, block_args, block_body = *node
|
19
|
+
|
20
|
+
_breceiver, bmethod_name, bargs = *block_send
|
21
|
+
|
22
|
+
# we should ignore lambdas
|
23
|
+
return if bmethod_name == :lambda
|
24
|
+
return if ignored_method?(bmethod_name)
|
25
|
+
# File.open(file) { |f| f.readlines }
|
26
|
+
return if bargs
|
27
|
+
# something { |x, y| ... }
|
28
|
+
return unless block_args.children.size == 1
|
29
|
+
return unless block_body && block_body.type == :send
|
30
|
+
|
31
|
+
receiver, method_name, args = *block_body
|
32
|
+
|
33
|
+
# method in block must be invoked on a lvar without args
|
34
|
+
return if args
|
35
|
+
return if receiver.type != :lvar
|
36
|
+
|
37
|
+
block_arg_name, = *block_args.children.first
|
38
|
+
receiver_name, = *receiver
|
39
|
+
|
40
|
+
return if block_arg_name != receiver_name
|
41
|
+
|
42
|
+
add_offense(node,
|
43
|
+
:expression,
|
44
|
+
format(MSG,
|
45
|
+
method_name,
|
46
|
+
bmethod_name))
|
47
|
+
end
|
48
|
+
|
49
|
+
def autocorrect(node)
|
50
|
+
@corrections << lambda do |corrector|
|
51
|
+
block_method, _block_args, block_body = *node
|
52
|
+
_receiver, method_name, _args = *block_body
|
53
|
+
|
54
|
+
replacement = "#{block_method.loc.expression.source}" \
|
55
|
+
"(&:#{method_name})"
|
56
|
+
|
57
|
+
corrector.replace(node.loc.expression, replacement)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ignored_methods
|
62
|
+
cop_config['IgnoredMethods']
|
63
|
+
end
|
64
|
+
|
65
|
+
def ignored_method?(name)
|
66
|
+
ignored_methods.include?(name.to_s)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|