rubocop 0.31.0 → 0.35.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/CHANGELOG.md +315 -0
- data/README.md +199 -38
- data/config/default.yml +91 -12
- data/config/disabled.yml +45 -4
- data/config/enabled.yml +107 -9
- data/lib/rubocop/ast_node.rb +48 -0
- data/lib/rubocop/cli.rb +11 -1
- data/lib/rubocop/comment_config.rb +4 -1
- data/lib/rubocop/config.rb +26 -17
- data/lib/rubocop/config_loader.rb +61 -14
- data/lib/rubocop/cop/commissioner.rb +7 -12
- data/lib/rubocop/cop/cop.rb +43 -20
- data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +69 -0
- data/lib/rubocop/cop/lint/debugger.rb +9 -48
- data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +42 -23
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
- data/lib/rubocop/cop/lint/duplicated_key.rb +37 -0
- data/lib/rubocop/cop/lint/end_alignment.rb +33 -13
- data/lib/rubocop/cop/lint/eval.rb +6 -2
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +175 -0
- data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +10 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +31 -0
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +19 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/lint/unneeded_disable.rb +72 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +17 -6
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -3
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -2
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +28 -4
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_naming.rb +14 -3
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -3
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +10 -1
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
- data/lib/rubocop/cop/mixin/if_node.rb +10 -0
- data/lib/rubocop/cop/mixin/method_preference.rb +28 -0
- data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
- data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
- data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +8 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +8 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -7
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +5 -4
- data/lib/rubocop/cop/offense.rb +16 -3
- data/lib/rubocop/cop/performance/case_when_splat.rb +160 -0
- data/lib/rubocop/cop/performance/count.rb +35 -30
- data/lib/rubocop/cop/performance/detect.rb +16 -3
- data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
- data/lib/rubocop/cop/performance/flat_map.rb +3 -3
- data/lib/rubocop/cop/performance/sample.rb +103 -59
- data/lib/rubocop/cop/performance/size.rb +2 -1
- data/lib/rubocop/cop/performance/string_replacement.rb +187 -0
- data/lib/rubocop/cop/rails/action_filter.rb +31 -5
- data/lib/rubocop/cop/rails/date.rb +15 -14
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
- data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +46 -18
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/align_hash.rb +8 -15
- data/lib/rubocop/cop/style/align_parameters.rb +19 -7
- data/lib/rubocop/cop/style/and_or.rb +42 -13
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -1
- data/lib/rubocop/cop/style/block_comments.rb +4 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +69 -24
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +40 -12
- data/lib/rubocop/cop/style/case_indentation.rb +18 -4
- data/lib/rubocop/cop/style/collection_methods.rb +2 -20
- data/lib/rubocop/cop/style/command_literal.rb +2 -10
- data/lib/rubocop/cop/style/comment_annotation.rb +29 -8
- data/lib/rubocop/cop/style/copyright.rb +5 -3
- data/lib/rubocop/cop/style/documentation.rb +21 -12
- data/lib/rubocop/cop/style/dot_position.rb +6 -0
- data/lib/rubocop/cop/style/double_negation.rb +4 -15
- data/lib/rubocop/cop/style/each_with_object.rb +17 -4
- data/lib/rubocop/cop/style/else_alignment.rb +2 -1
- data/lib/rubocop/cop/style/empty_else.rb +25 -0
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +39 -14
- data/lib/rubocop/cop/style/encoding.rb +10 -4
- data/lib/rubocop/cop/style/extra_spacing.rb +126 -5
- data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
- data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
- data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
- data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +5 -3
- data/lib/rubocop/cop/style/for.rb +2 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -5
- data/lib/rubocop/cop/style/indent_hash.rb +67 -37
- data/lib/rubocop/cop/style/indentation_width.rb +36 -10
- data/lib/rubocop/cop/style/initial_indentation.rb +37 -0
- data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
- data/lib/rubocop/cop/style/method_call_parentheses.rb +28 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +21 -24
- data/lib/rubocop/cop/style/mutable_constant.rb +35 -0
- data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
- data/lib/rubocop/cop/style/next.rb +50 -15
- data/lib/rubocop/cop/style/non_nil_check.rb +12 -8
- data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
- data/lib/rubocop/cop/style/option_hash.rb +64 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +218 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
- data/lib/rubocop/cop/style/predicate_name.rb +7 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -13
- data/lib/rubocop/cop/style/redundant_freeze.rb +37 -0
- data/lib/rubocop/cop/style/redundant_return.rb +32 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +81 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +30 -22
- data/lib/rubocop/cop/style/send.rb +18 -0
- data/lib/rubocop/cop/style/signal_exception.rb +24 -11
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -9
- data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +61 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
- data/lib/rubocop/cop/style/string_methods.rb +32 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +11 -10
- data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +62 -13
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +9 -1
- data/lib/rubocop/cop/style/trailing_comma.rb +17 -7
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
- data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
- data/lib/rubocop/cop/style/variable_name.rb +5 -0
- data/lib/rubocop/cop/style/while_until_do.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +15 -2
- data/lib/rubocop/cop/team.rb +25 -5
- data/lib/rubocop/cop/util.rb +7 -2
- data/lib/rubocop/cop/variable_force/locatable.rb +6 -6
- data/lib/rubocop/cop/variable_force.rb +10 -10
- data/lib/rubocop/formatter/base_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +70 -8
- data/lib/rubocop/formatter/formatter_set.rb +27 -1
- data/lib/rubocop/formatter/progress_formatter.rb +10 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
- data/lib/rubocop/node_pattern.rb +390 -0
- data/lib/rubocop/options.rb +148 -81
- data/lib/rubocop/processed_source.rb +7 -2
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +60 -0
- data/lib/rubocop/result_cache.rb +123 -0
- data/lib/rubocop/runner.rb +85 -22
- data/lib/rubocop/target_finder.rb +4 -4
- data/lib/rubocop/token.rb +2 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/warning.rb +11 -0
- data/lib/rubocop.rb +32 -3
- data/relnotes/v0.32.0.md +139 -0
- data/relnotes/v0.32.1.md +122 -0
- data/relnotes/v0.33.0.md +157 -0
- data/relnotes/v0.34.0.md +182 -0
- data/relnotes/v0.34.1.md +129 -0
- data/relnotes/v0.34.2.md +139 -0
- data/relnotes/v0.35.0.md +210 -0
- data/rubocop.gemspec +4 -4
- metadata +50 -12
- data/lib/rubocop/cop/performance/parallel_assignment.rb +0 -79
|
@@ -5,28 +5,75 @@ module RuboCop
|
|
|
5
5
|
# Handles `EnforcedStyle` configuration parameters.
|
|
6
6
|
module ConfigurableEnforcedStyle
|
|
7
7
|
def opposite_style_detected
|
|
8
|
-
|
|
9
|
-
{ parameter_name => alternative_style.to_s }
|
|
10
|
-
both_styles_detected if config_to_allow_offenses['Enabled']
|
|
8
|
+
style_detected(alternative_style)
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def correct_style_detected
|
|
14
|
-
|
|
15
|
-
# that the correct style is used somewhere.
|
|
16
|
-
self.config_to_allow_offenses ||= { 'Enabled' => true }
|
|
17
|
-
both_styles_detected if config_to_allow_offenses[parameter_name]
|
|
12
|
+
style_detected(style)
|
|
18
13
|
end
|
|
19
14
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
def unexpected_style_detected(unexpected)
|
|
16
|
+
style_detected(unexpected)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ambiguous_style_detected(*possibilities)
|
|
20
|
+
style_detected(possibilities)
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
def
|
|
26
|
-
#
|
|
23
|
+
def style_detected(detected)
|
|
24
|
+
# `detected` can be a single style, or an Array of possible styles
|
|
25
|
+
# (if there is more than one which matches the observed code)
|
|
26
|
+
|
|
27
|
+
return if no_acceptable_style?
|
|
28
|
+
|
|
29
|
+
if detected.is_a?(Array)
|
|
30
|
+
detected.map!(&:to_s)
|
|
31
|
+
else
|
|
32
|
+
detected = detected.to_s
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if !detected_style # we haven't observed any specific style yet
|
|
36
|
+
self.detected_style = detected
|
|
37
|
+
elsif detected_style.is_a?(Array)
|
|
38
|
+
self.detected_style &= [*detected]
|
|
39
|
+
elsif detected.is_a?(Array)
|
|
40
|
+
no_acceptable_style! unless detected.include?(detected_style)
|
|
41
|
+
else
|
|
42
|
+
no_acceptable_style! unless detected_style == detected
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def no_acceptable_style?
|
|
47
|
+
config_to_allow_offenses['Enabled'] == false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def no_acceptable_style!
|
|
27
51
|
self.config_to_allow_offenses = { 'Enabled' => false }
|
|
28
52
|
end
|
|
29
53
|
|
|
54
|
+
def detected_style
|
|
55
|
+
config_to_allow_offenses[parameter_name]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def detected_style=(style)
|
|
59
|
+
if style.nil?
|
|
60
|
+
no_acceptable_style!
|
|
61
|
+
elsif style.is_a?(Array)
|
|
62
|
+
if style.empty?
|
|
63
|
+
no_acceptable_style!
|
|
64
|
+
elsif style.one?
|
|
65
|
+
config_to_allow_offenses[parameter_name] = style[0]
|
|
66
|
+
else
|
|
67
|
+
config_to_allow_offenses[parameter_name] = style
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
config_to_allow_offenses[parameter_name] = style
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
alias_method :conflicting_styles_detected, :no_acceptable_style!
|
|
75
|
+
alias_method :unrecognized_style_detected, :no_acceptable_style!
|
|
76
|
+
|
|
30
77
|
def style
|
|
31
78
|
s = cop_config[parameter_name]
|
|
32
79
|
if cop_config['SupportedStyles'].include?(s)
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
|
6
6
|
# appropriate value with --auto-gen-config.
|
|
7
7
|
module ConfigurableMax
|
|
8
8
|
def max=(value)
|
|
9
|
-
cfg =
|
|
9
|
+
cfg = config_to_allow_offenses
|
|
10
10
|
value = [cfg[parameter_name], value].max if cfg[parameter_name]
|
|
11
11
|
cfg[parameter_name] = value
|
|
12
12
|
end
|
|
@@ -13,7 +13,7 @@ module RuboCop
|
|
|
13
13
|
def check_name(node, name, name_range)
|
|
14
14
|
return if operator?(name)
|
|
15
15
|
|
|
16
|
-
if valid_name?(name)
|
|
16
|
+
if valid_name?(node, name)
|
|
17
17
|
correct_style_detected
|
|
18
18
|
else
|
|
19
19
|
add_offense(node, name_range, message(style)) do
|
|
@@ -22,9 +22,20 @@ module RuboCop
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def valid_name?(name)
|
|
25
|
+
def valid_name?(node, name)
|
|
26
26
|
pattern = (style == :snake_case ? SNAKE_CASE : CAMEL_CASE)
|
|
27
|
-
name.match(pattern)
|
|
27
|
+
name.match(pattern) || class_emitter_method?(node, name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# A class emitter method is a singleton method in a class/module, where
|
|
31
|
+
# the method has the same name as a class defined in the class/module.
|
|
32
|
+
def class_emitter_method?(node, name)
|
|
33
|
+
return false unless node.defs_type?
|
|
34
|
+
return false unless node.parent
|
|
35
|
+
|
|
36
|
+
node.parent.children.compact.any? do |c|
|
|
37
|
+
c.class_type? && c.loc.name.is?(name.to_s)
|
|
38
|
+
end
|
|
28
39
|
end
|
|
29
40
|
end
|
|
30
41
|
end
|
|
@@ -34,9 +34,7 @@ module RuboCop
|
|
|
34
34
|
def check_source(start_line, end_line)
|
|
35
35
|
case style
|
|
36
36
|
when :no_empty_lines
|
|
37
|
-
check_both(start_line, end_line, MSG_EXTRA)
|
|
38
|
-
line.empty?
|
|
39
|
-
end
|
|
37
|
+
check_both(start_line, end_line, MSG_EXTRA, &:empty?)
|
|
40
38
|
when :empty_lines
|
|
41
39
|
check_both(start_line, end_line, MSG_MISSING) do |line|
|
|
42
40
|
!line.empty?
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
|
6
6
|
module EndKeywordAlignment
|
|
7
7
|
include ConfigurableEnforcedStyle
|
|
8
8
|
|
|
9
|
-
MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d'
|
|
9
|
+
MSG = '`end` at %d, %d is not aligned with `%s` at %d, %d.'
|
|
10
10
|
|
|
11
11
|
private
|
|
12
12
|
|
|
@@ -38,6 +38,15 @@ module RuboCop
|
|
|
38
38
|
'AlignWith'
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def variable_alignment?(whole_expression, rhs, end_alignment_style)
|
|
42
|
+
end_alignment_style == :variable &&
|
|
43
|
+
!line_break_before_keyword?(whole_expression, rhs)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def line_break_before_keyword?(whole_expression, rhs)
|
|
47
|
+
rhs.loc.line > whole_expression.line
|
|
48
|
+
end
|
|
49
|
+
|
|
41
50
|
def align(node, alignment_node)
|
|
42
51
|
source_buffer = node.loc.expression.source_buffer
|
|
43
52
|
begin_pos = node.loc.end.begin_pos
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Common functionality for checking for a line break before the first
|
|
6
|
+
# element in a multi-line collection.
|
|
7
|
+
module FirstElementLineBreak
|
|
8
|
+
def autocorrect(node)
|
|
9
|
+
->(corrector) { corrector.insert_before(node.loc.expression, "\n") }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def check_method_line_break(node, children)
|
|
15
|
+
return if children.empty?
|
|
16
|
+
|
|
17
|
+
return unless method_uses_parens?(node, children.first)
|
|
18
|
+
|
|
19
|
+
check_children_line_break(node, children)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def method_uses_parens?(node, limit)
|
|
23
|
+
source = node.loc.expression.source_line[0...limit.loc.column]
|
|
24
|
+
source =~ /\s*\(\s*$/
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check_children_line_break(node, children, start = node)
|
|
28
|
+
return if children.size < 2
|
|
29
|
+
|
|
30
|
+
line = start.loc.line
|
|
31
|
+
min = children.min_by { |n| n.loc.first_line }
|
|
32
|
+
return if line != min.loc.first_line
|
|
33
|
+
|
|
34
|
+
max = children.max_by { |n| n.loc.last_line }
|
|
35
|
+
return if line == max.loc.last_line
|
|
36
|
+
|
|
37
|
+
add_offense(min, :expression, self.class::MSG)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -22,6 +22,16 @@ module RuboCop
|
|
|
22
22
|
def if_else?(node)
|
|
23
23
|
node.loc.respond_to?(:else) && node.loc.else
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
def if_node_parts(node)
|
|
27
|
+
case node.loc.keyword.source
|
|
28
|
+
when 'if', 'elsif' then condition, body, else_clause = *node
|
|
29
|
+
when 'unless' then condition, else_clause, body = *node
|
|
30
|
+
else condition, body = *node
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
[condition, body, else_clause]
|
|
34
|
+
end
|
|
25
35
|
end
|
|
26
36
|
end
|
|
27
37
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Common code for cops that deal with preferred methods.
|
|
6
|
+
module MethodPreference
|
|
7
|
+
def preferred_method(method)
|
|
8
|
+
preferred_methods[method.to_sym]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def preferred_methods
|
|
12
|
+
@preferred_methods ||=
|
|
13
|
+
begin
|
|
14
|
+
# Make sure default configuration 'foo' => 'bar' is removed from
|
|
15
|
+
# the total configuration if there is a 'bar' => 'foo' override.
|
|
16
|
+
default = default_cop_config['PreferredMethods']
|
|
17
|
+
merged = cop_config['PreferredMethods']
|
|
18
|
+
overrides = merged.values - default.values
|
|
19
|
+
merged.reject { |key, _| overrides.include?(key) }.symbolize_keys
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def default_cop_config
|
|
24
|
+
ConfigLoader.default_configuration[cop_name]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
|
8
8
|
def check_negative_conditional(node)
|
|
9
9
|
condition, _body, _rest = *node
|
|
10
10
|
|
|
11
|
-
# Look at last expression of contents if there
|
|
11
|
+
# Look at last expression of contents if there are parentheses
|
|
12
12
|
# around condition.
|
|
13
13
|
condition = condition.children.last while condition.type == :begin
|
|
14
14
|
return unless condition.type == :send
|
|
@@ -19,12 +19,11 @@ module RuboCop
|
|
|
19
19
|
# Returns true for constructs such as
|
|
20
20
|
# private def my_method
|
|
21
21
|
# which are allowed in Ruby 2.1 and later.
|
|
22
|
-
def
|
|
22
|
+
def modifier_and_def_on_same_line?(receiver, method_name, args)
|
|
23
23
|
!receiver &&
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
args.size == 1 && [:def, :defs].include?(args.first.type)
|
|
24
|
+
method_name != :def &&
|
|
25
|
+
args.size == 1 &&
|
|
26
|
+
[:def, :defs].include?(args.first.type)
|
|
28
27
|
end
|
|
29
28
|
end
|
|
30
29
|
end
|
|
@@ -6,21 +6,10 @@ module RuboCop
|
|
|
6
6
|
# putting parentheses around an assignment to indicate "I know I'm using an
|
|
7
7
|
# assignment as a condition. It's not a mistake."
|
|
8
8
|
module SafeAssignment
|
|
9
|
-
|
|
10
|
-
return false unless node.type == :begin
|
|
11
|
-
return false unless node.children.size == 1
|
|
9
|
+
extend NodePattern::Macros
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
when *Util::EQUALS_ASGN_NODES
|
|
16
|
-
true
|
|
17
|
-
when :send
|
|
18
|
-
_receiver, method_name, _args = *child
|
|
19
|
-
method_name.to_s.end_with?('=')
|
|
20
|
-
else
|
|
21
|
-
false
|
|
22
|
-
end
|
|
23
|
-
end
|
|
11
|
+
def_node_matcher :safe_assignment?,
|
|
12
|
+
'(begin {equals_asgn? asgn_method_call?})'
|
|
24
13
|
|
|
25
14
|
def safe_assignment_allowed?
|
|
26
15
|
cop_config['AllowSafeAssignment']
|
|
@@ -11,12 +11,19 @@ module RuboCop
|
|
|
11
11
|
processed_source.tokens.each_cons(2) do |t1, t2|
|
|
12
12
|
next unless kind(t1) && t1.pos.line == t2.pos.line &&
|
|
13
13
|
t2.pos.column == t1.pos.column + offset &&
|
|
14
|
-
![:tRPAREN, :tRBRACK, :tPIPE].include?(t2.type)
|
|
14
|
+
![:tRPAREN, :tRBRACK, :tPIPE].include?(t2.type) &&
|
|
15
|
+
!(t2.type == :tRCURLY && space_forbidden_before_rcurly?)
|
|
15
16
|
|
|
16
17
|
add_offense(t1, t1.pos, format(MSG, kind(t1)))
|
|
17
18
|
end
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
def space_forbidden_before_rcurly?
|
|
22
|
+
cfg = config.for_cop('Style/SpaceInsideBlockBraces')
|
|
23
|
+
style = cfg['Enabled'] ? cfg['EnforcedStyle'] : 'space'
|
|
24
|
+
style == 'no_space'
|
|
25
|
+
end
|
|
26
|
+
|
|
20
27
|
# The normal offset, i.e., the distance from the punctuation
|
|
21
28
|
# token where a space should be, is 1.
|
|
22
29
|
def offset
|
|
@@ -10,7 +10,8 @@ module RuboCop
|
|
|
10
10
|
def investigate(processed_source)
|
|
11
11
|
processed_source.tokens.each_cons(2) do |t1, t2|
|
|
12
12
|
next unless kind(t2) && t1.pos.line == t2.pos.line &&
|
|
13
|
-
t2.pos.begin_pos > t1.pos.end_pos
|
|
13
|
+
t2.pos.begin_pos > t1.pos.end_pos &&
|
|
14
|
+
!(t1.type == :tLCURLY && space_required_after_lcurly?)
|
|
14
15
|
buffer = processed_source.buffer
|
|
15
16
|
pos_before_punctuation = Parser::Source::Range.new(buffer,
|
|
16
17
|
t1.pos.end_pos,
|
|
@@ -22,6 +23,12 @@ module RuboCop
|
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
def space_required_after_lcurly?
|
|
27
|
+
cfg = config.for_cop('Style/SpaceInsideBlockBraces')
|
|
28
|
+
style = cfg['Enabled'] ? cfg['EnforcedStyle'] : 'space'
|
|
29
|
+
style == 'space'
|
|
30
|
+
end
|
|
31
|
+
|
|
25
32
|
def autocorrect(pos_before_punctuation)
|
|
26
33
|
->(corrector) { corrector.remove(pos_before_punctuation) }
|
|
27
34
|
end
|
|
@@ -7,13 +7,10 @@ module RuboCop
|
|
|
7
7
|
include IfNode
|
|
8
8
|
|
|
9
9
|
def fit_within_line_as_modifier_form?(node)
|
|
10
|
-
|
|
11
|
-
when 'if' then cond, body, _else = *node
|
|
12
|
-
when 'unless' then cond, _else, body = *node
|
|
13
|
-
else cond, body = *node
|
|
14
|
-
end
|
|
10
|
+
cond, body, _else = if_node_parts(node)
|
|
15
11
|
|
|
16
12
|
return false if length(node) > 3
|
|
13
|
+
return false if body && body.begin_type? # multiple statements
|
|
17
14
|
|
|
18
15
|
body_length = body_length(body)
|
|
19
16
|
|
|
@@ -33,7 +30,7 @@ module RuboCop
|
|
|
33
30
|
end
|
|
34
31
|
|
|
35
32
|
def max_line_length
|
|
36
|
-
cop_config
|
|
33
|
+
cop_config['MaxLineLength'] ||
|
|
37
34
|
config.for_cop('Metrics/LineLength')['Max']
|
|
38
35
|
end
|
|
39
36
|
|
|
@@ -58,7 +55,7 @@ module RuboCop
|
|
|
58
55
|
end
|
|
59
56
|
|
|
60
57
|
def comment_lines
|
|
61
|
-
@comment_lines ||= processed_source.comments.map
|
|
58
|
+
@comment_lines ||= processed_source.comments.map { |c| c.location.line }
|
|
62
59
|
end
|
|
63
60
|
end
|
|
64
61
|
end
|
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
|
31
31
|
def inside_interpolation?(node)
|
|
32
32
|
# A :begin node inside a :dstr node is an interpolation.
|
|
33
33
|
begin_found = false
|
|
34
|
-
node.each_ancestor.
|
|
34
|
+
node.each_ancestor.any? do |a|
|
|
35
35
|
begin_found = true if a.type == :begin
|
|
36
36
|
begin_found && a.type == :dstr
|
|
37
37
|
end
|
|
@@ -17,13 +17,13 @@ module RuboCop
|
|
|
17
17
|
|
|
18
18
|
def index_of_first_token(node)
|
|
19
19
|
b = node.loc.expression.begin
|
|
20
|
-
token_table[
|
|
20
|
+
token_table[b.line][b.column]
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def index_of_last_token(node)
|
|
24
24
|
e = node.loc.expression.end
|
|
25
|
-
(0...e.column).to_a.
|
|
26
|
-
ix = token_table[
|
|
25
|
+
(0...e.column).to_a.reverse_each do |c|
|
|
26
|
+
ix = token_table[e.line][c]
|
|
27
27
|
return ix if ix
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -32,7 +32,8 @@ module RuboCop
|
|
|
32
32
|
@token_table ||= begin
|
|
33
33
|
table = {}
|
|
34
34
|
@processed_source.tokens.each_with_index do |t, ix|
|
|
35
|
-
table[
|
|
35
|
+
table[t.pos.line] ||= {}
|
|
36
|
+
table[t.pos.line][t.pos.column] = ix
|
|
36
37
|
end
|
|
37
38
|
table
|
|
38
39
|
end
|
data/lib/rubocop/cop/offense.rb
CHANGED
|
@@ -56,16 +56,29 @@ module RuboCop
|
|
|
56
56
|
#
|
|
57
57
|
# @return [Boolean]
|
|
58
58
|
# whether this offense is automatically corrected.
|
|
59
|
-
|
|
59
|
+
def corrected
|
|
60
|
+
@status == :unsupported ? nil : @status == :corrected
|
|
61
|
+
end
|
|
60
62
|
alias_method :corrected?, :corrected
|
|
61
63
|
|
|
64
|
+
# @api public
|
|
65
|
+
#
|
|
66
|
+
# @!attribute [r] disabled?
|
|
67
|
+
#
|
|
68
|
+
# @return [Boolean]
|
|
69
|
+
# whether this offense was locally disabled where it occurred
|
|
70
|
+
def disabled?
|
|
71
|
+
@status == :disabled
|
|
72
|
+
end
|
|
73
|
+
|
|
62
74
|
# @api private
|
|
63
|
-
def initialize(severity, location, message, cop_name,
|
|
75
|
+
def initialize(severity, location, message, cop_name,
|
|
76
|
+
status = :uncorrected)
|
|
64
77
|
@severity = RuboCop::Cop::Severity.new(severity)
|
|
65
78
|
@location = location
|
|
66
79
|
@message = message.freeze
|
|
67
80
|
@cop_name = cop_name.freeze
|
|
68
|
-
@
|
|
81
|
+
@status = status
|
|
69
82
|
freeze
|
|
70
83
|
end
|
|
71
84
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Performance
|
|
6
|
+
# Place `when` conditions that use splat at the end
|
|
7
|
+
# of the list of `when` branches.
|
|
8
|
+
#
|
|
9
|
+
# Ruby has to allocate memory for the splat expansion every time
|
|
10
|
+
# that the `case` `when` statement is run. Since Ruby does not support
|
|
11
|
+
# fall through inside of `case` `when`, like some other languages do,
|
|
12
|
+
# the order of the `when` branches does not matter. By placing any
|
|
13
|
+
# splat expansions at the end of the list of `when` branches we will
|
|
14
|
+
# reduce the number of times that memory has to be allocated for
|
|
15
|
+
# the expansion.
|
|
16
|
+
#
|
|
17
|
+
# This is not a guaranteed performance improvement. If the data being
|
|
18
|
+
# processed by the `case` condition is normalized in a manner that favors
|
|
19
|
+
# hitting a condition in the splat expansion, it is possible that
|
|
20
|
+
# moving the splat condition to the end will use more memory,
|
|
21
|
+
# and run slightly slower.
|
|
22
|
+
#
|
|
23
|
+
# @example
|
|
24
|
+
# # bad
|
|
25
|
+
# case foo
|
|
26
|
+
# when *condition
|
|
27
|
+
# bar
|
|
28
|
+
# when baz
|
|
29
|
+
# foobar
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# case foo
|
|
33
|
+
# when *[1, 2, 3, 4]
|
|
34
|
+
# bar
|
|
35
|
+
# when 5
|
|
36
|
+
# baz
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# # good
|
|
40
|
+
# case foo
|
|
41
|
+
# when baz
|
|
42
|
+
# foobar
|
|
43
|
+
# when *condition
|
|
44
|
+
# bar
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# case foo
|
|
48
|
+
# when 1, 2, 3, 4
|
|
49
|
+
# bar
|
|
50
|
+
# when 5
|
|
51
|
+
# baz
|
|
52
|
+
# end
|
|
53
|
+
class CaseWhenSplat < Cop
|
|
54
|
+
include AutocorrectAlignment
|
|
55
|
+
|
|
56
|
+
MSG = 'Place `when` conditions with a splat ' \
|
|
57
|
+
'at the end of the `when` branches.'.freeze
|
|
58
|
+
ARRAY_MSG = 'Do not expand array literals in `when` conditions.'.freeze
|
|
59
|
+
OPEN_BRACKET = '['.freeze
|
|
60
|
+
PERCENT_W = '%w'.freeze
|
|
61
|
+
PERCENT_CAPITAL_W = '%W'.freeze
|
|
62
|
+
PERCENT_I = '%i'.freeze
|
|
63
|
+
PERCENT_CAPITAL_I = '%I'.freeze
|
|
64
|
+
|
|
65
|
+
def on_case(node)
|
|
66
|
+
_case_branch, *when_branches, _else_branch = *node
|
|
67
|
+
when_conditions =
|
|
68
|
+
when_branches.each_with_object([]) do |branch, conditions|
|
|
69
|
+
condition, = *branch
|
|
70
|
+
conditions << condition
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
splat_offenses(when_conditions).reverse_each do |condition|
|
|
74
|
+
range = condition.parent.loc.keyword.join(condition.loc.expression)
|
|
75
|
+
variable, = *condition
|
|
76
|
+
message = variable.array_type? ? ARRAY_MSG : MSG
|
|
77
|
+
add_offense(condition.parent, range, message)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def autocorrect(node)
|
|
82
|
+
condition, = *node
|
|
83
|
+
variable, = *condition
|
|
84
|
+
if variable.array_type?
|
|
85
|
+
correct_array_literal(condition, variable)
|
|
86
|
+
else
|
|
87
|
+
reorder_splat_condition(node)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def splat_offenses(when_conditions)
|
|
94
|
+
found_non_splat = false
|
|
95
|
+
when_conditions.reverse.each_with_object([]) do |condition, result|
|
|
96
|
+
found_non_splat ||= true if error_condition?(condition)
|
|
97
|
+
|
|
98
|
+
next unless condition.splat_type?
|
|
99
|
+
result << condition if found_non_splat
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def error_condition?(condition)
|
|
104
|
+
variable, = *condition
|
|
105
|
+
|
|
106
|
+
(condition.splat_type? && variable.array_type?) ||
|
|
107
|
+
!condition.splat_type?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def correct_array_literal(condition, variable)
|
|
111
|
+
lambda do |corrector|
|
|
112
|
+
array_start = variable.loc.begin.source
|
|
113
|
+
|
|
114
|
+
if array_start.start_with?(OPEN_BRACKET)
|
|
115
|
+
corrector.remove(condition.loc.operator)
|
|
116
|
+
corrector.remove(variable.loc.begin)
|
|
117
|
+
corrector.remove(variable.loc.end)
|
|
118
|
+
else
|
|
119
|
+
corrector.replace(condition.loc.expression,
|
|
120
|
+
expand_percent_array(variable))
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def reorder_splat_condition(node)
|
|
126
|
+
_case_branch, *when_branches, _else_branch = *node.parent
|
|
127
|
+
current_index = when_branches.index { |branch| branch == node }
|
|
128
|
+
next_branch = when_branches[current_index + 1]
|
|
129
|
+
correction = "\n#{offset(node)}#{node.loc.expression.source}"
|
|
130
|
+
range =
|
|
131
|
+
Parser::Source::Range.new(node.parent,
|
|
132
|
+
node.loc.expression.begin_pos,
|
|
133
|
+
next_branch.loc.expression.begin_pos)
|
|
134
|
+
|
|
135
|
+
lambda do |corrector|
|
|
136
|
+
corrector.remove(range)
|
|
137
|
+
corrector.insert_after(when_branches.last.loc.expression,
|
|
138
|
+
correction)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def expand_percent_array(array)
|
|
143
|
+
array_start = array.loc.begin.source
|
|
144
|
+
elements = *array
|
|
145
|
+
elements = elements.map { |e| e.loc.expression.source }
|
|
146
|
+
|
|
147
|
+
if array_start.start_with?(PERCENT_W)
|
|
148
|
+
"'#{elements.join("', '")}'"
|
|
149
|
+
elsif array_start.start_with?(PERCENT_CAPITAL_W)
|
|
150
|
+
%("#{elements.join('", "')}")
|
|
151
|
+
elsif array_start.start_with?(PERCENT_I)
|
|
152
|
+
":#{elements.join(', :')}"
|
|
153
|
+
elsif array_start.start_with?(PERCENT_CAPITAL_I)
|
|
154
|
+
%(:"#{elements.join('", :"')}")
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|