rubocop 0.88.0 → 0.89.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 +1 -1
- data/bin/rubocop-profile +1 -0
- data/config/default.yml +96 -16
- data/lib/rubocop.rb +16 -4
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/base.rb +1 -0
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/show_cops.rb +1 -1
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/comment_config.rb +2 -2
- data/lib/rubocop/config.rb +19 -2
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_obsoletion.rb +6 -1
- data/lib/rubocop/config_validator.rb +1 -3
- data/lib/rubocop/cop/base.rb +2 -2
- data/lib/rubocop/cop/commissioner.rb +0 -1
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +3 -3
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/punctuation_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +15 -18
- data/lib/rubocop/cop/force.rb +1 -0
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +32 -11
- data/lib/rubocop/cop/generator/configuration_injector.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +4 -12
- data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +10 -7
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +7 -8
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -2
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines.rb +0 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +9 -16
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/indentation_style.rb +0 -2
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +0 -2
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +9 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +7 -4
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +15 -10
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +11 -13
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
- data/lib/rubocop/cop/lint/big_decimal_new.rb +10 -10
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +49 -0
- data/lib/rubocop/cop/lint/boolean_symbol.rb +16 -11
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +1 -1
- data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +7 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +9 -10
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +17 -13
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_hash_key.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +7 -4
- data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +60 -0
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
- data/lib/rubocop/cop/lint/else_layout.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +67 -0
- data/lib/rubocop/cop/lint/empty_ensure.rb +5 -5
- data/lib/rubocop/cop/lint/empty_expression.rb +2 -2
- data/lib/rubocop/cop/lint/empty_interpolation.rb +5 -6
- data/lib/rubocop/cop/lint/empty_when.rb +2 -2
- data/lib/rubocop/cop/lint/ensure_return.rb +27 -29
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +11 -10
- data/lib/rubocop/cop/lint/flip_flop.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +93 -0
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -4
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +13 -14
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +2 -2
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
- data/lib/rubocop/cop/lint/inherit_exception.rb +12 -7
- data/lib/rubocop/cop/lint/interpolation_check.rb +18 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -2
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -7
- data/lib/rubocop/cop/lint/loop.rb +23 -2
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +6 -5
- data/lib/rubocop/cop/lint/missing_super.rb +99 -0
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/multiple_comparison.rb +6 -9
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +27 -23
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/number_conversion.rb +6 -9
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +11 -13
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +61 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +4 -10
- data/lib/rubocop/cop/lint/percent_string_array.rb +13 -12
- data/lib/rubocop/cop/lint/percent_symbol_array.rb +13 -12
- data/lib/rubocop/cop/lint/raise_exception.rb +12 -10
- data/lib/rubocop/cop/lint/rand_one.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +7 -11
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -7
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -9
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +6 -13
- data/lib/rubocop/cop/lint/redundant_with_index.rb +11 -14
- data/lib/rubocop/cop/lint/redundant_with_object.rb +11 -14
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +4 -6
- data/lib/rubocop/cop/lint/require_parentheses.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +8 -8
- data/lib/rubocop/cop/lint/return_in_void_context.rb +2 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -6
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +14 -10
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +7 -7
- data/lib/rubocop/cop/lint/script_permission.rb +10 -7
- data/lib/rubocop/cop/lint/self_assignment.rb +78 -0
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -11
- data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -3
- data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -2
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -3
- data/lib/rubocop/cop/lint/struct_new_override.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -7
- data/lib/rubocop/cop/lint/to_json.rb +4 -6
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +34 -0
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +4 -4
- data/lib/rubocop/cop/lint/unified_integer.rb +4 -6
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +174 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +8 -3
- data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -3
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +1 -1
- data/lib/rubocop/cop/lint/uri_regexp.rb +11 -31
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +25 -15
- data/lib/rubocop/cop/lint/useless_assignment.rb +4 -4
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +6 -15
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -6
- data/lib/rubocop/cop/lint/void.rb +3 -7
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +2 -2
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
- data/lib/rubocop/cop/metrics/class_length.rb +2 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +2 -1
- data/lib/rubocop/cop/metrics/method_length.rb +2 -2
- data/lib/rubocop/cop/metrics/module_length.rb +2 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +2 -6
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +7 -8
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +48 -5
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +52 -24
- data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +37 -0
- data/lib/rubocop/cop/migration/department_name.rb +13 -15
- data/lib/rubocop/cop/mixin/array_min_size.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/code_length.rb +22 -5
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +10 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +35 -6
- data/lib/rubocop/cop/mixin/surrounding_space.rb +0 -25
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +6 -13
- data/lib/rubocop/cop/mixin/unused_argument.rb +4 -6
- data/lib/rubocop/cop/naming/accessor_method_name.rb +4 -2
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +3 -3
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -2
- data/lib/rubocop/cop/naming/constant_name.rb +2 -2
- data/lib/rubocop/cop/naming/file_name.rb +3 -3
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +2 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +2 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -11
- data/lib/rubocop/cop/registry.rb +3 -3
- data/lib/rubocop/cop/security/eval.rb +2 -2
- data/lib/rubocop/cop/security/json_load.rb +6 -8
- data/lib/rubocop/cop/security/marshal_load.rb +2 -4
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/security/yaml_load.rb +6 -6
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +11 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +9 -7
- data/lib/rubocop/cop/style/alias.rb +7 -3
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -2
- data/lib/rubocop/cop/style/case_equality.rb +22 -3
- data/lib/rubocop/cop/style/case_like_if.rb +2 -2
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -3
- data/lib/rubocop/cop/style/conditional_assignment.rb +11 -2
- data/lib/rubocop/cop/style/documentation.rb +4 -4
- data/lib/rubocop/cop/style/each_with_object.rb +0 -2
- data/lib/rubocop/cop/style/empty_method.rb +5 -5
- data/lib/rubocop/cop/style/eval_with_location.rb +4 -0
- data/lib/rubocop/cop/style/expand_path_arguments.rb +4 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +102 -0
- data/lib/rubocop/cop/style/format_string.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -0
- data/lib/rubocop/cop/style/global_std_stream.rb +65 -0
- data/lib/rubocop/cop/style/guard_clause.rb +2 -2
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +8 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -20
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +2 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -0
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +9 -2
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +4 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +42 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/random_with_offset.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +15 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -9
- data/lib/rubocop/cop/style/redundant_sort.rb +25 -10
- data/lib/rubocop/cop/style/signal_exception.rb +2 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +54 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +92 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +10 -6
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/tokens_util.rb +84 -0
- data/lib/rubocop/cop/util.rb +1 -13
- data/lib/rubocop/cop/variable_force.rb +0 -2
- data/lib/rubocop/cop/variable_force/branch.rb +1 -0
- data/lib/rubocop/cop/variable_force/variable.rb +2 -2
- data/lib/rubocop/cops_documentation_generator.rb +282 -0
- data/lib/rubocop/error.rb +1 -0
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/path_util.rb +19 -4
- data/lib/rubocop/rake_task.rb +1 -0
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/target_finder.rb +12 -9
- data/lib/rubocop/version.rb +2 -2
- metadata +19 -6
- data/lib/rubocop/cop/lint/useless_comparison.rb +0 -28
- data/lib/rubocop/cop/mixin/parser_diagnostic.rb +0 -37
- data/lib/rubocop/cop/mixin/too_many_lines.rb +0 -25
- data/lib/rubocop/cop/style/method_missing_super.rb +0 -34
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Sometimes using dig method ends up with just a single
|
7
|
+
# argument. In such cases, dig should be replaced with [].
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# { key: 'value' }.dig(:key)
|
12
|
+
# [1, 2, 3].dig(0)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# { key: 'value' }[:key]
|
16
|
+
# [1, 2, 3][0]
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# { key1: { key2: 'value' } }.dig(:key1, :key2)
|
20
|
+
# [1, [2, [3]]].dig(1, 1)
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# keys = %i[key1 key2]
|
24
|
+
# { key1: { key2: 'value' } }.dig(*keys)
|
25
|
+
#
|
26
|
+
class SingleArgumentDig < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
|
29
|
+
MSG = 'Use `%<receiver>s[%<argument>s]` instead of `%<original>s`.'
|
30
|
+
|
31
|
+
def_node_matcher :single_argument_dig?, <<~PATTERN
|
32
|
+
(send _ :dig $!splat)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.receiver
|
37
|
+
|
38
|
+
expression = single_argument_dig?(node)
|
39
|
+
return unless expression
|
40
|
+
|
41
|
+
receiver = node.receiver.source
|
42
|
+
argument = expression.source
|
43
|
+
|
44
|
+
message = format(MSG, receiver: receiver, argument: argument,
|
45
|
+
original: node.source)
|
46
|
+
add_offense(node, message: message) do |corrector|
|
47
|
+
correct_access = "#{receiver}[#{argument}]"
|
48
|
+
corrector.replace(node, correct_access)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for places where string concatenation
|
7
|
+
# can be replaced with string interpolation.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# email_with_name = user.name + ' <' + user.email + '>'
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# email_with_name = "#{user.name} <#{user.email}>"
|
15
|
+
# email_with_name = format('%s <%s>', user.name, user.email)
|
16
|
+
#
|
17
|
+
class StringConcatenation < Base
|
18
|
+
include Util
|
19
|
+
extend AutoCorrector
|
20
|
+
|
21
|
+
MSG = 'Prefer string interpolation to string concatenation.'
|
22
|
+
|
23
|
+
def_node_matcher :string_concatenation?, <<~PATTERN
|
24
|
+
{
|
25
|
+
(send str_type? :+ _)
|
26
|
+
(send _ :+ str_type?)
|
27
|
+
}
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return unless node.method?(:+)
|
32
|
+
return unless string_concatenation?(node)
|
33
|
+
|
34
|
+
topmost_plus_node = find_topmost_plus_node(node)
|
35
|
+
|
36
|
+
parts = []
|
37
|
+
collect_parts(topmost_plus_node, parts)
|
38
|
+
|
39
|
+
add_offense(topmost_plus_node) do |corrector|
|
40
|
+
corrector.replace(topmost_plus_node, replacement(parts))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def find_topmost_plus_node(node)
|
47
|
+
current = node
|
48
|
+
while (parent = current.parent) && plus_node?(parent)
|
49
|
+
current = parent
|
50
|
+
end
|
51
|
+
current
|
52
|
+
end
|
53
|
+
|
54
|
+
def collect_parts(node, parts)
|
55
|
+
return unless node
|
56
|
+
|
57
|
+
if plus_node?(node)
|
58
|
+
collect_parts(node.receiver, parts)
|
59
|
+
collect_parts(node.first_argument, parts)
|
60
|
+
else
|
61
|
+
parts << node
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def plus_node?(node)
|
66
|
+
node.send_type? && node.method?(:+)
|
67
|
+
end
|
68
|
+
|
69
|
+
def replacement(parts)
|
70
|
+
interpolated_parts =
|
71
|
+
parts.map do |part|
|
72
|
+
if part.str_type?
|
73
|
+
if single_quoted?(part)
|
74
|
+
part.value.gsub('\\') { '\\\\' }
|
75
|
+
else
|
76
|
+
escape_string(part.value)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
"\#{#{part.source}}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
"\"#{interpolated_parts.join}\""
|
84
|
+
end
|
85
|
+
|
86
|
+
def single_quoted?(str_node)
|
87
|
+
str_node.source.start_with?("'")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
|
34
34
|
def autocorrect(node)
|
35
35
|
lambda do |corrector|
|
36
|
-
corrector.remove(range_with_surrounding_space(range: node.loc.keyword))
|
36
|
+
corrector.remove(range_with_surrounding_space(range: node.loc.keyword, newlines: false))
|
37
37
|
corrector.replace(node.loc.operator, '=')
|
38
38
|
|
39
39
|
correct_parent(node.parent_class, corrector)
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
if c.dsym_type?
|
75
75
|
string_literal = to_string_literal(c.source)
|
76
76
|
|
77
|
-
|
77
|
+
":#{trim_string_interporation_escape_character(string_literal)}"
|
78
78
|
else
|
79
79
|
to_symbol_literal(c.value.to_s)
|
80
80
|
end
|
@@ -84,7 +84,7 @@ module RuboCop
|
|
84
84
|
arg_range = args.last.source_range
|
85
85
|
arg_range = range_with_surrounding_comma(arg_range, :right)
|
86
86
|
replacement = " &:#{method_name}"
|
87
|
-
replacement =
|
87
|
+
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
|
88
88
|
corrector.insert_after(arg_range, replacement)
|
89
89
|
corrector.remove(block_range_with_space(node))
|
90
90
|
end
|
@@ -30,6 +30,8 @@ module RuboCop
|
|
30
30
|
NONZERO_MSG = 'Use `!empty?` instead of ' \
|
31
31
|
'`%<lhs>s %<opr>s %<rhs>s`.'
|
32
32
|
|
33
|
+
LENGTH_METHODS = %i[size length].freeze
|
34
|
+
|
33
35
|
def on_send(node)
|
34
36
|
check_zero_length_predicate(node)
|
35
37
|
check_nonzero_length_predicate(node)
|
@@ -44,31 +46,33 @@ module RuboCop
|
|
44
46
|
private
|
45
47
|
|
46
48
|
def check_zero_length_predicate(node)
|
47
|
-
|
49
|
+
return unless LENGTH_METHODS.include?(node.method_name)
|
48
50
|
|
51
|
+
zero_length_predicate = zero_length_predicate(node.parent)
|
49
52
|
return unless zero_length_predicate
|
50
53
|
|
51
54
|
lhs, opr, rhs = zero_length_predicate
|
52
55
|
|
53
|
-
return if non_polymorphic_collection?(node)
|
56
|
+
return if non_polymorphic_collection?(node.parent)
|
54
57
|
|
55
58
|
add_offense(
|
56
|
-
node,
|
59
|
+
node.parent,
|
57
60
|
message: format(ZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
|
58
61
|
)
|
59
62
|
end
|
60
63
|
|
61
64
|
def check_nonzero_length_predicate(node)
|
62
|
-
|
65
|
+
return unless LENGTH_METHODS.include?(node.method_name)
|
63
66
|
|
67
|
+
nonzero_length_predicate = nonzero_length_predicate(node.parent)
|
64
68
|
return unless nonzero_length_predicate
|
65
69
|
|
66
70
|
lhs, opr, rhs = nonzero_length_predicate
|
67
71
|
|
68
|
-
return if non_polymorphic_collection?(node)
|
72
|
+
return if non_polymorphic_collection?(node.parent)
|
69
73
|
|
70
74
|
add_offense(
|
71
|
-
node,
|
75
|
+
node.parent,
|
72
76
|
message: format(NONZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
|
73
77
|
)
|
74
78
|
end
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
cop_classes = Registry.new(cop_classes.to_a) unless cop_classes.is_a?(Registry)
|
44
44
|
only = options.fetch(:only, [])
|
45
45
|
safe = options.fetch(:safe, false)
|
46
|
-
cop_classes.enabled(config, only, safe).map do |cop_class|
|
46
|
+
cop_classes.enabled(config, only, only_safe: safe).map do |cop_class|
|
47
47
|
cop_class.new(config, options)
|
48
48
|
end
|
49
49
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# Common methods and behaviors for dealing with tokens.
|
5
|
+
module TokensUtil
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# rubocop:disable Metrics/AbcSize
|
9
|
+
def tokens(node)
|
10
|
+
@tokens ||= {}
|
11
|
+
return @tokens[node.object_id] if @tokens[node.object_id]
|
12
|
+
|
13
|
+
@tokens[node.object_id] =
|
14
|
+
# The tokens list is always sorted by token position,
|
15
|
+
# except for cases when heredoc is passed as a method argument.
|
16
|
+
# In this case tokens are interleaved by heredoc contents' tokens.
|
17
|
+
# We can try a fast (binary) search, assuming the mentioned cases are rare,
|
18
|
+
# and fallback to linear search if failed.
|
19
|
+
if (tokens = fast_tokens(node))
|
20
|
+
tokens
|
21
|
+
else
|
22
|
+
begin_pos = node.source_range.begin_pos
|
23
|
+
end_pos = node.source_range.end_pos
|
24
|
+
|
25
|
+
processed_source.tokens.select do |token|
|
26
|
+
token.end_pos <= end_pos && token.begin_pos >= begin_pos
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# rubocop:enable Metrics/AbcSize
|
31
|
+
|
32
|
+
def index_of_first_token(node)
|
33
|
+
index = fast_index_of_first_token(node)
|
34
|
+
return index if index
|
35
|
+
|
36
|
+
begin_pos = node.source_range.begin_pos
|
37
|
+
processed_source.tokens.index { |token| token.begin_pos == begin_pos }
|
38
|
+
end
|
39
|
+
|
40
|
+
def index_of_last_token(node)
|
41
|
+
index = fast_index_of_last_token(node)
|
42
|
+
return index if index
|
43
|
+
|
44
|
+
end_pos = node.source_range.end_pos
|
45
|
+
processed_source.tokens.index { |token| token.end_pos == end_pos }
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def fast_index_of_first_token(node)
|
51
|
+
begin_pos = node.source_range.begin_pos
|
52
|
+
tokens = processed_source.tokens
|
53
|
+
|
54
|
+
index = tokens.bsearch_index { |token| token.begin_pos >= begin_pos }
|
55
|
+
index if index && tokens[index].begin_pos == begin_pos
|
56
|
+
end
|
57
|
+
|
58
|
+
def fast_index_of_last_token(node)
|
59
|
+
end_pos = node.source_range.end_pos
|
60
|
+
tokens = processed_source.tokens
|
61
|
+
|
62
|
+
index = tokens.bsearch_index { |token| token.end_pos >= end_pos }
|
63
|
+
index if index && tokens[index].end_pos == end_pos
|
64
|
+
end
|
65
|
+
|
66
|
+
def fast_tokens(node)
|
67
|
+
begin_index = index_of_first_token(node)
|
68
|
+
end_index = index_of_last_token(node)
|
69
|
+
|
70
|
+
tokens = processed_source.tokens[begin_index..end_index]
|
71
|
+
tokens if sorted_tokens?(tokens)
|
72
|
+
end
|
73
|
+
|
74
|
+
def sorted_tokens?(tokens)
|
75
|
+
prev_begin_pos = -1
|
76
|
+
tokens.each do |token|
|
77
|
+
return false if token.begin_pos < prev_begin_pos
|
78
|
+
|
79
|
+
prev_begin_pos = token.begin_pos
|
80
|
+
end
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -5,6 +5,7 @@ module RuboCop
|
|
5
5
|
# This module contains a collection of useful utility methods.
|
6
6
|
module Util
|
7
7
|
include PathUtil
|
8
|
+
include TokensUtil
|
8
9
|
|
9
10
|
# Match literal regex characters, not including anchors, character
|
10
11
|
# classes, alternatives, groups, repetitions, references, etc
|
@@ -127,19 +128,6 @@ module RuboCop
|
|
127
128
|
.sub('Style', 'Styles')
|
128
129
|
end
|
129
130
|
|
130
|
-
def tokens(node)
|
131
|
-
@tokens ||= {}
|
132
|
-
return @tokens[node.object_id] if @tokens[node.object_id]
|
133
|
-
|
134
|
-
source_range = node.source_range
|
135
|
-
begin_pos = source_range.begin_pos
|
136
|
-
end_pos = source_range.end_pos
|
137
|
-
|
138
|
-
@tokens[node.object_id] = processed_source.tokens.select do |token|
|
139
|
-
token.end_pos <= end_pos && token.begin_pos >= begin_pos
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
131
|
private
|
144
132
|
|
145
133
|
def compatible_external_encoding_for?(src)
|
@@ -197,7 +197,6 @@ module RuboCop
|
|
197
197
|
regexp.named_captures.keys
|
198
198
|
end
|
199
199
|
|
200
|
-
# rubocop:disable Metrics/AbcSize
|
201
200
|
def process_variable_operator_assignment(node)
|
202
201
|
if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
|
203
202
|
asgn_node, rhs_node = *node
|
@@ -232,7 +231,6 @@ module RuboCop
|
|
232
231
|
|
233
232
|
skip_children!
|
234
233
|
end
|
235
|
-
# rubocop:enable Metrics/AbcSize
|
236
234
|
|
237
235
|
def process_variable_multiple_assignment(node)
|
238
236
|
lhs_node, rhs_node = *node
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
38
38
|
!@references.empty?
|
39
39
|
end
|
40
40
|
|
41
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
41
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
42
42
|
def reference!(node)
|
43
43
|
reference = Reference.new(node, @scope)
|
44
44
|
@references << reference
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
66
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
66
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
67
67
|
|
68
68
|
def in_modifier_if?(assignment)
|
69
69
|
parent = assignment.node.parent
|
@@ -0,0 +1,282 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Class for generating documentation of all cops departments
|
4
|
+
class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
5
|
+
# This class will only generate documentation for cops that belong to one of
|
6
|
+
# the departments given in the `departments` array. E.g. if we only wanted
|
7
|
+
# documentation for Lint cops:
|
8
|
+
#
|
9
|
+
# CopsDocumentationGenerator.new(departments: ['Lint']).call
|
10
|
+
#
|
11
|
+
def initialize(departments: [])
|
12
|
+
@departments = departments.map(&:to_sym).sort!
|
13
|
+
@cops = RuboCop::Cop::Cop.registry
|
14
|
+
@config = RuboCop::ConfigLoader.default_configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
YARD::Registry.load!
|
19
|
+
departments.each do |department|
|
20
|
+
print_cops_of_department(department)
|
21
|
+
end
|
22
|
+
|
23
|
+
print_table_of_contents
|
24
|
+
ensure
|
25
|
+
RuboCop::ConfigLoader.default_configuration = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :departments, :cops, :config
|
31
|
+
|
32
|
+
def cops_of_department(department)
|
33
|
+
cops.with_department(department).sort!
|
34
|
+
end
|
35
|
+
|
36
|
+
def cops_body(cop, description, examples_objects, pars)
|
37
|
+
content = h2(cop.cop_name)
|
38
|
+
content << required_ruby_version(cop)
|
39
|
+
content << properties(cop)
|
40
|
+
content << "#{description}\n"
|
41
|
+
content << examples(examples_objects) if examples_objects.count.positive?
|
42
|
+
content << configurations(pars)
|
43
|
+
content << references(cop)
|
44
|
+
content
|
45
|
+
end
|
46
|
+
|
47
|
+
def examples(examples_object)
|
48
|
+
examples_object.each_with_object(h3('Examples').dup) do |example, content|
|
49
|
+
content << "\n" unless content.end_with?("\n\n")
|
50
|
+
content << h4(example.name) unless example.name == ''
|
51
|
+
content << code_example(example)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def required_ruby_version(cop)
|
56
|
+
return '' unless cop.respond_to?(:required_minimum_ruby_version)
|
57
|
+
|
58
|
+
"NOTE: Required Ruby version: #{cop.required_minimum_ruby_version}\n\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
# rubocop:disable Metrics/MethodLength
|
62
|
+
def properties(cop)
|
63
|
+
header = [
|
64
|
+
'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
|
65
|
+
'VersionChanged'
|
66
|
+
]
|
67
|
+
autocorrect = if cop.support_autocorrect?
|
68
|
+
"Yes#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}"
|
69
|
+
else
|
70
|
+
'No'
|
71
|
+
end
|
72
|
+
cop_config = config.for_cop(cop)
|
73
|
+
content = [[
|
74
|
+
cop_status(cop_config.fetch('Enabled')),
|
75
|
+
cop_config.fetch('Safe', true) ? 'Yes' : 'No',
|
76
|
+
autocorrect,
|
77
|
+
cop_config.fetch('VersionAdded', '-'),
|
78
|
+
cop_config.fetch('VersionChanged', '-')
|
79
|
+
]]
|
80
|
+
"#{to_table(header, content)}\n"
|
81
|
+
end
|
82
|
+
# rubocop:enable Metrics/MethodLength
|
83
|
+
|
84
|
+
def h2(title)
|
85
|
+
content = +"\n"
|
86
|
+
content << "== #{title}\n"
|
87
|
+
content << "\n"
|
88
|
+
content
|
89
|
+
end
|
90
|
+
|
91
|
+
def h3(title)
|
92
|
+
content = +"\n"
|
93
|
+
content << "=== #{title}\n"
|
94
|
+
content << "\n"
|
95
|
+
content
|
96
|
+
end
|
97
|
+
|
98
|
+
def h4(title)
|
99
|
+
content = +"==== #{title}\n"
|
100
|
+
content << "\n"
|
101
|
+
content
|
102
|
+
end
|
103
|
+
|
104
|
+
def code_example(ruby_code)
|
105
|
+
content = +"[source,ruby]\n----\n"
|
106
|
+
content << ruby_code.text.gsub('@good', '# good')
|
107
|
+
.gsub('@bad', '# bad').strip
|
108
|
+
content << "\n----\n"
|
109
|
+
content
|
110
|
+
end
|
111
|
+
|
112
|
+
def configurations(pars)
|
113
|
+
return '' if pars.empty?
|
114
|
+
|
115
|
+
header = ['Name', 'Default value', 'Configurable values']
|
116
|
+
configs = pars
|
117
|
+
.each_key
|
118
|
+
.reject { |key| key.start_with?('Supported') }
|
119
|
+
.reject { |key| key.start_with?('AllowMultipleStyles') }
|
120
|
+
content = configs.map do |name|
|
121
|
+
configurable = configurable_values(pars, name)
|
122
|
+
default = format_table_value(pars[name])
|
123
|
+
[name, default, configurable]
|
124
|
+
end
|
125
|
+
|
126
|
+
h3('Configurable attributes') + to_table(header, content)
|
127
|
+
end
|
128
|
+
|
129
|
+
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
130
|
+
def configurable_values(pars, name)
|
131
|
+
case name
|
132
|
+
when /^Enforced/
|
133
|
+
supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
|
134
|
+
format_table_value(pars[supported_style_name])
|
135
|
+
when 'IndentationWidth'
|
136
|
+
'Integer'
|
137
|
+
when 'Database'
|
138
|
+
format_table_value(pars['SupportedDatabases'])
|
139
|
+
else
|
140
|
+
case pars[name]
|
141
|
+
when String
|
142
|
+
'String'
|
143
|
+
when Integer
|
144
|
+
'Integer'
|
145
|
+
when Float
|
146
|
+
'Float'
|
147
|
+
when true, false
|
148
|
+
'Boolean'
|
149
|
+
when Array
|
150
|
+
'Array'
|
151
|
+
else
|
152
|
+
''
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
157
|
+
|
158
|
+
def to_table(header, content)
|
159
|
+
table = [
|
160
|
+
'|===',
|
161
|
+
"| #{header.join(' | ')}\n\n"
|
162
|
+
].join("\n")
|
163
|
+
marked_contents = content.map do |plain_content|
|
164
|
+
plain_content.map { |c| "| #{c}" }.join("\n")
|
165
|
+
end
|
166
|
+
table << marked_contents.join("\n\n")
|
167
|
+
table << "\n|===\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
def format_table_value(val)
|
171
|
+
value =
|
172
|
+
case val
|
173
|
+
when Array
|
174
|
+
if val.empty?
|
175
|
+
'`[]`'
|
176
|
+
else
|
177
|
+
val.map { |config| format_table_value(config) }.join(', ')
|
178
|
+
end
|
179
|
+
else
|
180
|
+
wrap_backtick(val.nil? ? '<none>' : val)
|
181
|
+
end
|
182
|
+
value.gsub("#{Dir.pwd}/", '').rstrip
|
183
|
+
end
|
184
|
+
|
185
|
+
def wrap_backtick(value)
|
186
|
+
if value.is_a?(String)
|
187
|
+
# Use `+` to prevent text like `**/*.gemspec` from being bold.
|
188
|
+
value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
|
189
|
+
else
|
190
|
+
"`#{value}`"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def references(cop)
|
195
|
+
cop_config = config.for_cop(cop)
|
196
|
+
urls = RuboCop::Cop::MessageAnnotator.new(
|
197
|
+
config, cop.name, cop_config, {}
|
198
|
+
).urls
|
199
|
+
return '' if urls.empty?
|
200
|
+
|
201
|
+
content = h3('References')
|
202
|
+
content << urls.map { |url| "* #{url}" }.join("\n")
|
203
|
+
content << "\n"
|
204
|
+
content
|
205
|
+
end
|
206
|
+
|
207
|
+
def print_cops_of_department(department)
|
208
|
+
selected_cops = cops_of_department(department)
|
209
|
+
content = +"= #{department}\n"
|
210
|
+
selected_cops.each do |cop|
|
211
|
+
content << print_cop_with_doc(cop)
|
212
|
+
end
|
213
|
+
file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/cops_#{department.downcase}.adoc"
|
214
|
+
File.open(file_name, 'w') do |file|
|
215
|
+
puts "* generated #{file_name}"
|
216
|
+
file.write("#{content.strip}\n")
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def print_cop_with_doc(cop)
|
221
|
+
cop_config = config.for_cop(cop)
|
222
|
+
non_display_keys = %w[
|
223
|
+
Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
|
224
|
+
VersionChanged
|
225
|
+
]
|
226
|
+
pars = cop_config.reject { |k| non_display_keys.include? k }
|
227
|
+
description = 'No documentation'
|
228
|
+
examples_object = []
|
229
|
+
cop_code(cop) do |code_object|
|
230
|
+
description = code_object.docstring unless code_object.docstring.blank?
|
231
|
+
examples_object = code_object.tags('example')
|
232
|
+
end
|
233
|
+
cops_body(cop, description, examples_object, pars)
|
234
|
+
end
|
235
|
+
|
236
|
+
def cop_code(cop)
|
237
|
+
YARD::Registry.all(:class).detect do |code_object|
|
238
|
+
next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
|
239
|
+
|
240
|
+
yield code_object
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def table_of_content_for_department(department)
|
245
|
+
type_title = department[0].upcase + department[1..-1]
|
246
|
+
filename = "cops_#{department.downcase}.adoc"
|
247
|
+
content = +"=== Department xref:#{filename}[#{type_title}]\n\n"
|
248
|
+
cops_of_department(department).each do |cop|
|
249
|
+
anchor = cop.cop_name.sub('/', '').downcase
|
250
|
+
content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n"
|
251
|
+
end
|
252
|
+
|
253
|
+
content
|
254
|
+
end
|
255
|
+
|
256
|
+
def print_table_of_contents
|
257
|
+
path = "#{Dir.pwd}/docs/modules/ROOT/pages/cops.adoc"
|
258
|
+
original = File.read(path)
|
259
|
+
content = +"// START_COP_LIST\n\n"
|
260
|
+
|
261
|
+
content << table_contents
|
262
|
+
|
263
|
+
content << "\n// END_COP_LIST"
|
264
|
+
|
265
|
+
content = original.sub(
|
266
|
+
%r{// START_COP_LIST.+// END_COP_LIST}m, content
|
267
|
+
)
|
268
|
+
File.write(path, content)
|
269
|
+
end
|
270
|
+
|
271
|
+
def table_contents
|
272
|
+
departments
|
273
|
+
.map { |department| table_of_content_for_department(department) }
|
274
|
+
.join("\n")
|
275
|
+
end
|
276
|
+
|
277
|
+
def cop_status(status)
|
278
|
+
return 'Disabled' unless status
|
279
|
+
|
280
|
+
status == 'pending' ? 'Pending' : 'Enabled'
|
281
|
+
end
|
282
|
+
end
|