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
@@ -64,17 +64,6 @@ module RuboCop
|
|
64
64
|
@total_correction_count += offenses.count(&:corrected?)
|
65
65
|
end
|
66
66
|
|
67
|
-
def smart_path(path)
|
68
|
-
# Ideally, we calculate this relative to the project root.
|
69
|
-
base_dir = Dir.pwd
|
70
|
-
|
71
|
-
if path.start_with? base_dir
|
72
|
-
relative_path(path, base_dir)
|
73
|
-
else
|
74
|
-
path
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
67
|
def colored_severity_code(offense)
|
79
68
|
color = COLOR_FOR_SEVERITY[offense.severity.name]
|
80
69
|
colorize(offense.severity.code, color)
|
data/lib/rubocop/node_pattern.rb
CHANGED
@@ -23,55 +23,55 @@ module RuboCop
|
|
23
23
|
#
|
24
24
|
# ## Pattern string format examples
|
25
25
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
26
|
+
# ':sym' # matches a literal symbol
|
27
|
+
# '1' # matches a literal integer
|
28
|
+
# 'nil' # matches a literal nil
|
29
|
+
# 'send' # matches (send ...)
|
30
|
+
# '(send)' # matches (send)
|
31
|
+
# '(send ...)' # matches (send ...)
|
32
|
+
# '(op-asgn)' # node types with hyphenated names also work
|
33
|
+
# '{send class}' # matches (send ...) or (class ...)
|
34
|
+
# '({send class})' # matches (send) or (class)
|
35
|
+
# '(send const)' # matches (send (const ...))
|
36
|
+
# '(send _ :new)' # matches (send <anything> :new)
|
37
|
+
# '(send $_ :new)' # as above, but whatever matches the $_ is captured
|
38
|
+
# '(send $_ $_)' # you can use as many captures as you want
|
39
|
+
# '(send !const ...)' # ! negates the next part of the pattern
|
40
|
+
# '$(send const ...)' # arbitrary matching can be performed on a capture
|
41
|
+
# '(send _recv _msg)' # wildcards can be named (for readability)
|
42
|
+
# '(send ... :new)' # you can specifically match against the last child
|
43
|
+
# # (this only works for the very last)
|
44
|
+
# '(send $...)' # capture all the children as an array
|
45
|
+
# '(send $... int)' # capture all children but the last as an array
|
46
|
+
# '(send _x :+ _x)' # unification is performed on named wildcards
|
47
|
+
# # (like Prolog variables...)
|
48
|
+
# # (#== is used to see if values unify)
|
49
|
+
# '(int odd?)' # words which end with a ? are predicate methods,
|
50
|
+
# # are are called on the target to see if it matches
|
51
|
+
# # any Ruby method which the matched object supports
|
52
|
+
# # can be used
|
53
|
+
# # if a truthy value is returned, the match succeeds
|
54
|
+
# '(int [!1 !2])' # [] contains multiple patterns, ALL of which must
|
55
|
+
# # match in that position
|
56
|
+
# # in other words, while {} is pattern union (logical
|
57
|
+
# # OR), [] is intersection (logical AND)
|
58
|
+
# '(send %1 _)' # % stands for a parameter which must be supplied to
|
59
|
+
# # #match at matching time
|
60
|
+
# # it will be compared to the corresponding value in
|
61
|
+
# # the AST using #==
|
62
|
+
# # a bare '%' is the same as '%1'
|
63
|
+
# # the number of extra parameters passed to #match
|
64
|
+
# # must equal the highest % value in the pattern
|
65
|
+
# # for consistency, %0 is the 'root node' which is
|
66
|
+
# # passed as the 1st argument to #match, where the
|
67
|
+
# # matching process starts
|
68
|
+
# '^^send' # each ^ ascends one level in the AST
|
69
|
+
# # so this matches against the grandparent node
|
70
|
+
# '#method' # we call this a 'funcall'; it calls a method in the
|
71
|
+
# # context where a pattern-matching method is defined
|
72
|
+
# # if that returns a truthy value, the match succeeds
|
73
|
+
# 'equal?(%1)' # predicates can be given 1 or more extra args
|
74
|
+
# '#method(%0, 1)' # funcalls can also be given 1 or more extra args
|
75
75
|
#
|
76
76
|
# You can nest arbitrarily deep:
|
77
77
|
#
|
@@ -475,8 +475,8 @@ module RuboCop
|
|
475
475
|
"#{compiler.emit_trailing_params});" \
|
476
476
|
"#{compiler.emit_method_code};end"
|
477
477
|
|
478
|
-
|
479
|
-
class_eval(src,
|
478
|
+
location = caller_locations(1, 1).first
|
479
|
+
class_eval(src, location.path, location.lineno)
|
480
480
|
end
|
481
481
|
|
482
482
|
# Define a method which recurses over the descendants of an AST node,
|
@@ -487,7 +487,7 @@ module RuboCop
|
|
487
487
|
# yield all descendants which match.
|
488
488
|
def def_node_search(method_name, pattern_str)
|
489
489
|
compiler = RuboCop::NodePattern::Compiler.new(pattern_str, 'node')
|
490
|
-
called_from = caller.first.split(':')
|
490
|
+
called_from = caller(1..1).first.split(':')
|
491
491
|
|
492
492
|
if method_name.to_s.end_with?('?')
|
493
493
|
node_search_first(method_name, compiler, called_from)
|
data/lib/rubocop/options.rb
CHANGED
@@ -156,6 +156,7 @@ module RuboCop
|
|
156
156
|
|
157
157
|
option(opts, '-v', '--version')
|
158
158
|
option(opts, '-V', '--verbose-version')
|
159
|
+
option(opts, '-P', '--parallel')
|
159
160
|
end
|
160
161
|
|
161
162
|
def add_list_options(opts)
|
@@ -217,11 +218,33 @@ module RuboCop
|
|
217
218
|
raise ArgumentError, '--no-offense-counts can only be used together ' \
|
218
219
|
'with --auto-gen-config.'
|
219
220
|
end
|
221
|
+
validate_parallel
|
222
|
+
|
220
223
|
return if incompatible_options.size <= 1
|
221
224
|
raise ArgumentError, 'Incompatible cli options: ' \
|
222
225
|
"#{incompatible_options.inspect}"
|
223
226
|
end
|
224
227
|
|
228
|
+
def validate_parallel
|
229
|
+
return unless @options.key?(:parallel)
|
230
|
+
|
231
|
+
if @options[:cache] == 'false'
|
232
|
+
raise ArgumentError, '-P/--parallel uses caching to speed up ' \
|
233
|
+
'execution, so combining with --cache false is ' \
|
234
|
+
'not allowed.'
|
235
|
+
end
|
236
|
+
|
237
|
+
combos = {
|
238
|
+
auto_gen_config: '-P/--parallel uses caching to speed up execution, ' \
|
239
|
+
'while --auto-gen-config needs a non-cached run, ' \
|
240
|
+
'so they cannot be combined.',
|
241
|
+
fail_fast: '-P/--parallel can not be combined with -F/--fail-fast.',
|
242
|
+
auto_correct: '-P/--parallel can not be combined with --auto-correct.'
|
243
|
+
}
|
244
|
+
|
245
|
+
combos.each { |key, msg| raise ArgumentError, msg if @options.key?(key) }
|
246
|
+
end
|
247
|
+
|
225
248
|
def only_includes_unneeded_disable?
|
226
249
|
@options.key?(:only) &&
|
227
250
|
(@options[:only] & %w[Lint/UnneededDisable UnneededDisable]).any?
|
@@ -323,6 +346,8 @@ module RuboCop
|
|
323
346
|
no_color: 'Force color output on or off.',
|
324
347
|
version: 'Display version.',
|
325
348
|
verbose_version: 'Display verbose version.',
|
349
|
+
parallel: ['Use available CPUs to execute inspection in',
|
350
|
+
'parallel.'],
|
326
351
|
stdin: ['Pipe source from STDIN, using FILE in offense',
|
327
352
|
'reports. This is useful for editor integration.']
|
328
353
|
}.freeze
|
data/lib/rubocop/path_util.rb
CHANGED
@@ -14,12 +14,28 @@ module RuboCop
|
|
14
14
|
path_name.relative_path_from(Pathname.new(base_dir)).to_s
|
15
15
|
end
|
16
16
|
|
17
|
+
def smart_path(path)
|
18
|
+
# Ideally, we calculate this relative to the project root.
|
19
|
+
base_dir = Dir.pwd
|
20
|
+
|
21
|
+
if path.start_with? base_dir
|
22
|
+
relative_path(path, base_dir)
|
23
|
+
else
|
24
|
+
path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
17
28
|
def match_path?(pattern, path)
|
18
29
|
case pattern
|
19
30
|
when String
|
20
31
|
File.fnmatch?(pattern, path, File::FNM_PATHNAME)
|
21
32
|
when Regexp
|
22
|
-
|
33
|
+
begin
|
34
|
+
path =~ pattern
|
35
|
+
rescue ArgumentError => e
|
36
|
+
return false if e.message.start_with?('invalid byte sequence')
|
37
|
+
raise e
|
38
|
+
end
|
23
39
|
end
|
24
40
|
end
|
25
41
|
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -2,14 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'digest/md5'
|
4
4
|
require 'find'
|
5
|
-
require 'tmpdir'
|
6
5
|
require 'etc'
|
7
6
|
|
8
7
|
module RuboCop
|
9
8
|
# Provides functionality for caching rubocop runs.
|
10
9
|
class ResultCache
|
11
10
|
NON_CHANGING = %i[color format formatters out debug fail_level
|
12
|
-
cache fail_fast stdin].freeze
|
11
|
+
cache fail_fast stdin parallel].freeze
|
13
12
|
|
14
13
|
# Remove old files so that the cache doesn't grow too big. When the
|
15
14
|
# threshold MaxFilesInCache has been exceeded, the oldest 50% of all the
|
@@ -63,11 +62,13 @@ module RuboCop
|
|
63
62
|
|
64
63
|
def self.cache_root(config_store)
|
65
64
|
root = config_store.for('.').for_all_cops['CacheRootDirectory']
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
root ||= if ENV.key?('XDG_CACHE_HOME')
|
66
|
+
# Include user ID in the path to make sure the user has write
|
67
|
+
# access.
|
68
|
+
File.join(ENV['XDG_CACHE_HOME'], Process.uid.to_s)
|
69
|
+
else
|
70
|
+
File.join(ENV['HOME'], '.cache')
|
71
|
+
end
|
71
72
|
File.join(root, 'rubocop_cache')
|
72
73
|
end
|
73
74
|
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Mixin for `expect_offense` and `expect_no_offenses`
|
6
|
+
#
|
7
|
+
# This mixin makes it easier to specify strict offense expectations
|
8
|
+
# and a declarative and visual fashion. Just type out the code that
|
9
|
+
# should generate a offense, annotate code by writing '^'s
|
10
|
+
# underneath each character that should be highlighted, and follow
|
11
|
+
# the carets with a string (separated by a space) that is the
|
12
|
+
# message of the offense. You can include multiple offenses in
|
13
|
+
# one code snippet.
|
14
|
+
#
|
15
|
+
# @example Usage
|
16
|
+
#
|
17
|
+
# expect_offense(<<-RUBY.strip_indent)
|
18
|
+
# a do
|
19
|
+
# b
|
20
|
+
# end.c
|
21
|
+
# ^^^^^ Avoid chaining a method call on a do...end block.
|
22
|
+
# RUBY
|
23
|
+
#
|
24
|
+
# @example Equivalent assertion without `expect_offense`
|
25
|
+
#
|
26
|
+
# inspect_source(cop, <<-RUBY.strip_indent)
|
27
|
+
# a do
|
28
|
+
# b
|
29
|
+
# end.c
|
30
|
+
# RUBY
|
31
|
+
#
|
32
|
+
# expect(cop.offenses.size).to be(1)
|
33
|
+
#
|
34
|
+
# offense = cop.offenses.first
|
35
|
+
# expect(offense.line).to be(3)
|
36
|
+
# expect(offense.column_range).to be(0...5)
|
37
|
+
# expect(offense.message).to eql(
|
38
|
+
# 'Avoid chaining a method call on a do...end block.'
|
39
|
+
# )
|
40
|
+
#
|
41
|
+
# If you do not want to specify an offense then use the
|
42
|
+
# companion method `expect_no_offenses`. This method is a much
|
43
|
+
# simpler assertion since it just inspects the source and checks
|
44
|
+
# that there were no offenses. The `expect_offenses` method has
|
45
|
+
# to do more work by parsing out lines that contain carets.
|
46
|
+
module ExpectOffense
|
47
|
+
DEFAULT_FILENAME = 'example.rb'.freeze
|
48
|
+
|
49
|
+
def expect_offense(source, filename = DEFAULT_FILENAME)
|
50
|
+
expected_annotations = AnnotatedSource.parse(source)
|
51
|
+
|
52
|
+
if expected_annotations.plain_source == source
|
53
|
+
raise 'Use expect_no_offenses to assert that no offenses are found'
|
54
|
+
end
|
55
|
+
|
56
|
+
inspect_source(cop, expected_annotations.plain_source, filename)
|
57
|
+
actual_annotations =
|
58
|
+
expected_annotations.with_offense_annotations(cop.offenses)
|
59
|
+
expect(expected_annotations.to_s).to eq(actual_annotations.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
def expect_no_offenses(source, filename = DEFAULT_FILENAME)
|
63
|
+
inspect_source(cop, source, filename)
|
64
|
+
|
65
|
+
expect(cop.offenses).to be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
# Parsed representation of code annotated with the `^^^ Message` style
|
69
|
+
class AnnotatedSource
|
70
|
+
ANNOTATION_PATTERN = /\A\s*\^+ /
|
71
|
+
|
72
|
+
# @param annotated_source [String] string passed to the matchers
|
73
|
+
#
|
74
|
+
# Separates annotation lines from source lines. Tracks the real
|
75
|
+
# source line number that each annotation corresponds to.
|
76
|
+
#
|
77
|
+
# @return [AnnotatedSource]
|
78
|
+
def self.parse(annotated_source)
|
79
|
+
source = []
|
80
|
+
annotations = []
|
81
|
+
|
82
|
+
annotated_source.each_line do |source_line|
|
83
|
+
if source_line =~ ANNOTATION_PATTERN
|
84
|
+
annotations << [source.size, source_line]
|
85
|
+
else
|
86
|
+
source << source_line
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
new(source, annotations)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @param lines [Array<String>]
|
94
|
+
# @param annotations [Array<(Integer, String)>]
|
95
|
+
# each entry is the annotated line number and the annotation text
|
96
|
+
#
|
97
|
+
# @note annotations are sorted so that reconstructing the annotation
|
98
|
+
# text via {#to_s} is deterministic
|
99
|
+
def initialize(lines, annotations)
|
100
|
+
@lines = lines.freeze
|
101
|
+
@annotations = annotations.sort.freeze
|
102
|
+
end
|
103
|
+
|
104
|
+
# Construct annotated source string (like what we parse)
|
105
|
+
#
|
106
|
+
# Reconstruct a deterministic annotated source string. This is
|
107
|
+
# useful for eliminating semantically irrelevant annotation
|
108
|
+
# ordering differences.
|
109
|
+
#
|
110
|
+
# @example standardization
|
111
|
+
#
|
112
|
+
# source1 = AnnotatedSource.parse(<<-RUBY)
|
113
|
+
# line1
|
114
|
+
# ^ Annotation 1
|
115
|
+
# ^^ Annotation 2
|
116
|
+
# RUBY
|
117
|
+
#
|
118
|
+
# source2 = AnnotatedSource.parse(<<-RUBY)
|
119
|
+
# line1
|
120
|
+
# ^^ Annotation 2
|
121
|
+
# ^ Annotation 1
|
122
|
+
# RUBY
|
123
|
+
#
|
124
|
+
# source1.to_s == source2.to_s # => true
|
125
|
+
#
|
126
|
+
# @return [String]
|
127
|
+
def to_s
|
128
|
+
reconstructed = lines.dup
|
129
|
+
|
130
|
+
annotations.reverse_each do |line_number, annotation|
|
131
|
+
reconstructed.insert(line_number, annotation)
|
132
|
+
end
|
133
|
+
|
134
|
+
reconstructed.join
|
135
|
+
end
|
136
|
+
|
137
|
+
# Return the plain source code without annotations
|
138
|
+
#
|
139
|
+
# @return [String]
|
140
|
+
def plain_source
|
141
|
+
lines.join
|
142
|
+
end
|
143
|
+
|
144
|
+
# Annotate the source code with the RuboCop offenses provided
|
145
|
+
#
|
146
|
+
# @param offenses [Array<RuboCop::Cop::Offense>]
|
147
|
+
#
|
148
|
+
# @return [self]
|
149
|
+
def with_offense_annotations(offenses)
|
150
|
+
offense_annotations =
|
151
|
+
offenses.map do |offense|
|
152
|
+
indent = ' ' * offense.column
|
153
|
+
carets = '^' * offense.column_length
|
154
|
+
|
155
|
+
[offense.line, "#{indent}#{carets} #{offense.message}\n"]
|
156
|
+
end
|
157
|
+
|
158
|
+
self.class.new(lines, offense_annotations)
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
attr_reader :lines, :annotations
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -82,14 +82,6 @@ shared_examples_for 'debugger' do |name, src|
|
|
82
82
|
.to eq(src.map { |s| "Remove debugger entry point `#{s}`." })
|
83
83
|
expect(cop.highlights).to eq(src)
|
84
84
|
end
|
85
|
-
|
86
|
-
it "can autocorrect a #{name} call" do
|
87
|
-
lines = src.is_a?(String) ? src : src.join("\n")
|
88
|
-
new_source = autocorrect_source(cop, ['def a',
|
89
|
-
" #{lines}",
|
90
|
-
'end'].join("\n"))
|
91
|
-
expect(new_source).to eq("def a\nend")
|
92
|
-
end
|
93
85
|
end
|
94
86
|
|
95
87
|
shared_examples_for 'non-debugger' do |name, src|
|
data/lib/rubocop/runner.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'parallel'
|
4
|
+
|
3
5
|
module RuboCop
|
4
6
|
# This class handles the processing of files, which includes dealing with
|
5
7
|
# formatters and letting cops inspect the files.
|
@@ -33,6 +35,7 @@ module RuboCop
|
|
33
35
|
if @options[:list_target_files]
|
34
36
|
list_files(target_files)
|
35
37
|
else
|
38
|
+
warm_cache(target_files) if @options[:parallel]
|
36
39
|
inspect_files(target_files)
|
37
40
|
end
|
38
41
|
end
|
@@ -43,6 +46,13 @@ module RuboCop
|
|
43
46
|
|
44
47
|
private
|
45
48
|
|
49
|
+
# Warms up the RuboCop cache by forking a suitable number of rubocop
|
50
|
+
# instances that each inspects its alotted group of files.
|
51
|
+
def warm_cache(target_files)
|
52
|
+
puts 'Running parallel inspection'
|
53
|
+
Parallel.each(target_files, &method(:file_offenses))
|
54
|
+
end
|
55
|
+
|
46
56
|
def find_target_files(paths)
|
47
57
|
target_finder = TargetFinder.new(@config_store, @options)
|
48
58
|
target_files = target_finder.find(paths)
|
@@ -116,7 +126,7 @@ module RuboCop
|
|
116
126
|
end
|
117
127
|
|
118
128
|
def add_unneeded_disables(file, offenses, source)
|
119
|
-
if
|
129
|
+
if check_for_unneeded_disables?(source)
|
120
130
|
config = @config_store.for(file)
|
121
131
|
if config.for_cop(Cop::Lint::UnneededDisable).fetch('Enabled')
|
122
132
|
cop = Cop::Lint::UnneededDisable.new(config, @options)
|
@@ -132,7 +142,7 @@ module RuboCop
|
|
132
142
|
offenses.sort.reject(&:disabled?).freeze
|
133
143
|
end
|
134
144
|
|
135
|
-
def
|
145
|
+
def check_for_unneeded_disables?(source)
|
136
146
|
!source.disabled_line_ranges.empty? && !filtered_run?
|
137
147
|
end
|
138
148
|
|