rubocop 0.40.0 → 0.41.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/README.md +7 -1014
- data/config/default.yml +61 -5
- data/config/disabled.yml +6 -0
- data/config/enabled.yml +63 -4
- data/lib/rubocop.rb +17 -1
- data/lib/rubocop/ast_node.rb +56 -42
- data/lib/rubocop/ast_node/traversal.rb +3 -3
- data/lib/rubocop/cli.rb +14 -9
- data/lib/rubocop/comment_config.rb +85 -32
- data/lib/rubocop/config.rb +29 -8
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/corrector.rb +13 -0
- data/lib/rubocop/cop/lint/block_alignment.rb +25 -11
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -2
- data/lib/rubocop/cop/lint/inherit_exception.rb +69 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +60 -0
- data/lib/rubocop/cop/lint/percent_symbol_array.rb +57 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +95 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -13
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +25 -19
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +16 -8
- data/lib/rubocop/cop/mixin/if_node.rb +1 -2
- data/lib/rubocop/cop/mixin/integer_node.rb +13 -0
- data/lib/rubocop/cop/mixin/match_range.rb +26 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +16 -7
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +18 -1
- data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -4
- data/lib/rubocop/cop/mixin/percent_literal.rb +10 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +24 -6
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +20 -7
- data/lib/rubocop/cop/mixin/string_literals_help.rb +2 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +34 -20
- data/lib/rubocop/cop/performance/flat_map.rb +23 -10
- data/lib/rubocop/cop/performance/push_splat.rb +47 -0
- data/lib/rubocop/cop/performance/redundant_block_call.rb +24 -1
- data/lib/rubocop/cop/performance/redundant_merge.rb +3 -5
- data/lib/rubocop/cop/performance/sample.rb +15 -11
- data/lib/rubocop/cop/rails/exit.rb +62 -0
- data/lib/rubocop/cop/rails/output_safety.rb +45 -0
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +12 -4
- data/lib/rubocop/cop/rails/request_referer.rb +40 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +63 -28
- data/lib/rubocop/cop/rails/validation.rb +37 -23
- data/lib/rubocop/cop/style/alias.rb +10 -6
- data/lib/rubocop/cop/style/bare_percent_literals.rb +18 -7
- data/lib/rubocop/cop/style/block_delimiters.rb +15 -22
- data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +19 -8
- data/lib/rubocop/cop/style/comment_indentation.rb +13 -5
- data/lib/rubocop/cop/style/conditional_assignment.rb +111 -59
- data/lib/rubocop/cop/style/documentation.rb +7 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +43 -0
- data/lib/rubocop/cop/style/each_with_object.rb +25 -14
- data/lib/rubocop/cop/style/empty_else.rb +6 -10
- data/lib/rubocop/cop/style/extra_spacing.rb +20 -3
- data/lib/rubocop/cop/style/file_name.rb +16 -4
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +9 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +20 -13
- data/lib/rubocop/cop/style/implicit_runtime_error.rb +32 -0
- data/lib/rubocop/cop/style/infinite_loop.rb +42 -5
- data/lib/rubocop/cop/style/lambda.rb +22 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +12 -4
- data/lib/rubocop/cop/style/module_function.rb +28 -6
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +49 -12
- data/lib/rubocop/cop/style/mutable_constant.rb +8 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/next.rb +43 -31
- data/lib/rubocop/cop/style/not.rb +33 -13
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +92 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +26 -8
- data/lib/rubocop/cop/style/{deprecated_hash_methods.rb → preferred_hash_methods.rb} +8 -8
- data/lib/rubocop/cop/style/redundant_parentheses.rb +29 -19
- data/lib/rubocop/cop/style/redundant_self.rb +13 -6
- data/lib/rubocop/cop/style/space_after_not.rb +7 -5
- data/lib/rubocop/cop/style/space_around_keyword.rb +6 -0
- data/lib/rubocop/cop/style/space_around_operators.rb +5 -1
- data/lib/rubocop/cop/style/space_before_first_arg.rb +21 -9
- data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +53 -0
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +2 -2
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +26 -6
- data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +64 -0
- data/lib/rubocop/cop/style/string_literals.rb +37 -8
- data/lib/rubocop/cop/style/symbol_array.rb +21 -12
- data/lib/rubocop/cop/style/symbol_proc.rb +26 -19
- data/lib/rubocop/cop/style/word_array.rb +1 -5
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -6
- data/lib/rubocop/cop/team.rb +40 -27
- data/lib/rubocop/cop/util.rb +13 -42
- data/lib/rubocop/formatter/disabled_config_formatter.rb +37 -14
- data/lib/rubocop/formatter/html_formatter.rb +3 -7
- data/lib/rubocop/result_cache.rb +18 -4
- data/{spec/support → lib/rubocop/rspec}/cop_helper.rb +3 -0
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +33 -0
- data/lib/rubocop/rspec/shared_contexts.rb +75 -0
- data/lib/rubocop/rspec/shared_examples.rb +101 -0
- data/lib/rubocop/rspec/support.rb +9 -0
- data/lib/rubocop/runner.rb +2 -2
- data/lib/rubocop/string_interpreter.rb +58 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +27 -7
@@ -20,13 +20,13 @@ module RuboCop
|
|
20
20
|
:arg, :restarg, :blockarg, :shadowarg,
|
21
21
|
:kwrestarg, :zsuper, :lambda, :redo, :retry].freeze
|
22
22
|
ONE_CHILD_NODE = [:splat, :kwsplat, :block_pass, :not, :break, :next,
|
23
|
-
:
|
24
|
-
:
|
23
|
+
:preexe, :postexe, :match_current_line, :defined?,
|
24
|
+
:arg_expr].freeze
|
25
25
|
MANY_CHILD_NODES = [:dstr, :dsym, :xstr, :regexp, :array, :hash, :pair,
|
26
26
|
:irange, :erange, :mlhs, :masgn, :or_asgn, :and_asgn,
|
27
27
|
:undef, :alias, :args, :super, :yield, :or, :and,
|
28
28
|
:while_post, :until_post, :iflipflop, :eflipflop,
|
29
|
-
:match_with_lvasgn, :begin, :kwbegin].freeze
|
29
|
+
:match_with_lvasgn, :begin, :kwbegin, :return].freeze
|
30
30
|
SECOND_CHILD_ONLY = [:lvasgn, :ivasgn, :cvasgn, :gvasgn, :optarg, :kwarg,
|
31
31
|
:kwoptarg].freeze
|
32
32
|
|
data/lib/rubocop/cli.rb
CHANGED
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
class CLI
|
8
8
|
include Formatter::TextUtil
|
9
9
|
|
10
|
-
class Finished <
|
10
|
+
class Finished < RuntimeError; end
|
11
11
|
|
12
12
|
attr_reader :options, :config_store
|
13
13
|
|
@@ -25,14 +25,7 @@ module RuboCop
|
|
25
25
|
act_on_options
|
26
26
|
apply_default_formatter
|
27
27
|
|
28
|
-
|
29
|
-
trap_interrupt(runner)
|
30
|
-
all_passed = runner.run(paths)
|
31
|
-
display_warning_summary(runner.warnings)
|
32
|
-
display_error_summary(runner.errors)
|
33
|
-
maybe_print_corrected_source
|
34
|
-
|
35
|
-
all_passed && !runner.aborting? && runner.errors.empty? ? 0 : 1
|
28
|
+
execute_runner(paths)
|
36
29
|
rescue RuboCop::Error => e
|
37
30
|
$stderr.puts Rainbow("Error: #{e.message}").red
|
38
31
|
return 2
|
@@ -72,6 +65,18 @@ module RuboCop
|
|
72
65
|
end
|
73
66
|
end
|
74
67
|
|
68
|
+
def execute_runner(paths)
|
69
|
+
runner = Runner.new(@options, @config_store)
|
70
|
+
|
71
|
+
trap_interrupt(runner)
|
72
|
+
all_passed = runner.run(paths)
|
73
|
+
display_warning_summary(runner.warnings)
|
74
|
+
display_error_summary(runner.errors)
|
75
|
+
maybe_print_corrected_source
|
76
|
+
|
77
|
+
all_passed && !runner.aborting? && runner.errors.empty? ? 0 : 1
|
78
|
+
end
|
79
|
+
|
75
80
|
def handle_exiting_options
|
76
81
|
return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
|
77
82
|
|
@@ -6,10 +6,17 @@ module RuboCop
|
|
6
6
|
# and provides a way to check if each cop is enabled at arbitrary line.
|
7
7
|
class CommentConfig
|
8
8
|
UNNEEDED_DISABLE = 'Lint/UnneededDisable'.freeze
|
9
|
+
|
10
|
+
COP_NAME_PATTERN = '([A-Z][a-z]+/)?(?:[A-Z][a-z]+)+'.freeze
|
11
|
+
COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}".freeze
|
12
|
+
COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})".freeze
|
13
|
+
|
9
14
|
COMMENT_DIRECTIVE_REGEXP = Regexp.new(
|
10
|
-
'\A# rubocop : ((?:dis|en)able)\b
|
15
|
+
('\A# rubocop : ((?:dis|en)able)\b ' + COPS_PATTERN).gsub(' ', '\s*')
|
11
16
|
)
|
12
17
|
|
18
|
+
CopAnalysis = Struct.new(:line_ranges, :start_line_number)
|
19
|
+
|
13
20
|
attr_reader :processed_source
|
14
21
|
|
15
22
|
def initialize(processed_source)
|
@@ -19,6 +26,8 @@ module RuboCop
|
|
19
26
|
def cop_enabled_at_line?(cop, line_number)
|
20
27
|
cop = cop.cop_name if cop.respond_to?(:cop_name)
|
21
28
|
disabled_line_ranges = cop_disabled_line_ranges[cop]
|
29
|
+
return true unless disabled_line_ranges
|
30
|
+
|
22
31
|
disabled_line_ranges.none? { |range| range.include?(line_number) }
|
23
32
|
end
|
24
33
|
|
@@ -29,57 +38,101 @@ module RuboCop
|
|
29
38
|
private
|
30
39
|
|
31
40
|
def analyze
|
32
|
-
|
33
|
-
disablement_start_line_numbers = {}
|
41
|
+
analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
|
34
42
|
|
35
43
|
each_mentioned_cop do |cop_name, disabled, line, single_line|
|
36
|
-
|
37
|
-
|
38
|
-
elsif disabled
|
39
|
-
if disablement_start_line_numbers[cop_name]
|
40
|
-
# Cop already disabled on this line, so we end the current disabled
|
41
|
-
# range before we start a new range.
|
42
|
-
start_line = disablement_start_line_numbers.delete(cop_name)
|
43
|
-
disabled_line_ranges[cop_name] << (start_line..line)
|
44
|
-
end
|
45
|
-
disablement_start_line_numbers[cop_name] = line
|
46
|
-
else
|
47
|
-
start_line = disablement_start_line_numbers.delete(cop_name)
|
48
|
-
disabled_line_ranges[cop_name] << (start_line..line) if start_line
|
49
|
-
end
|
44
|
+
analyses[cop_name] =
|
45
|
+
analyze_cop(analyses[cop_name], disabled, line, single_line)
|
50
46
|
end
|
51
47
|
|
52
|
-
|
53
|
-
|
48
|
+
analyses.each_with_object({}) do |element, hash|
|
49
|
+
cop_name, analysis = *element
|
50
|
+
hash[cop_name] = cop_line_ranges(analysis)
|
54
51
|
end
|
52
|
+
end
|
55
53
|
|
56
|
-
|
54
|
+
def analyze_cop(analysis, disabled, line, single_line)
|
55
|
+
if single_line
|
56
|
+
analyze_single_line(analysis, line, disabled)
|
57
|
+
elsif disabled
|
58
|
+
analyze_disabled(analysis, line)
|
59
|
+
else
|
60
|
+
analyze_rest(analysis, line)
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
|
-
def
|
60
|
-
return
|
64
|
+
def analyze_single_line(analysis, line, disabled)
|
65
|
+
return analysis unless disabled
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
|
67
|
+
CopAnalysis.new(analysis.line_ranges + [(line..line)],
|
68
|
+
analysis.start_line_number)
|
69
|
+
end
|
70
|
+
|
71
|
+
def analyze_disabled(analysis, line)
|
72
|
+
if (start_line = analysis.start_line_number)
|
73
|
+
# Cop already disabled on this line, so we end the current disabled
|
74
|
+
# range before we start a new range.
|
75
|
+
return CopAnalysis.new(analysis.line_ranges + [start_line..line], line)
|
76
|
+
end
|
77
|
+
|
78
|
+
CopAnalysis.new(analysis.line_ranges, line)
|
79
|
+
end
|
80
|
+
|
81
|
+
def analyze_rest(analysis, line)
|
82
|
+
if (start_line = analysis.start_line_number)
|
83
|
+
return CopAnalysis.new(analysis.line_ranges + [start_line..line], nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
CopAnalysis.new(analysis.line_ranges, nil)
|
87
|
+
end
|
65
88
|
|
66
|
-
|
89
|
+
def cop_line_ranges(analysis)
|
90
|
+
return analysis.line_ranges unless analysis.start_line_number
|
67
91
|
|
68
|
-
|
69
|
-
|
92
|
+
analysis.line_ranges + [(analysis.start_line_number..Float::INFINITY)]
|
93
|
+
end
|
70
94
|
|
71
|
-
|
95
|
+
def each_mentioned_cop
|
96
|
+
each_directive do |comment, cop_names, disabled|
|
72
97
|
comment_line_number = comment.loc.expression.line
|
73
98
|
single_line = !comment_only_line?(comment_line_number)
|
74
99
|
|
75
100
|
cop_names.each do |cop_name|
|
76
|
-
|
77
|
-
|
78
|
-
yield cop_name, disabled, comment_line_number, single_line
|
101
|
+
yield qualified_cop_name(cop_name), disabled, comment_line_number,
|
102
|
+
single_line
|
79
103
|
end
|
80
104
|
end
|
81
105
|
end
|
82
106
|
|
107
|
+
def each_directive
|
108
|
+
return if processed_source.comments.nil?
|
109
|
+
|
110
|
+
processed_source.comments.each do |comment|
|
111
|
+
directive = directive_parts(comment)
|
112
|
+
next unless directive
|
113
|
+
|
114
|
+
yield comment, *directive
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def directive_parts(comment)
|
119
|
+
match = comment.text.match(COMMENT_DIRECTIVE_REGEXP)
|
120
|
+
return unless match
|
121
|
+
|
122
|
+
switch, cops_string = match.captures
|
123
|
+
|
124
|
+
cop_names =
|
125
|
+
cops_string == 'all' ? all_cop_names : cops_string.split(/,\s*/)
|
126
|
+
|
127
|
+
disabled = (switch == 'disable')
|
128
|
+
|
129
|
+
[cop_names, disabled]
|
130
|
+
end
|
131
|
+
|
132
|
+
def qualified_cop_name(cop_name)
|
133
|
+
Cop::Cop.qualified_cop_name(cop_name.strip, processed_source.buffer.name)
|
134
|
+
end
|
135
|
+
|
83
136
|
def all_cop_names
|
84
137
|
@all_cop_names ||= Cop::Cop.all.map(&:cop_name).reject do |cop_name|
|
85
138
|
cop_name == UNNEEDED_DISABLE
|
data/lib/rubocop/config.rb
CHANGED
@@ -194,6 +194,19 @@ module RuboCop
|
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
+
def target_ruby_version
|
198
|
+
@target_ruby_version ||=
|
199
|
+
if File.file?('.ruby-version')
|
200
|
+
@target_ruby_version_source = :dot_ruby_version
|
201
|
+
|
202
|
+
File.read('.ruby-version').to_f
|
203
|
+
else
|
204
|
+
@target_ruby_version_source = :rubocop_yml
|
205
|
+
|
206
|
+
for_all_cops['TargetRubyVersion']
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
197
210
|
private
|
198
211
|
|
199
212
|
def warn_about_unrecognized_cops(invalid_cop_names)
|
@@ -272,14 +285,22 @@ module RuboCop
|
|
272
285
|
end
|
273
286
|
|
274
287
|
def check_target_ruby
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
288
|
+
return unless target_ruby_version
|
289
|
+
|
290
|
+
unless KNOWN_RUBIES.include?(target_ruby_version)
|
291
|
+
msg = "Unknown Ruby version #{target_ruby_version.inspect} found "
|
292
|
+
|
293
|
+
msg +=
|
294
|
+
case @target_ruby_version_source
|
295
|
+
when :dot_ruby_version
|
296
|
+
'in `.ruby-version`.'
|
297
|
+
when :rubocop_yml
|
298
|
+
"in `TargetRubyVersion` parameter (in #{loaded_path})." \
|
299
|
+
end
|
300
|
+
|
301
|
+
msg += "\nKnown versions: #{KNOWN_RUBIES.join(', ')}"
|
302
|
+
|
303
|
+
raise ValidationError, msg
|
283
304
|
end
|
284
305
|
end
|
285
306
|
end
|
@@ -139,7 +139,7 @@ module RuboCop
|
|
139
139
|
end
|
140
140
|
|
141
141
|
def load_yaml_configuration(absolute_path)
|
142
|
-
yaml_code = IO.read(absolute_path)
|
142
|
+
yaml_code = IO.read(absolute_path, encoding: 'UTF-8')
|
143
143
|
# At one time, there was a problem with the psych YAML engine under
|
144
144
|
# Ruby 1.9.3. YAML.load_file would crash when reading empty .yml files
|
145
145
|
# or files that only contained comments and blank lines. This problem
|
data/lib/rubocop/cop/cop.rb
CHANGED
@@ -118,6 +118,19 @@ module RuboCop
|
|
118
118
|
range.begin_pos + size)
|
119
119
|
@source_rewriter.remove(to_remove)
|
120
120
|
end
|
121
|
+
|
122
|
+
# Removes `size` characters from the end of the given range.
|
123
|
+
# If `size` is greater than the size of `range`, the removed region can
|
124
|
+
# overrun the beginning of `range`.
|
125
|
+
#
|
126
|
+
# @param [Parser::Source::Range] range
|
127
|
+
# @param [Integer] size
|
128
|
+
def remove_trailing(range, size)
|
129
|
+
to_remove = Parser::Source::Range.new(range.source_buffer,
|
130
|
+
range.end_pos - size,
|
131
|
+
range.end_pos)
|
132
|
+
@source_rewriter.remove(to_remove)
|
133
|
+
end
|
121
134
|
end
|
122
135
|
end
|
123
136
|
end
|
@@ -63,15 +63,7 @@ module RuboCop
|
|
63
63
|
|
64
64
|
def start_for_block_node(block_node)
|
65
65
|
# Which node should we align the 'end' with?
|
66
|
-
result = block_node
|
67
|
-
|
68
|
-
while (parent = result.parent)
|
69
|
-
break if !parent || !parent.loc
|
70
|
-
break if parent.loc.line != block_node.loc.line &&
|
71
|
-
!parent.masgn_type?
|
72
|
-
break unless block_end_align_target?(parent, result)
|
73
|
-
result = parent
|
74
|
-
end
|
66
|
+
result = block_end_align_target(block_node)
|
75
67
|
|
76
68
|
# In offense message, we want to show the assignment LHS rather than
|
77
69
|
# the entire assignment
|
@@ -79,6 +71,17 @@ module RuboCop
|
|
79
71
|
result
|
80
72
|
end
|
81
73
|
|
74
|
+
def block_end_align_target(node)
|
75
|
+
while (parent = node.parent)
|
76
|
+
break if !parent || !parent.loc
|
77
|
+
break if parent.loc.line != node.loc.line && !parent.masgn_type?
|
78
|
+
break unless block_end_align_target?(parent, node)
|
79
|
+
node = parent
|
80
|
+
end
|
81
|
+
|
82
|
+
node
|
83
|
+
end
|
84
|
+
|
82
85
|
def check_block_alignment(start_node, block_node)
|
83
86
|
end_loc = block_node.loc.end
|
84
87
|
return unless begins_its_line?(end_loc)
|
@@ -91,19 +94,30 @@ module RuboCop
|
|
91
94
|
compute_do_source_line_column(block_node, end_loc)
|
92
95
|
return unless do_source_line_column
|
93
96
|
|
97
|
+
offense(block_node, start_loc, end_loc, do_source_line_column)
|
98
|
+
end
|
99
|
+
|
100
|
+
def offense(block_node, start_loc, end_loc, do_source_line_column)
|
94
101
|
error_source_line_column = if style == :start_of_block
|
95
102
|
do_source_line_column
|
96
103
|
else
|
97
104
|
loc_to_source_line_column(start_loc)
|
98
105
|
end
|
99
106
|
|
100
|
-
|
107
|
+
message = format_message(start_loc, end_loc, do_source_line_column,
|
108
|
+
error_source_line_column)
|
109
|
+
|
110
|
+
add_offense(block_node, end_loc, message)
|
111
|
+
end
|
112
|
+
|
113
|
+
def format_message(start_loc, end_loc, do_source_line_column,
|
114
|
+
error_source_line_column)
|
115
|
+
format(
|
101
116
|
MSG,
|
102
117
|
format_source_line_column(loc_to_source_line_column(end_loc)),
|
103
118
|
format_source_line_column(error_source_line_column),
|
104
119
|
alt_start_msg(start_loc, do_source_line_column)
|
105
120
|
)
|
106
|
-
add_offense(block_node, end_loc, fmt)
|
107
121
|
end
|
108
122
|
|
109
123
|
def compute_do_source_line_column(node, end_loc)
|
@@ -34,13 +34,12 @@ module RuboCop
|
|
34
34
|
|
35
35
|
def offending_node?(node)
|
36
36
|
return false unless called_on_string?(node)
|
37
|
-
return false unless
|
37
|
+
return false unless method_with_format_args?(node)
|
38
38
|
return false if named_mode?(node) || node_with_splat_args?(node)
|
39
39
|
|
40
40
|
num_of_format_args, num_of_expected_fields = count_matches(node)
|
41
41
|
|
42
42
|
num_of_format_args != :unknown &&
|
43
|
-
num_of_expected_fields != :unknown &&
|
44
43
|
num_of_expected_fields != num_of_format_args
|
45
44
|
end
|
46
45
|
|
@@ -53,6 +52,10 @@ module RuboCop
|
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
55
|
+
def method_with_format_args?(node)
|
56
|
+
sprintf?(node) || format?(node) || percent?(node)
|
57
|
+
end
|
58
|
+
|
56
59
|
def named_mode?(node)
|
57
60
|
receiver_node, _method_name, *args = *node
|
58
61
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module Lint
|
7
|
+
# This cop looks for error classes inheriting from `Exception`.
|
8
|
+
# It is configurable to suggest using either `RuntimeError` (default) or
|
9
|
+
# `StandardError` instead.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
#
|
15
|
+
# class C < Exception; end
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# # EnforcedStyle: runtime_error (default)
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
#
|
23
|
+
# class C < RuntimeError; end
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
#
|
27
|
+
# # EnforcedStyle: standard_error
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
#
|
31
|
+
# class C < StandardError; end
|
32
|
+
class InheritException < Cop
|
33
|
+
include ConfigurableEnforcedStyle
|
34
|
+
|
35
|
+
MSG = 'Inherit from `%s` instead of `Exception`.'.freeze
|
36
|
+
PREFERRED_BASE_CLASS = {
|
37
|
+
runtime_error: 'RuntimeError',
|
38
|
+
standard_error: 'StandardError'
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
def on_class(node)
|
42
|
+
_class, base_class, _body = *node
|
43
|
+
|
44
|
+
return if base_class.nil?
|
45
|
+
|
46
|
+
check(base_class)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def check(node)
|
52
|
+
if node.const_name == 'Exception'
|
53
|
+
add_offense(node, :expression, format(MSG, preferred_base_class))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def autocorrect(node)
|
58
|
+
lambda do |corrector|
|
59
|
+
corrector.replace(node.loc.expression, preferred_base_class)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def preferred_base_class
|
64
|
+
PREFERRED_BASE_CLASS[style]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|