rubocop 0.48.1 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -3
- data/config/default.yml +397 -357
- data/config/disabled.yml +29 -29
- data/config/enabled.yml +366 -326
- data/lib/rubocop.rb +85 -70
- data/lib/rubocop/ast/builder.rb +4 -1
- data/lib/rubocop/ast/node.rb +2 -2
- data/lib/rubocop/ast/node/and_node.rb +1 -1
- data/lib/rubocop/ast/node/args_node.rb +24 -0
- data/lib/rubocop/ast/node/block_node.rb +107 -0
- data/lib/rubocop/ast/node/case_node.rb +1 -1
- data/lib/rubocop/ast/node/ensure_node.rb +1 -1
- data/lib/rubocop/ast/node/for_node.rb +1 -1
- data/lib/rubocop/ast/node/if_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +74 -0
- data/lib/rubocop/ast/node/or_node.rb +1 -1
- data/lib/rubocop/ast/node/pair_node.rb +1 -1
- data/lib/rubocop/ast/node/resbody_node.rb +1 -1
- data/lib/rubocop/ast/node/send_node.rb +36 -57
- data/lib/rubocop/ast/node/super_node.rb +42 -0
- data/lib/rubocop/ast/node/until_node.rb +1 -1
- data/lib/rubocop/ast/node/when_node.rb +1 -1
- data/lib/rubocop/ast/node/while_node.rb +1 -1
- data/lib/rubocop/cli.rb +10 -0
- data/lib/rubocop/config.rb +23 -7
- data/lib/rubocop/config_loader.rb +19 -3
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
- data/lib/rubocop/cop/commissioner.rb +1 -1
- data/lib/rubocop/cop/cop.rb +10 -0
- data/lib/rubocop/cop/{style → layout}/access_modifier_indentation.rb +33 -3
- data/lib/rubocop/cop/{style → layout}/align_array.rb +16 -1
- data/lib/rubocop/cop/{style → layout}/align_hash.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/align_parameters.rb +29 -1
- data/lib/rubocop/cop/{style → layout}/block_end_newline.rb +10 -5
- data/lib/rubocop/cop/{style → layout}/case_indentation.rb +64 -1
- data/lib/rubocop/cop/{style → layout}/closing_parenthesis_indentation.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/comment_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/dot_position.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/else_alignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_line_after_magic_comment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_access_modifier.rb +2 -7
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_begin_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_block_body.rb +2 -4
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_method_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_module_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/end_of_line.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_array_element_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_method_argument_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_method_parameter_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_array.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_assignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_hash.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/indent_heredoc.rb +3 -3
- data/lib/rubocop/cop/{style → layout}/indentation_consistency.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indentation_width.rb +10 -12
- data/lib/rubocop/cop/{style → layout}/initial_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_array_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_block_layout.rb +21 -36
- data/lib/rubocop/cop/{style → layout}/multiline_hash_brace_layout.rb +5 -1
- data/lib/rubocop/cop/{style → layout}/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_method_call_indentation.rb +3 -3
- data/lib/rubocop/cop/{style → layout}/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_operation_indentation.rb +6 -5
- data/lib/rubocop/cop/{style → layout}/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_colon.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_after_comma.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_not.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_semicolon.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_around_block_parameters.rb +7 -5
- data/lib/rubocop/cop/{style → layout}/space_around_equals_in_parameter_default.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_around_operators.rb +6 -2
- data/lib/rubocop/cop/{style → layout}/space_before_block_braces.rb +6 -2
- data/lib/rubocop/cop/{style → layout}/space_before_comma.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_before_comment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_before_first_arg.rb +4 -2
- data/lib/rubocop/cop/{style → layout}/space_before_semicolon.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_in_lambda_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_array_percent_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_block_braces.rb +3 -4
- data/lib/rubocop/cop/{style → layout}/space_inside_brackets.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_percent_literal_delimiters.rb +8 -7
- data/lib/rubocop/cop/{style → layout}/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_string_interpolation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/tab.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/trailing_whitespace.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -4
- data/lib/rubocop/cop/lint/debugger.rb +0 -15
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +81 -0
- data/lib/rubocop/cop/lint/script_permission.rb +42 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
- data/lib/rubocop/cop/message_annotator.rb +23 -13
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/mixin/array_min_size.rb +59 -0
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +10 -11
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +36 -0
- data/lib/rubocop/cop/mixin/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -3
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/performance/caller.rb +41 -0
- data/lib/rubocop/cop/performance/compare_with_block.rb +60 -14
- data/lib/rubocop/cop/performance/double_start_end_with.rb +2 -2
- data/lib/rubocop/cop/performance/redundant_merge.rb +2 -0
- data/lib/rubocop/cop/rails/action_filter.rb +1 -3
- data/lib/rubocop/cop/rails/application_job.rb +32 -0
- data/lib/rubocop/cop/rails/application_record.rb +32 -0
- data/lib/rubocop/cop/rails/blank.rb +9 -3
- data/lib/rubocop/cop/rails/output_safety.rb +59 -15
- data/lib/rubocop/cop/rails/present.rb +9 -3
- data/lib/rubocop/cop/rails/relative_date_constant.rb +35 -4
- data/lib/rubocop/cop/rails/reversible_migration.rb +82 -18
- data/lib/rubocop/cop/rails/save_bang.rb +7 -2
- data/lib/rubocop/cop/rails/skips_model_validations.rb +7 -0
- data/lib/rubocop/cop/registry.rb +4 -3
- data/lib/rubocop/cop/security/eval.rb +9 -3
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +11 -17
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +1 -3
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/copyright.rb +2 -2
- data/lib/rubocop/cop/style/documentation_method.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +2 -1
- data/lib/rubocop/cop/style/each_with_object.rb +10 -6
- data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +4 -5
- data/lib/rubocop/cop/style/format_string.rb +49 -0
- data/lib/rubocop/cop/style/format_string_token.rb +141 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -2
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +10 -1
- data/lib/rubocop/cop/style/lambda.rb +9 -9
- data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/method_name.rb +8 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +41 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +7 -11
- data/lib/rubocop/cop/style/multiple_comparison.rb +77 -0
- data/lib/rubocop/cop/style/next.rb +11 -22
- data/lib/rubocop/cop/style/parallel_assignment.rb +10 -19
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/self_assignment.rb +4 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +23 -17
- data/lib/rubocop/cop/style/symbol_array.rb +24 -13
- data/lib/rubocop/cop/style/symbol_proc.rb +4 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -0
- data/lib/rubocop/cop/style/word_array.rb +33 -53
- data/lib/rubocop/cop/style/yoda_condition.rb +78 -0
- data/lib/rubocop/cop/team.rb +1 -14
- data/lib/rubocop/cop/util.rb +16 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -11
- data/lib/rubocop/node_pattern.rb +52 -52
- data/lib/rubocop/options.rb +25 -0
- data/lib/rubocop/path_util.rb +17 -1
- data/lib/rubocop/result_cache.rb +8 -7
- data/lib/rubocop/rspec/expect_offense.rb +167 -0
- data/lib/rubocop/rspec/shared_examples.rb +0 -8
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +12 -2
- data/lib/rubocop/target_finder.rb +5 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +101 -72
@@ -107,11 +107,16 @@ module RuboCop
|
|
107
107
|
|
108
108
|
def persisted_referenced?(assignment)
|
109
109
|
return unless assignment.referenced?
|
110
|
+
|
110
111
|
assignment.variable.references.any? do |reference|
|
111
|
-
reference.node.parent
|
112
|
+
call_to_persisted?(reference.node.parent)
|
112
113
|
end
|
113
114
|
end
|
114
115
|
|
116
|
+
def call_to_persisted?(node)
|
117
|
+
node.send_type? && node.method?(:persisted?)
|
118
|
+
end
|
119
|
+
|
115
120
|
def check_used_in_conditional(node)
|
116
121
|
return false unless conditional?(node)
|
117
122
|
|
@@ -130,7 +135,7 @@ module RuboCop
|
|
130
135
|
end
|
131
136
|
|
132
137
|
def last_call_of_method?(node)
|
133
|
-
node.parent && node.parent.children.
|
138
|
+
node.parent && node.parent.children.size == node.sibling_index + 1
|
134
139
|
end
|
135
140
|
|
136
141
|
# Ignore simple assignment or if condition
|
@@ -22,6 +22,7 @@ module RuboCop
|
|
22
22
|
#
|
23
23
|
# # good
|
24
24
|
# user.update_attributes(website: 'example.com')
|
25
|
+
# FileUtils.touch('file')
|
25
26
|
class SkipsModelValidations < Cop
|
26
27
|
MSG = 'Avoid using `%s` because it skips validations.'.freeze
|
27
28
|
|
@@ -36,6 +37,10 @@ module RuboCop
|
|
36
37
|
update_columns
|
37
38
|
update_counters].freeze
|
38
39
|
|
40
|
+
def_node_matcher :good_touch?, <<-PATTERN
|
41
|
+
(send (const nil :FileUtils) :touch ...)
|
42
|
+
PATTERN
|
43
|
+
|
39
44
|
def on_send(node)
|
40
45
|
return unless blacklist.include?(node.method_name.to_s)
|
41
46
|
|
@@ -45,6 +50,8 @@ module RuboCop
|
|
45
50
|
return
|
46
51
|
end
|
47
52
|
|
53
|
+
return if good_touch?(node)
|
54
|
+
|
48
55
|
add_offense(node, :selector)
|
49
56
|
end
|
50
57
|
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -62,17 +62,18 @@ module RuboCop
|
|
62
62
|
# @example gives back a correctly qualified cop name
|
63
63
|
#
|
64
64
|
# cops = RuboCop::Cop::Cop.all
|
65
|
-
# cops.
|
65
|
+
# cops.
|
66
|
+
# qualified_cop_name('Layout/IndentArray') # => 'Layout/IndentArray'
|
66
67
|
#
|
67
68
|
# @example fixes incorrect namespaces
|
68
69
|
#
|
69
70
|
# cops = RuboCop::Cop::Cop.all
|
70
|
-
# cops.qualified_cop_name('Lint/IndentArray') # => '
|
71
|
+
# cops.qualified_cop_name('Lint/IndentArray') # => 'Layout/IndentArray'
|
71
72
|
#
|
72
73
|
# @example namespaces bare cop identifiers
|
73
74
|
#
|
74
75
|
# cops = RuboCop::Cop::Cop.all
|
75
|
-
# cops.qualified_cop_name('IndentArray') # => '
|
76
|
+
# cops.qualified_cop_name('IndentArray') # => 'Layout/IndentArray'
|
76
77
|
#
|
77
78
|
# @example passes back unrecognized cop names
|
78
79
|
#
|
@@ -3,20 +3,26 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Security
|
6
|
-
# This cop checks for the use of
|
6
|
+
# This cop checks for the use of `Kernel#eval` and `Binding#eval`.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
#
|
10
10
|
# # bad
|
11
11
|
#
|
12
12
|
# eval(something)
|
13
|
+
# binding.eval(something)
|
13
14
|
class Eval < Cop
|
14
15
|
MSG = 'The use of `eval` is a serious security risk.'.freeze
|
15
16
|
|
16
|
-
def_node_matcher :eval?,
|
17
|
+
def_node_matcher :eval?, <<-END
|
18
|
+
(send {nil (send nil :binding)} :eval $!str ...)
|
19
|
+
END
|
17
20
|
|
18
21
|
def on_send(node)
|
19
|
-
eval?(node)
|
22
|
+
eval?(node) do |code|
|
23
|
+
return if code.dstr_type? && code.recursive_literal?
|
24
|
+
add_offense(node, :selector)
|
25
|
+
end
|
20
26
|
end
|
21
27
|
end
|
22
28
|
end
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
def autocorrect(node)
|
72
72
|
return if correction_would_break_code?(node)
|
73
73
|
|
74
|
-
if node.
|
74
|
+
if node.braces?
|
75
75
|
replace_braces_with_do_end(node.loc)
|
76
76
|
else
|
77
77
|
replace_do_end_with_braces(node.loc)
|
@@ -97,17 +97,18 @@ module RuboCop
|
|
97
97
|
|
98
98
|
lambda do |corrector|
|
99
99
|
corrector.insert_after(b, ' ') unless whitespace_after?(b, 2)
|
100
|
+
|
100
101
|
corrector.replace(b, '{')
|
101
102
|
corrector.replace(e, '}')
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
105
|
-
def whitespace_before?(
|
106
|
-
|
106
|
+
def whitespace_before?(range)
|
107
|
+
range.source_buffer.source[range.begin_pos - 1, 1] =~ /\s/
|
107
108
|
end
|
108
109
|
|
109
|
-
def whitespace_after?(
|
110
|
-
|
110
|
+
def whitespace_after?(range, length = 1)
|
111
|
+
range.source_buffer.source[range.begin_pos + length, 1] =~ /\s/
|
111
112
|
end
|
112
113
|
|
113
114
|
def get_blocks(node, &block)
|
@@ -120,7 +121,7 @@ module RuboCop
|
|
120
121
|
# A hash which is passed as method argument may have no braces
|
121
122
|
# In that case, one of the K/V pairs could contain a block node
|
122
123
|
# which could change in meaning if do...end replaced {...}
|
123
|
-
return if node.
|
124
|
+
return if node.braces?
|
124
125
|
node.each_child_node { |child| get_blocks(child, &block) }
|
125
126
|
when :pair
|
126
127
|
node.each_child_node { |child| get_blocks(child, &block) }
|
@@ -139,16 +140,13 @@ module RuboCop
|
|
139
140
|
end
|
140
141
|
|
141
142
|
def line_count_based_block_style?(node)
|
142
|
-
|
143
|
-
|
144
|
-
(block_length(node) > 0) ^ (block_begin == '{')
|
143
|
+
node.multiline? ^ node.braces?
|
145
144
|
end
|
146
145
|
|
147
146
|
def semantic_block_style?(node)
|
148
147
|
method_name = node.method_name
|
149
|
-
block_begin = node.loc.begin.source
|
150
148
|
|
151
|
-
if
|
149
|
+
if node.braces?
|
152
150
|
functional_method?(method_name) || functional_block?(node)
|
153
151
|
else
|
154
152
|
procedural_method?(method_name) || !return_value_used?(node)
|
@@ -171,13 +169,9 @@ module RuboCop
|
|
171
169
|
end
|
172
170
|
|
173
171
|
def correction_would_break_code?(node)
|
174
|
-
return unless node.
|
175
|
-
|
176
|
-
# Converting `obj.method arg do |x| end` to use `{}` would cause
|
177
|
-
# a syntax error.
|
178
|
-
send = node.children.first
|
172
|
+
return unless node.keywords?
|
179
173
|
|
180
|
-
|
174
|
+
node.send_node.arguments? && !node.send_node.parenthesized?
|
181
175
|
end
|
182
176
|
|
183
177
|
def ignored_method?(method_name)
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
MSG = '%s curly braces around a hash parameter.'.freeze
|
46
46
|
|
47
47
|
def on_send(node)
|
48
|
-
return if node.
|
48
|
+
return if node.assignment_method? || node.operator_method?
|
49
49
|
|
50
50
|
return unless node.arguments? && node.last_argument.hash_type? &&
|
51
51
|
!node.last_argument.empty?
|
@@ -209,7 +209,7 @@ module RuboCop
|
|
209
209
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES +
|
210
210
|
%i[and_asgn or_asgn op_asgn masgn].freeze
|
211
211
|
LINE_LENGTH = 'Metrics/LineLength'.freeze
|
212
|
-
INDENTATION_WIDTH = '
|
212
|
+
INDENTATION_WIDTH = 'Layout/IndentationWidth'.freeze
|
213
213
|
ENABLED = 'Enabled'.freeze
|
214
214
|
MAX = 'Max'.freeze
|
215
215
|
SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'.freeze
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
8
8
|
# The default regexp for an acceptable copyright notice can be found in
|
9
9
|
# config/default.yml. The default can be changed as follows:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# Style/Copyright:
|
12
|
+
# Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
|
13
13
|
#
|
14
14
|
# This regex string is treated as an unanchored regex. For each file
|
15
15
|
# that RuboCop scans, a comment that matches this regex must be found or
|
@@ -38,20 +38,24 @@ module RuboCop
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
private
|
42
|
+
|
43
|
+
# rubocop:disable Metrics/AbcSize
|
41
44
|
def autocorrect(node)
|
42
45
|
lambda do |corrector|
|
43
|
-
|
44
|
-
|
45
|
-
first_arg, second_arg = *
|
46
|
+
corrector.replace(node.send_node.loc.selector, 'each_with_object')
|
47
|
+
|
48
|
+
first_arg, second_arg = *node.arguments
|
49
|
+
|
46
50
|
corrector.replace(first_arg.loc.expression, second_arg.source)
|
47
51
|
corrector.replace(second_arg.loc.expression, first_arg.source)
|
48
52
|
|
49
|
-
return_value = return_value(body)
|
53
|
+
return_value = return_value(node.body)
|
54
|
+
|
50
55
|
corrector.remove(return_value.loc.expression)
|
51
56
|
end
|
52
57
|
end
|
53
|
-
|
54
|
-
private
|
58
|
+
# rubocop:endable Metrics/AbcSize
|
55
59
|
|
56
60
|
def simple_method_arg?(method_arg)
|
57
61
|
method_arg && method_arg.basic_literal?
|
@@ -57,11 +57,11 @@ module RuboCop
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def correct_case_when(corrector, case_node, when_nodes)
|
60
|
-
case_range = case_node.loc.keyword.join(when_nodes.
|
60
|
+
case_range = case_node.loc.keyword.join(when_nodes.first.loc.keyword)
|
61
61
|
|
62
62
|
corrector.replace(case_range, 'if')
|
63
63
|
|
64
|
-
when_nodes.each do |when_node|
|
64
|
+
when_nodes[1..-1].each do |when_node|
|
65
65
|
corrector.replace(when_node.loc.keyword, 'elsif')
|
66
66
|
end
|
67
67
|
end
|
@@ -22,14 +22,13 @@ module RuboCop
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def on_block(node)
|
25
|
-
return if
|
25
|
+
return if node.single_line?
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
!method.arguments?
|
27
|
+
return unless node.send_node.method?(:each) &&
|
28
|
+
!node.send_node.arguments?
|
30
29
|
|
31
30
|
if style == :for
|
32
|
-
incorrect_style_detected(
|
31
|
+
incorrect_style_detected(node.send_node)
|
33
32
|
else
|
34
33
|
correct_style_detected
|
35
34
|
end
|
@@ -40,6 +40,55 @@ module RuboCop
|
|
40
40
|
def method_name(style_name)
|
41
41
|
style_name == :percent ? 'String#%' : style_name
|
42
42
|
end
|
43
|
+
|
44
|
+
def autocorrect(node)
|
45
|
+
lambda do |corrector|
|
46
|
+
_receiver, detected_method = *node
|
47
|
+
|
48
|
+
case detected_method
|
49
|
+
when :%
|
50
|
+
autocorrect_from_percent(corrector, node)
|
51
|
+
when :format, :sprintf
|
52
|
+
case style
|
53
|
+
when :percent
|
54
|
+
autocorrect_to_percent(corrector, node)
|
55
|
+
when :format, :sprintf
|
56
|
+
corrector.replace(node.loc.selector, style.to_s)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def autocorrect_from_percent(corrector, node)
|
65
|
+
receiver, _method, args = *node
|
66
|
+
format = receiver.source
|
67
|
+
args = if args.array_type? || args.hash_type?
|
68
|
+
args.children.map(&:source).join(', ')
|
69
|
+
else
|
70
|
+
args.source
|
71
|
+
end
|
72
|
+
corrected = "#{style}(#{format}, #{args})"
|
73
|
+
corrector.replace(node.loc.expression, corrected)
|
74
|
+
end
|
75
|
+
|
76
|
+
def autocorrect_to_percent(corrector, node)
|
77
|
+
_nil, _method, format, *args = *node
|
78
|
+
format = format.source
|
79
|
+
args = if args.one?
|
80
|
+
arg = args.first
|
81
|
+
if arg.hash_type?
|
82
|
+
"{ #{arg.source} }"
|
83
|
+
else
|
84
|
+
arg.source
|
85
|
+
end
|
86
|
+
else
|
87
|
+
"[#{args.map(&:source).join(', ')}]"
|
88
|
+
end
|
89
|
+
corrected = "#{format} % #{args}"
|
90
|
+
corrector.replace(node.loc.expression, corrected)
|
91
|
+
end
|
43
92
|
end
|
44
93
|
end
|
45
94
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Use a consistent style for named format string tokens.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# EnforcedStyle: annotated
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
#
|
14
|
+
# format('%{greeting}', greeting: 'Hello')
|
15
|
+
# format('%s', 'Hello')
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
#
|
19
|
+
# format('%<greeting>s', greeting: 'Hello')
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
#
|
23
|
+
# EnforcedStyle: template
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
#
|
27
|
+
# format('%<greeting>s', greeting: 'Hello')
|
28
|
+
# format('%s', 'Hello')
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
#
|
32
|
+
# format('%{greeting}', greeting: 'Hello')
|
33
|
+
class FormatStringToken < Cop
|
34
|
+
include ConfigurableEnforcedStyle
|
35
|
+
|
36
|
+
FIELD_CHARACTERS = Regexp.union(%w[A B E G X a b c d e f g i o p s u x])
|
37
|
+
|
38
|
+
STYLE_PATTERNS = {
|
39
|
+
annotated: /(?<token>%<[^>]+>#{FIELD_CHARACTERS})/,
|
40
|
+
template: /(?<token>%\{[^\}]+\})/
|
41
|
+
}.freeze
|
42
|
+
|
43
|
+
TOKEN_PATTERN = Regexp.union(STYLE_PATTERNS.values)
|
44
|
+
|
45
|
+
def on_str(node)
|
46
|
+
return if node.each_ancestor(:xstr).any?
|
47
|
+
|
48
|
+
tokens(node) do |detected_style, token_range|
|
49
|
+
if detected_style == style
|
50
|
+
correct_style_detected
|
51
|
+
else
|
52
|
+
style_detected(detected_style)
|
53
|
+
add_offense(node, token_range, message(detected_style))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def message(detected_style)
|
61
|
+
"Prefer #{message_text(style)} over #{message_text(detected_style)}."
|
62
|
+
end
|
63
|
+
|
64
|
+
# rubocop:disable FormatStringToken
|
65
|
+
def message_text(style)
|
66
|
+
case style
|
67
|
+
when :annotated then 'annotated tokens (like `%<foo>s`)'
|
68
|
+
when :template then 'template tokens (like `%{foo}`)'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
# rubocop:enable FormatStringToken
|
72
|
+
|
73
|
+
def tokens(str_node, &block)
|
74
|
+
return if str_node.source == '__FILE__'
|
75
|
+
|
76
|
+
token_ranges(str_contents(str_node.loc), &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def str_contents(source_map)
|
80
|
+
if source_map.is_a?(Parser::Source::Map::Heredoc)
|
81
|
+
source_map.heredoc_body
|
82
|
+
elsif source_map.begin
|
83
|
+
slice_source(
|
84
|
+
source_map.expression,
|
85
|
+
source_map.expression.begin_pos + 1,
|
86
|
+
source_map.expression.end_pos - 1
|
87
|
+
)
|
88
|
+
else
|
89
|
+
source_map.expression
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def token_ranges(contents)
|
94
|
+
while (offending_match = match_token(contents))
|
95
|
+
detected_style, *range = *offending_match
|
96
|
+
token, contents = split_token(contents, *range)
|
97
|
+
yield(detected_style, token)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def match_token(source_range)
|
102
|
+
supported_styles.each do |style_name|
|
103
|
+
pattern = STYLE_PATTERNS.fetch(style_name)
|
104
|
+
match = source_range.source.match(pattern)
|
105
|
+
next unless match
|
106
|
+
|
107
|
+
return [style_name, match.begin(:token), match.end(:token)]
|
108
|
+
end
|
109
|
+
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def split_token(source_range, match_begin, match_end)
|
114
|
+
token =
|
115
|
+
slice_source(
|
116
|
+
source_range,
|
117
|
+
source_range.begin_pos + match_begin,
|
118
|
+
source_range.begin_pos + match_end
|
119
|
+
)
|
120
|
+
|
121
|
+
remainder =
|
122
|
+
slice_source(
|
123
|
+
source_range,
|
124
|
+
source_range.begin_pos + match_end,
|
125
|
+
source_range.end_pos
|
126
|
+
)
|
127
|
+
|
128
|
+
[token, remainder]
|
129
|
+
end
|
130
|
+
|
131
|
+
def slice_source(source_range, new_begin, new_end)
|
132
|
+
Parser::Source::Range.new(
|
133
|
+
source_range.source_buffer,
|
134
|
+
new_begin,
|
135
|
+
new_end
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|