rubocop 0.93.1 → 1.6.1
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 +36 -16
- data/config/default.yml +276 -82
- data/config/obsoletion.yml +196 -0
- data/exe/rubocop +1 -1
- data/lib/rubocop.rb +31 -2
- data/lib/rubocop/cli.rb +5 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/execute_runner.rb +26 -11
- data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
- data/lib/rubocop/cli/command/version.rb +1 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +34 -8
- data/lib/rubocop/config_loader_resolver.rb +12 -6
- data/lib/rubocop/config_obsoletion.rb +65 -247
- data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
- data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
- data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
- data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
- data/lib/rubocop/config_obsoletion/rule.rb +41 -0
- data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
- data/lib/rubocop/config_regeneration.rb +1 -1
- data/lib/rubocop/config_validator.rb +25 -10
- data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
- data/lib/rubocop/cop/badge.rb +9 -24
- data/lib/rubocop/cop/base.rb +33 -16
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/commissioner.rb +37 -23
- data/lib/rubocop/cop/cop.rb +2 -2
- data/lib/rubocop/cop/corrector.rb +3 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
- data/lib/rubocop/cop/force.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
- data/lib/rubocop/cop/generator.rb +3 -10
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/class_structure.rb +22 -3
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +80 -10
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
- data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
- data/lib/rubocop/cop/layout/line_length.rb +10 -13
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +26 -2
- data/lib/rubocop/cop/lint/debugger.rb +17 -28
- data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
- data/lib/rubocop/cop/lint/else_layout.rb +29 -3
- data/lib/rubocop/cop/lint/empty_block.rb +82 -0
- data/lib/rubocop/cop/lint/empty_class.rb +93 -0
- data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +39 -7
- data/lib/rubocop/cop/lint/loop.rb +4 -4
- data/lib/rubocop/cop/lint/missing_super.rb +7 -4
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
- data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +86 -0
- data/lib/rubocop/cop/lint/to_json.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +199 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
- data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
- data/lib/rubocop/cop/metrics/block_length.rb +13 -7
- data/lib/rubocop/cop/metrics/method_length.rb +7 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +68 -2
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
- data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
- data/lib/rubocop/cop/migration/department_name.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +4 -3
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
- data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
- data/lib/rubocop/cop/mixin/string_help.rb +4 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
- data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
- data/lib/rubocop/cop/naming/variable_number.rb +100 -8
- data/lib/rubocop/cop/offense.rb +3 -3
- data/lib/rubocop/cop/security/open.rb +12 -10
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +11 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
- data/lib/rubocop/cop/style/case_like_if.rb +0 -4
- data/lib/rubocop/cop/style/character_literal.rb +10 -11
- data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
- data/lib/rubocop/cop/style/collection_compact.rb +91 -0
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +169 -0
- data/lib/rubocop/cop/style/documentation.rb +12 -1
- data/lib/rubocop/cop/style/double_negation.rb +6 -1
- data/lib/rubocop/cop/style/float_division.rb +44 -1
- data/lib/rubocop/cop/style/format_string.rb +8 -3
- data/lib/rubocop/cop/style/format_string_token.rb +47 -2
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +8 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +106 -0
- data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
- data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
- data/lib/rubocop/cop/style/raise_args.rb +21 -6
- data/lib/rubocop/cop/style/redundant_argument.rb +88 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
- data/lib/rubocop/cop/style/redundant_self.rb +3 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
- data/lib/rubocop/cop/style/semicolon.rb +3 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
- data/lib/rubocop/cop/style/static_class.rb +97 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +39 -2
- data/lib/rubocop/cop/style/string_literals.rb +14 -8
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
- data/lib/rubocop/cop/style/swap_values.rb +108 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
- data/lib/rubocop/cop/team.rb +6 -1
- data/lib/rubocop/cop/util.rb +6 -2
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/core_ext/hash.rb +20 -0
- data/lib/rubocop/ext/regexp_node.rb +36 -11
- data/lib/rubocop/ext/regexp_parser.rb +95 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
- data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
- data/lib/rubocop/formatter/tap_formatter.rb +2 -0
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/lockfile.rb +40 -0
- data/lib/rubocop/magic_comment.rb +2 -2
- data/lib/rubocop/options.rb +11 -1
- data/lib/rubocop/rake_task.rb +2 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +65 -1
- data/lib/rubocop/version.rb +56 -6
- metadata +50 -9
- data/bin/console +0 -10
- data/bin/rubocop-profile +0 -32
- data/bin/setup +0 -7
@@ -55,13 +55,18 @@ module RuboCop
|
|
55
55
|
padding = ((' ' * indent_width) + leading_spaces(node)).to_s
|
56
56
|
padding_for_trailing_end = padding.sub(' ' * node.loc.end.column, '')
|
57
57
|
|
58
|
-
|
58
|
+
replace_namespace_keyword(corrector, node)
|
59
59
|
split_on_double_colon(corrector, node, padding)
|
60
60
|
add_trailing_end(corrector, node, padding_for_trailing_end)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
|
63
|
+
def replace_namespace_keyword(corrector, node)
|
64
|
+
class_definition = node.left_sibling&.each_node(:class)&.find do |class_node|
|
65
|
+
class_node.identifier == node.identifier.namespace
|
66
|
+
end
|
67
|
+
namespace_keyword = class_definition ? 'class' : 'module'
|
68
|
+
|
69
|
+
corrector.replace(node.loc.keyword, namespace_keyword)
|
65
70
|
end
|
66
71
|
|
67
72
|
def split_on_double_colon(corrector, node, padding)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for places where custom logic on rejection nils from arrays
|
7
|
+
# and hashes can be replaced with `{Array,Hash}#{compact,compact!}`.
|
8
|
+
#
|
9
|
+
# It is marked as unsafe by default because false positives may occur in the
|
10
|
+
# nil check of block arguments to the receiver object.
|
11
|
+
# For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
|
12
|
+
# and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
|
13
|
+
# when the receiver is a hash object.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# # bad
|
17
|
+
# array.reject { |e| e.nil? }
|
18
|
+
# array.select { |e| !e.nil? }
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# array.compact
|
22
|
+
#
|
23
|
+
# # bad
|
24
|
+
# hash.reject! { |k, v| v.nil? }
|
25
|
+
# hash.select! { |k, v| !v.nil? }
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# hash.compact!
|
29
|
+
#
|
30
|
+
class CollectionCompact < Base
|
31
|
+
include RangeHelp
|
32
|
+
extend AutoCorrector
|
33
|
+
|
34
|
+
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
35
|
+
|
36
|
+
RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
|
37
|
+
|
38
|
+
def_node_matcher :reject_method?, <<~PATTERN
|
39
|
+
(block
|
40
|
+
(send
|
41
|
+
_ ${:reject :reject!})
|
42
|
+
$(args ...)
|
43
|
+
(send
|
44
|
+
$(lvar _) :nil?))
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def_node_matcher :select_method?, <<~PATTERN
|
48
|
+
(block
|
49
|
+
(send
|
50
|
+
_ ${:select :select!})
|
51
|
+
$(args ...)
|
52
|
+
(send
|
53
|
+
(send
|
54
|
+
$(lvar _) :nil?) :!))
|
55
|
+
PATTERN
|
56
|
+
|
57
|
+
def on_send(node)
|
58
|
+
block_node = node.parent
|
59
|
+
return unless block_node&.block_type?
|
60
|
+
|
61
|
+
return unless (method_name, args, receiver =
|
62
|
+
reject_method?(block_node) || select_method?(block_node))
|
63
|
+
|
64
|
+
return unless args.last.source == receiver.source
|
65
|
+
|
66
|
+
range = offense_range(node, block_node)
|
67
|
+
good = good_method_name(method_name)
|
68
|
+
message = format(MSG, good: good, bad: range.source)
|
69
|
+
|
70
|
+
add_offense(range, message: message) do |corrector|
|
71
|
+
corrector.replace(range, good)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def good_method_name(method_name)
|
78
|
+
if method_name.to_s.end_with?('!')
|
79
|
+
'compact!'
|
80
|
+
else
|
81
|
+
'compact'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def offense_range(send_node, block_node)
|
86
|
+
range_between(send_node.loc.selector.begin_pos, block_node.loc.end.end_pos)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# When using `class_eval` (or other `eval`) with string interpolation,
|
7
|
+
# add a comment block showing its appearance if interpolated (a practice used in Rails code).
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # from activesupport/lib/active_support/core_ext/string/output_safety.rb
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# UNSAFE_STRING_METHODS.each do |unsafe_method|
|
14
|
+
# if 'String'.respond_to?(unsafe_method)
|
15
|
+
# class_eval <<-EOT, __FILE__, __LINE__ + 1
|
16
|
+
# def #{unsafe_method}(*params, &block)
|
17
|
+
# to_str.#{unsafe_method}(*params, &block)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def #{unsafe_method}!(*params)
|
21
|
+
# @dirty = true
|
22
|
+
# super
|
23
|
+
# end
|
24
|
+
# EOT
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # good, inline comments in heredoc
|
29
|
+
# UNSAFE_STRING_METHODS.each do |unsafe_method|
|
30
|
+
# if 'String'.respond_to?(unsafe_method)
|
31
|
+
# class_eval <<-EOT, __FILE__, __LINE__ + 1
|
32
|
+
# def #{unsafe_method}(*params, &block) # def capitalize(*params, &block)
|
33
|
+
# to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block)
|
34
|
+
# end # end
|
35
|
+
#
|
36
|
+
# def #{unsafe_method}!(*params) # def capitalize!(*params)
|
37
|
+
# @dirty = true # @dirty = true
|
38
|
+
# super # super
|
39
|
+
# end # end
|
40
|
+
# EOT
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # good, block comments in heredoc
|
45
|
+
# class_eval <<-EOT, __FILE__, __LINE__ + 1
|
46
|
+
# # def capitalize!(*params)
|
47
|
+
# # @dirty = true
|
48
|
+
# # super
|
49
|
+
# # end
|
50
|
+
#
|
51
|
+
# def #{unsafe_method}!(*params)
|
52
|
+
# @dirty = true
|
53
|
+
# super
|
54
|
+
# end
|
55
|
+
# EOT
|
56
|
+
#
|
57
|
+
# # good, block comments before heredoc
|
58
|
+
# class_eval(
|
59
|
+
# # def capitalize!(*params)
|
60
|
+
# # @dirty = true
|
61
|
+
# # super
|
62
|
+
# # end
|
63
|
+
#
|
64
|
+
# <<-EOT, __FILE__, __LINE__ + 1
|
65
|
+
# def #{unsafe_method}!(*params)
|
66
|
+
# @dirty = true
|
67
|
+
# super
|
68
|
+
# end
|
69
|
+
# EOT
|
70
|
+
# )
|
71
|
+
#
|
72
|
+
# # bad - interpolated string without comment
|
73
|
+
# class_eval("def #{unsafe_method}!(*params); end")
|
74
|
+
#
|
75
|
+
# # good - with inline comment or replace it with block comment using heredoc
|
76
|
+
# class_eval("def #{unsafe_method}!(*params); end # def capitalize!(*params); end")
|
77
|
+
class DocumentDynamicEvalDefinition < Base
|
78
|
+
BLOCK_COMMENT_REGEXP = /^\s*#(?!{)/.freeze
|
79
|
+
COMMENT_REGEXP = /\s*#(?!{).*/.freeze
|
80
|
+
MSG = 'Add a comment block showing its appearance if interpolated.'
|
81
|
+
|
82
|
+
RESTRICT_ON_SEND = %i[eval class_eval module_eval instance_eval].freeze
|
83
|
+
|
84
|
+
def on_send(node)
|
85
|
+
arg_node = node.first_argument
|
86
|
+
|
87
|
+
return unless arg_node&.dstr_type? && interpolated?(arg_node)
|
88
|
+
return if inline_comment_docs?(arg_node) ||
|
89
|
+
arg_node.heredoc? && comment_block_docs?(arg_node)
|
90
|
+
|
91
|
+
add_offense(node.loc.selector)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def interpolated?(arg_node)
|
97
|
+
arg_node.each_child_node(:begin).any?
|
98
|
+
end
|
99
|
+
|
100
|
+
def inline_comment_docs?(node)
|
101
|
+
node.each_child_node(:begin).all? do |begin_node|
|
102
|
+
source_line = processed_source.lines[begin_node.first_line - 1]
|
103
|
+
source_line.match?(COMMENT_REGEXP)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def comment_block_docs?(arg_node)
|
108
|
+
comments = heredoc_comment_blocks(arg_node.loc.heredoc_body.line_span)
|
109
|
+
.concat(preceding_comment_blocks(arg_node.parent))
|
110
|
+
|
111
|
+
return if comments.none?
|
112
|
+
|
113
|
+
regexp = comment_regexp(arg_node)
|
114
|
+
comments.any? { |comment| regexp.match?(comment) } || regexp.match?(comments.join)
|
115
|
+
end
|
116
|
+
|
117
|
+
def preceding_comment_blocks(node)
|
118
|
+
# Collect comments in the method call, but outside the heredoc
|
119
|
+
comments = processed_source.each_comment_in_lines(node.loc.expression.line_span)
|
120
|
+
|
121
|
+
comments.each_with_object({}) do |comment, hash|
|
122
|
+
merge_adjacent_comments(comment.text, comment.loc.line, hash)
|
123
|
+
end.values
|
124
|
+
end
|
125
|
+
|
126
|
+
def heredoc_comment_blocks(heredoc_body)
|
127
|
+
# Collect comments inside the heredoc
|
128
|
+
line_range = (heredoc_body.begin - 1)..(heredoc_body.end - 1)
|
129
|
+
lines = processed_source.lines[line_range]
|
130
|
+
|
131
|
+
lines.each_with_object({}).with_index(line_range.begin) do |(line, hash), index|
|
132
|
+
merge_adjacent_comments(line, index, hash)
|
133
|
+
end.values
|
134
|
+
end
|
135
|
+
|
136
|
+
def merge_adjacent_comments(line, index, hash)
|
137
|
+
# Combine adjacent comment lines into a single string
|
138
|
+
return unless (line = line.dup.gsub!(BLOCK_COMMENT_REGEXP, ''))
|
139
|
+
|
140
|
+
hash[index] = if hash.keys.last == index - 1
|
141
|
+
[hash.delete(index - 1), line].join("\n")
|
142
|
+
else
|
143
|
+
line
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def comment_regexp(arg_node)
|
148
|
+
# Replace the interpolations with wildcards
|
149
|
+
regexp_parts = arg_node.child_nodes.map do |n|
|
150
|
+
n.begin_type? ? /.+/ : source_to_regexp(n.source)
|
151
|
+
end
|
152
|
+
|
153
|
+
Regexp.new(regexp_parts.join)
|
154
|
+
end
|
155
|
+
|
156
|
+
def source_to_regexp(source)
|
157
|
+
# Get the source in the heredoc being `eval`ed, without any comments
|
158
|
+
# and turn it into a regexp
|
159
|
+
return /\s+/ if source.blank?
|
160
|
+
|
161
|
+
source = source.gsub(COMMENT_REGEXP, '')
|
162
|
+
return if source.blank?
|
163
|
+
|
164
|
+
/\s*#{Regexp.escape(source.strip)}/
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -55,6 +55,11 @@ module RuboCop
|
|
55
55
|
# Public = Class.new
|
56
56
|
# end
|
57
57
|
#
|
58
|
+
# # Macro calls
|
59
|
+
# module Namespace
|
60
|
+
# extend Foo
|
61
|
+
# end
|
62
|
+
#
|
58
63
|
class Documentation < Base
|
59
64
|
include DocumentationComment
|
60
65
|
|
@@ -83,15 +88,21 @@ module RuboCop
|
|
83
88
|
return if documentation_comment?(node) || nodoc_comment?(node)
|
84
89
|
return if compact_namespace?(node) &&
|
85
90
|
nodoc_comment?(outer_module(node).first)
|
91
|
+
return if macro_only?(body)
|
86
92
|
|
87
93
|
add_offense(node.loc.keyword, message: format(MSG, type: type))
|
88
94
|
end
|
89
95
|
|
96
|
+
def macro_only?(body)
|
97
|
+
body.respond_to?(:macro?) && body.macro? ||
|
98
|
+
body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
|
99
|
+
end
|
100
|
+
|
90
101
|
def namespace?(node)
|
91
102
|
return false unless node
|
92
103
|
|
93
104
|
if node.begin_type?
|
94
|
-
node.children.all?
|
105
|
+
node.children.all? { |child| constant_declaration?(child) }
|
95
106
|
else
|
96
107
|
constant_definition?(node)
|
97
108
|
end
|
@@ -34,6 +34,7 @@ module RuboCop
|
|
34
34
|
# this is rarely a problem in practice.
|
35
35
|
class DoubleNegation < Base
|
36
36
|
include ConfigurableEnforcedStyle
|
37
|
+
extend AutoCorrector
|
37
38
|
|
38
39
|
MSG = 'Avoid the use of double negation (`!!`).'
|
39
40
|
RESTRICT_ON_SEND = %i[!].freeze
|
@@ -44,7 +45,11 @@ module RuboCop
|
|
44
45
|
return unless double_negative?(node) && node.prefix_bang?
|
45
46
|
return if style == :allowed_in_returns && allowed_in_returns?(node)
|
46
47
|
|
47
|
-
|
48
|
+
location = node.loc.selector
|
49
|
+
add_offense(location) do |corrector|
|
50
|
+
corrector.remove(location)
|
51
|
+
corrector.insert_after(node, '.nil?')
|
52
|
+
end
|
48
53
|
end
|
49
54
|
|
50
55
|
private
|
@@ -41,6 +41,8 @@ module RuboCop
|
|
41
41
|
# a.fdiv(b)
|
42
42
|
class FloatDivision < Base
|
43
43
|
include ConfigurableEnforcedStyle
|
44
|
+
extend AutoCorrector
|
45
|
+
|
44
46
|
MESSAGES = {
|
45
47
|
left_coerce: 'Prefer using `.to_f` on the left side.',
|
46
48
|
right_coerce: 'Prefer using `.to_f` on the right side.',
|
@@ -64,7 +66,20 @@ module RuboCop
|
|
64
66
|
PATTERN
|
65
67
|
|
66
68
|
def on_send(node)
|
67
|
-
|
69
|
+
return unless offense_condition?(node)
|
70
|
+
|
71
|
+
add_offense(node) do |corrector|
|
72
|
+
case style
|
73
|
+
when :left_coerce, :single_coerce
|
74
|
+
add_to_f_method(corrector, node.receiver)
|
75
|
+
remove_to_f_method(corrector, node.first_argument)
|
76
|
+
when :right_coerce
|
77
|
+
remove_to_f_method(corrector, node.receiver)
|
78
|
+
add_to_f_method(corrector, node.first_argument)
|
79
|
+
when :fdiv
|
80
|
+
correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
|
81
|
+
end
|
82
|
+
end
|
68
83
|
end
|
69
84
|
|
70
85
|
private
|
@@ -87,6 +102,34 @@ module RuboCop
|
|
87
102
|
def message(_node)
|
88
103
|
MESSAGES[style]
|
89
104
|
end
|
105
|
+
|
106
|
+
def add_to_f_method(corrector, node)
|
107
|
+
corrector.insert_after(node, '.to_f') unless node.send_type? && node.method?(:to_f)
|
108
|
+
end
|
109
|
+
|
110
|
+
def remove_to_f_method(corrector, send_node)
|
111
|
+
corrector.remove(send_node.loc.dot)
|
112
|
+
corrector.remove(send_node.loc.selector)
|
113
|
+
end
|
114
|
+
|
115
|
+
def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
|
116
|
+
receiver_source = extract_receiver_source(receiver)
|
117
|
+
argument_source = extract_receiver_source(argument)
|
118
|
+
|
119
|
+
if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
|
120
|
+
argument_source = "(#{argument_source})"
|
121
|
+
end
|
122
|
+
|
123
|
+
corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
|
124
|
+
end
|
125
|
+
|
126
|
+
def extract_receiver_source(node)
|
127
|
+
if node.send_type? && node.method?(:to_f)
|
128
|
+
node.receiver.source
|
129
|
+
else
|
130
|
+
node.source
|
131
|
+
end
|
132
|
+
end
|
90
133
|
end
|
91
134
|
end
|
92
135
|
end
|
@@ -111,15 +111,20 @@ module RuboCop
|
|
111
111
|
format = format_arg.source
|
112
112
|
|
113
113
|
args = if param_args.one?
|
114
|
-
|
115
|
-
|
116
|
-
arg.hash_type? ? "{ #{arg.source} }" : arg.source
|
114
|
+
format_single_parameter(param_args.last)
|
117
115
|
else
|
118
116
|
"[#{param_args.map(&:source).join(', ')}]"
|
119
117
|
end
|
120
118
|
|
121
119
|
corrector.replace(node, "#{format} % #{args}")
|
122
120
|
end
|
121
|
+
|
122
|
+
def format_single_parameter(arg)
|
123
|
+
source = arg.source
|
124
|
+
return "{ #{source} }" if arg.hash_type?
|
125
|
+
|
126
|
+
arg.send_type? && arg.operator_method? && !arg.parenthesized? ? "(#{source})" : source
|
127
|
+
end
|
123
128
|
end
|
124
129
|
end
|
125
130
|
end
|
@@ -37,6 +37,27 @@ module RuboCop
|
|
37
37
|
#
|
38
38
|
# # good
|
39
39
|
# format('%s', 'Hello')
|
40
|
+
#
|
41
|
+
# It is allowed to contain unannotated token
|
42
|
+
# if the number of them is less than or equals to
|
43
|
+
# `MaxUnannotatedPlaceholdersAllowed`.
|
44
|
+
#
|
45
|
+
# @example MaxUnannotatedPlaceholdersAllowed: 0
|
46
|
+
#
|
47
|
+
# # bad
|
48
|
+
# format('%06d', 10)
|
49
|
+
# format('%s %s.', 'Hello', 'world')
|
50
|
+
#
|
51
|
+
# # good
|
52
|
+
# format('%<number>06d', number: 10)
|
53
|
+
#
|
54
|
+
# @example MaxUnannotatedPlaceholdersAllowed: 1 (default)
|
55
|
+
#
|
56
|
+
# # bad
|
57
|
+
# format('%s %s.', 'Hello', 'world')
|
58
|
+
#
|
59
|
+
# # good
|
60
|
+
# format('%06d', 10)
|
40
61
|
class FormatStringToken < Base
|
41
62
|
include ConfigurableEnforcedStyle
|
42
63
|
|
@@ -44,8 +65,12 @@ module RuboCop
|
|
44
65
|
return unless node.value.include?('%')
|
45
66
|
return if node.each_ancestor(:xstr, :regexp).any?
|
46
67
|
|
47
|
-
|
48
|
-
|
68
|
+
detections = collect_detections(node)
|
69
|
+
return if detections.empty?
|
70
|
+
return if allowed_unannotated?(detections)
|
71
|
+
|
72
|
+
detections.each do |detected_style, token_range|
|
73
|
+
if detected_style == style
|
49
74
|
correct_style_detected
|
50
75
|
else
|
51
76
|
style_detected(detected_style)
|
@@ -112,6 +137,26 @@ module RuboCop
|
|
112
137
|
yield(detected_style, token)
|
113
138
|
end
|
114
139
|
end
|
140
|
+
|
141
|
+
def collect_detections(node)
|
142
|
+
detections = []
|
143
|
+
tokens(node) do |detected_style, token_range|
|
144
|
+
unless unannotated_format?(node, detected_style)
|
145
|
+
detections << [detected_style, token_range]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
detections
|
149
|
+
end
|
150
|
+
|
151
|
+
def allowed_unannotated?(detections)
|
152
|
+
return false if detections.size > max_unannotated_placeholders_allowed
|
153
|
+
|
154
|
+
detections.all? { |detected_style,| detected_style == :unannotated }
|
155
|
+
end
|
156
|
+
|
157
|
+
def max_unannotated_placeholders_allowed
|
158
|
+
cop_config['MaxUnannotatedPlaceholdersAllowed']
|
159
|
+
end
|
115
160
|
end
|
116
161
|
end
|
117
162
|
end
|