rubocop 0.48.1 → 0.49.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|