rubocop 1.88.0 → 1.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/config/default.yml +72 -12
- data/lib/rubocop/comment_config.rb +35 -19
- data/lib/rubocop/config.rb +53 -0
- data/lib/rubocop/config_validator.rb +38 -1
- data/lib/rubocop/cop/badge.rb +8 -0
- data/lib/rubocop/cop/base.rb +19 -12
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -1
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +55 -5
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -1
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +12 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -1
- data/lib/rubocop/cop/gemspec.rb +22 -0
- data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
- data/lib/rubocop/cop/generator.rb +4 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +17 -0
- data/lib/rubocop/cop/layout/class_structure.rb +14 -4
- data/lib/rubocop/cop/layout/comment_indentation.rb +9 -2
- data/lib/rubocop/cop/layout/condition_position.rb +13 -3
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -14
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +14 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +13 -14
- data/lib/rubocop/cop/layout/indentation_width.rb +31 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- data/lib/rubocop/cop/layout/line_length.rb +95 -17
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +77 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -2
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +33 -34
- data/lib/rubocop/cop/layout.rb +114 -0
- data/lib/rubocop/cop/lazy_loader.rb +41 -0
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -7
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +71 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +13 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +1 -10
- data/lib/rubocop/cop/lint/constant_resolution.rb +25 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -1
- data/lib/rubocop/cop/lint/deprecated_reference.rb +185 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +202 -22
- data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- data/lib/rubocop/cop/lint/name_typo.rb +223 -0
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +7 -0
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +0 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +44 -2
- data/lib/rubocop/cop/lint/to_json.rb +8 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +32 -8
- data/lib/rubocop/cop/lint/unreachable_code.rb +9 -4
- data/lib/rubocop/cop/lint/unused_private_method.rb +157 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -0
- data/lib/rubocop/cop/lint/void.rb +19 -8
- data/lib/rubocop/cop/lint.rb +176 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +38 -7
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics.rb +31 -0
- data/lib/rubocop/cop/migration/department_name.rb +0 -4
- data/lib/rubocop/cop/migration.rb +13 -0
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -5
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +23 -6
- data/lib/rubocop/cop/mixin/hash_subset.rb +8 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +4 -0
- data/lib/rubocop/cop/mixin/project_index_help.rb +140 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +43 -7
- data/lib/rubocop/cop/mixin.rb +78 -77
- data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
- data/lib/rubocop/cop/naming/file_name.rb +4 -3
- data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +9 -0
- data/lib/rubocop/cop/naming/predicate_prefix.rb +33 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +9 -3
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/naming.rb +31 -0
- data/lib/rubocop/cop/offense.rb +10 -6
- data/lib/rubocop/cop/registry.rb +153 -43
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/security.rb +19 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +11 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -1
- data/lib/rubocop/cop/style/array_intersect.rb +24 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +78 -18
- data/lib/rubocop/cop/style/collection_compact.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +22 -0
- data/lib/rubocop/cop/style/copyright.rb +6 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +4 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
- data/lib/rubocop/cop/style/dir_empty.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +41 -3
- data/lib/rubocop/cop/style/documentation.rb +47 -0
- data/lib/rubocop/cop/style/documentation_method.rb +5 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +12 -2
- data/lib/rubocop/cop/style/empty_class_definition.rb +8 -1
- data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
- data/lib/rubocop/cop/style/empty_literal.rb +7 -2
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +30 -20
- data/lib/rubocop/cop/style/endless_method.rb +0 -10
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- data/lib/rubocop/cop/style/even_odd.rb +11 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -1
- data/lib/rubocop/cop/style/file_null.rb +4 -2
- data/lib/rubocop/cop/style/format_string.rb +13 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +14 -6
- data/lib/rubocop/cop/style/hash_lookup_method.rb +2 -6
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -4
- data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -52
- data/lib/rubocop/cop/style/if_with_semicolon.rb +9 -1
- data/lib/rubocop/cop/style/inline_comment.rb +1 -1
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +7 -3
- data/lib/rubocop/cop/style/lambda.rb +11 -1
- data/lib/rubocop/cop/style/lambda_call.rb +11 -0
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
- data/lib/rubocop/cop/style/map_into_array.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -3
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -5
- data/lib/rubocop/cop/style/method_def_parentheses.rb +5 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +3 -0
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +4 -2
- data/lib/rubocop/cop/style/multiline_if_then.rb +7 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +11 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +5 -0
- data/lib/rubocop/cop/style/negative_array_index.rb +3 -1
- data/lib/rubocop/cop/style/nil_lambda.rb +8 -0
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +11 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
- data/lib/rubocop/cop/style/redundant_assignment.rb +11 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +37 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +6 -0
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +40 -3
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +80 -129
- data/lib/rubocop/cop/style/redundant_parentheses.rb +63 -63
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -4
- data/lib/rubocop/cop/style/redundant_self.rb +9 -0
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +23 -4
- data/lib/rubocop/cop/style/safe_navigation.rb +10 -0
- data/lib/rubocop/cop/style/semicolon.rb +4 -4
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +17 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +20 -3
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +3 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -8
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style.rb +310 -0
- data/lib/rubocop/cop/team.rb +66 -7
- data/lib/rubocop/cop/variable_force/variable.rb +18 -6
- data/lib/rubocop/cops_documentation_generator.rb +1 -1
- data/lib/rubocop/directive_comment.rb +2 -0
- data/lib/rubocop/feature_loader.rb +0 -6
- data/lib/rubocop/lsp/routes.rb +41 -3
- data/lib/rubocop/lsp/runtime.rb +4 -0
- data/lib/rubocop/lsp/server.rb +4 -0
- data/lib/rubocop/lsp/stdin_runner.rb +20 -0
- data/lib/rubocop/pending_cops_reporter.rb +1 -6
- data/lib/rubocop/project_index_loader.rb +16 -0
- data/lib/rubocop/result_cache.rb +6 -4
- data/lib/rubocop/rspec/shared_contexts.rb +14 -2
- data/lib/rubocop/runner.rb +100 -33
- data/lib/rubocop/server/cache.rb +10 -5
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +17 -626
- metadata +18 -3
|
@@ -16,11 +16,14 @@ module RuboCop
|
|
|
16
16
|
# enumerator.each { |item| item >= 2 } #=> [2, 3]
|
|
17
17
|
# ----
|
|
18
18
|
#
|
|
19
|
-
# NOTE:
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
19
|
+
# NOTE: The last expression in an assignment method definition such as `def foo=(arg)`
|
|
20
|
+
# is not flagged. Ruby discards it (the method returns its argument), but the method can
|
|
21
|
+
# still be called directly and its return value relied upon, so flagging it would be a
|
|
22
|
+
# false positive for this lint.
|
|
23
|
+
#
|
|
24
|
+
# NOTE: A constant used in a void context is flagged but not autocorrected, since
|
|
25
|
+
# referencing a constant can trigger autoloading side effects (e.g. forcing a file to
|
|
26
|
+
# load before a monkey-patch), so removing it may change behavior.
|
|
24
27
|
#
|
|
25
28
|
# @example CheckForMethodsWithNoSideEffects: false (default)
|
|
26
29
|
# # bad
|
|
@@ -109,7 +112,7 @@ module RuboCop
|
|
|
109
112
|
def check_begin(node)
|
|
110
113
|
expressions = *node
|
|
111
114
|
inside_each_block = node.each_ancestor(:any_block).first&.method?(:each)
|
|
112
|
-
expressions.pop if !in_void_context?(node) || inside_each_block
|
|
115
|
+
expressions.pop if !in_void_context?(node) || inside_each_block || setter_method?(node)
|
|
113
116
|
expressions.each do |expr|
|
|
114
117
|
check_void_op(expr) { inside_each_block }
|
|
115
118
|
check_expression(expr)
|
|
@@ -212,7 +215,7 @@ module RuboCop
|
|
|
212
215
|
end
|
|
213
216
|
|
|
214
217
|
def check_nonmutating(node)
|
|
215
|
-
return unless node.type?(:
|
|
218
|
+
return unless node.type?(:call, :any_block)
|
|
216
219
|
|
|
217
220
|
method_name = node.method_name
|
|
218
221
|
return unless NONMUTATING_METHODS.include?(method_name)
|
|
@@ -244,6 +247,10 @@ module RuboCop
|
|
|
244
247
|
parent.respond_to?(:void_context?) && parent.void_context?
|
|
245
248
|
end
|
|
246
249
|
|
|
250
|
+
def setter_method?(node)
|
|
251
|
+
node.parent&.any_def_type? && node.parent.assignment_method?
|
|
252
|
+
end
|
|
253
|
+
|
|
247
254
|
def autocorrect_void_op(corrector, node)
|
|
248
255
|
if node.arguments.empty?
|
|
249
256
|
corrector.replace(node, node.receiver.source)
|
|
@@ -258,6 +265,10 @@ module RuboCop
|
|
|
258
265
|
end
|
|
259
266
|
|
|
260
267
|
def autocorrect_void_expression(corrector, node)
|
|
268
|
+
# Referencing a constant can trigger autoloading side effects (e.g. forcing a file
|
|
269
|
+
# to load before a monkey-patch), so removing it may change behavior. Flag but don't
|
|
270
|
+
# autocorrect, leaving it to the user.
|
|
271
|
+
return if node.const_type? && !node.special_keyword?
|
|
261
272
|
return if node.parent.type?(:if, :case, :when, :case_match, :in_pattern)
|
|
262
273
|
return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
|
|
263
274
|
|
|
@@ -265,7 +276,7 @@ module RuboCop
|
|
|
265
276
|
end
|
|
266
277
|
|
|
267
278
|
def autocorrect_nonmutating_send(corrector, node, suggestion)
|
|
268
|
-
send_node = if node.
|
|
279
|
+
send_node = if node.call_type?
|
|
269
280
|
node
|
|
270
281
|
else
|
|
271
282
|
node.send_node
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Cops for the `Lint` department. The department's cops are registered for lazy loading
|
|
6
|
+
# and their files are loaded on demand.
|
|
7
|
+
module Lint
|
|
8
|
+
extend LazyLoader
|
|
9
|
+
|
|
10
|
+
register_cop :AmbiguousAssignment, "#{__dir__}/lint/ambiguous_assignment"
|
|
11
|
+
register_cop :AmbiguousBlockAssociation, "#{__dir__}/lint/ambiguous_block_association"
|
|
12
|
+
register_cop :AmbiguousOperator, "#{__dir__}/lint/ambiguous_operator"
|
|
13
|
+
register_cop :AmbiguousOperatorPrecedence, "#{__dir__}/lint/ambiguous_operator_precedence"
|
|
14
|
+
register_cop :AmbiguousRange, "#{__dir__}/lint/ambiguous_range"
|
|
15
|
+
register_cop :AmbiguousRegexpLiteral, "#{__dir__}/lint/ambiguous_regexp_literal"
|
|
16
|
+
register_cop :ArrayLiteralInRegexp, "#{__dir__}/lint/array_literal_in_regexp"
|
|
17
|
+
register_cop :AssignmentInCondition, "#{__dir__}/lint/assignment_in_condition"
|
|
18
|
+
register_cop :BigDecimalNew, "#{__dir__}/lint/big_decimal_new"
|
|
19
|
+
register_cop :BinaryOperatorWithIdenticalOperands, "#{__dir__}/lint/binary_operator_with_identical_operands"
|
|
20
|
+
register_cop :BooleanSymbol, "#{__dir__}/lint/boolean_symbol"
|
|
21
|
+
register_cop :CircularArgumentReference, "#{__dir__}/lint/circular_argument_reference"
|
|
22
|
+
register_cop :ConstantDefinitionInBlock, "#{__dir__}/lint/constant_definition_in_block"
|
|
23
|
+
register_cop :ConstantOverwrittenInRescue, "#{__dir__}/lint/constant_overwritten_in_rescue"
|
|
24
|
+
register_cop :ConstantReassignment, "#{__dir__}/lint/constant_reassignment"
|
|
25
|
+
register_cop :ConstantResolution, "#{__dir__}/lint/constant_resolution"
|
|
26
|
+
register_cop :CopDirectiveSyntax, "#{__dir__}/lint/cop_directive_syntax"
|
|
27
|
+
register_cop :DataDefineOverride, "#{__dir__}/lint/data_define_override"
|
|
28
|
+
register_cop :Debugger, "#{__dir__}/lint/debugger"
|
|
29
|
+
register_cop :DeprecatedClassMethods, "#{__dir__}/lint/deprecated_class_methods"
|
|
30
|
+
register_cop :DeprecatedConstants, "#{__dir__}/lint/deprecated_constants"
|
|
31
|
+
register_cop :DeprecatedOpenSSLConstant, "#{__dir__}/lint/deprecated_open_ssl_constant"
|
|
32
|
+
register_cop :DeprecatedReference, "#{__dir__}/lint/deprecated_reference"
|
|
33
|
+
register_cop :DisjunctiveAssignmentInConstructor, "#{__dir__}/lint/disjunctive_assignment_in_constructor"
|
|
34
|
+
register_cop :DuplicateBranch, "#{__dir__}/lint/duplicate_branch"
|
|
35
|
+
register_cop :DuplicateCaseCondition, "#{__dir__}/lint/duplicate_case_condition"
|
|
36
|
+
register_cop :DuplicateElsifCondition, "#{__dir__}/lint/duplicate_elsif_condition"
|
|
37
|
+
register_cop :DuplicateHashKey, "#{__dir__}/lint/duplicate_hash_key"
|
|
38
|
+
register_cop :DuplicateMagicComment, "#{__dir__}/lint/duplicate_magic_comment"
|
|
39
|
+
register_cop :DuplicateMatchPattern, "#{__dir__}/lint/duplicate_match_pattern"
|
|
40
|
+
register_cop :DuplicateMethods, "#{__dir__}/lint/duplicate_methods"
|
|
41
|
+
register_cop :DuplicateRegexpCharacterClassElement, "#{__dir__}/lint/duplicate_regexp_character_class_element"
|
|
42
|
+
register_cop :DuplicateRequire, "#{__dir__}/lint/duplicate_require"
|
|
43
|
+
register_cop :DuplicateRescueException, "#{__dir__}/lint/duplicate_rescue_exception"
|
|
44
|
+
register_cop :DuplicateSetElement, "#{__dir__}/lint/duplicate_set_element"
|
|
45
|
+
register_cop :EachWithObjectArgument, "#{__dir__}/lint/each_with_object_argument"
|
|
46
|
+
register_cop :ElseLayout, "#{__dir__}/lint/else_layout"
|
|
47
|
+
register_cop :EmptyBlock, "#{__dir__}/lint/empty_block"
|
|
48
|
+
register_cop :EmptyClass, "#{__dir__}/lint/empty_class"
|
|
49
|
+
register_cop :EmptyConditionalBody, "#{__dir__}/lint/empty_conditional_body"
|
|
50
|
+
register_cop :EmptyEnsure, "#{__dir__}/lint/empty_ensure"
|
|
51
|
+
register_cop :EmptyExpression, "#{__dir__}/lint/empty_expression"
|
|
52
|
+
register_cop :EmptyFile, "#{__dir__}/lint/empty_file"
|
|
53
|
+
register_cop :EmptyInPattern, "#{__dir__}/lint/empty_in_pattern"
|
|
54
|
+
register_cop :EmptyInterpolation, "#{__dir__}/lint/empty_interpolation"
|
|
55
|
+
register_cop :EmptyWhen, "#{__dir__}/lint/empty_when"
|
|
56
|
+
register_cop :EnsureReturn, "#{__dir__}/lint/ensure_return"
|
|
57
|
+
register_cop :SharedMutableDefault, "#{__dir__}/lint/shared_mutable_default"
|
|
58
|
+
register_cop :ErbNewArguments, "#{__dir__}/lint/erb_new_arguments"
|
|
59
|
+
register_cop :FlipFlop, "#{__dir__}/lint/flip_flop"
|
|
60
|
+
register_cop :FloatComparison, "#{__dir__}/lint/float_comparison"
|
|
61
|
+
register_cop :FloatOutOfRange, "#{__dir__}/lint/float_out_of_range"
|
|
62
|
+
register_cop :FormatParameterMismatch, "#{__dir__}/lint/format_parameter_mismatch"
|
|
63
|
+
register_cop :HashCompareByIdentity, "#{__dir__}/lint/hash_compare_by_identity"
|
|
64
|
+
register_cop :HashNewWithKeywordArgumentsAsDefault, "#{__dir__}/lint/hash_new_with_keyword_arguments_as_default"
|
|
65
|
+
register_cop :HeredocMethodCallPosition, "#{__dir__}/lint/heredoc_method_call_position"
|
|
66
|
+
register_cop :IdentityComparison, "#{__dir__}/lint/identity_comparison"
|
|
67
|
+
register_cop :ImplicitStringConcatenation, "#{__dir__}/lint/implicit_string_concatenation"
|
|
68
|
+
register_cop :IncompatibleIoSelectWithFiberScheduler, "#{__dir__}/lint/incompatible_io_select_with_fiber_scheduler"
|
|
69
|
+
register_cop :IneffectiveAccessModifier, "#{__dir__}/lint/ineffective_access_modifier"
|
|
70
|
+
register_cop :InheritException, "#{__dir__}/lint/inherit_exception"
|
|
71
|
+
register_cop :InterpolationCheck, "#{__dir__}/lint/interpolation_check"
|
|
72
|
+
register_cop :ItWithoutArgumentsInBlock, "#{__dir__}/lint/it_without_arguments_in_block"
|
|
73
|
+
register_cop :LambdaWithoutLiteralBlock, "#{__dir__}/lint/lambda_without_literal_block"
|
|
74
|
+
register_cop :LiteralAsCondition, "#{__dir__}/lint/literal_as_condition"
|
|
75
|
+
register_cop :LiteralAssignmentInCondition, "#{__dir__}/lint/literal_assignment_in_condition"
|
|
76
|
+
register_cop :LiteralInInterpolation, "#{__dir__}/lint/literal_in_interpolation"
|
|
77
|
+
register_cop :Loop, "#{__dir__}/lint/loop"
|
|
78
|
+
register_cop :MissingCopEnableDirective, "#{__dir__}/lint/missing_cop_enable_directive"
|
|
79
|
+
register_cop :MissingSuper, "#{__dir__}/lint/missing_super"
|
|
80
|
+
register_cop :MixedCaseRange, "#{__dir__}/lint/mixed_case_range"
|
|
81
|
+
register_cop :MixedRegexpCaptureTypes, "#{__dir__}/lint/mixed_regexp_capture_types"
|
|
82
|
+
register_cop :MultipleComparison, "#{__dir__}/lint/multiple_comparison"
|
|
83
|
+
register_cop :NameTypo, "#{__dir__}/lint/name_typo"
|
|
84
|
+
register_cop :NestedMethodDefinition, "#{__dir__}/lint/nested_method_definition"
|
|
85
|
+
register_cop :NestedPercentLiteral, "#{__dir__}/lint/nested_percent_literal"
|
|
86
|
+
register_cop :NextWithoutAccumulator, "#{__dir__}/lint/next_without_accumulator"
|
|
87
|
+
register_cop :NoReturnInBeginEndBlocks, "#{__dir__}/lint/no_return_in_begin_end_blocks"
|
|
88
|
+
register_cop :NonAtomicFileOperation, "#{__dir__}/lint/non_atomic_file_operation"
|
|
89
|
+
register_cop :NonDeterministicRequireOrder, "#{__dir__}/lint/non_deterministic_require_order"
|
|
90
|
+
register_cop :NonLocalExitFromIterator, "#{__dir__}/lint/non_local_exit_from_iterator"
|
|
91
|
+
register_cop :NumberConversion, "#{__dir__}/lint/number_conversion"
|
|
92
|
+
register_cop :NumberedParameterAssignment, "#{__dir__}/lint/numbered_parameter_assignment"
|
|
93
|
+
register_cop :NumericOperationWithConstantResult, "#{__dir__}/lint/numeric_operation_with_constant_result"
|
|
94
|
+
register_cop :OrAssignmentToConstant, "#{__dir__}/lint/or_assignment_to_constant"
|
|
95
|
+
register_cop :OrderedMagicComments, "#{__dir__}/lint/ordered_magic_comments"
|
|
96
|
+
register_cop :OutOfRangeRegexpRef, "#{__dir__}/lint/out_of_range_regexp_ref"
|
|
97
|
+
register_cop :ParenthesesAsGroupedExpression, "#{__dir__}/lint/parentheses_as_grouped_expression"
|
|
98
|
+
register_cop :PercentStringArray, "#{__dir__}/lint/percent_string_array"
|
|
99
|
+
register_cop :PercentSymbolArray, "#{__dir__}/lint/percent_symbol_array"
|
|
100
|
+
register_cop :RaiseException, "#{__dir__}/lint/raise_exception"
|
|
101
|
+
register_cop :RandOne, "#{__dir__}/lint/rand_one"
|
|
102
|
+
register_cop :RedundantCopDisableDirective, "#{__dir__}/lint/redundant_cop_disable_directive"
|
|
103
|
+
register_cop :RedundantCopEnableDirective, "#{__dir__}/lint/redundant_cop_enable_directive"
|
|
104
|
+
register_cop :RedundantDirGlobSort, "#{__dir__}/lint/redundant_dir_glob_sort"
|
|
105
|
+
register_cop :RedundantRegexpQuantifiers, "#{__dir__}/lint/redundant_regexp_quantifiers"
|
|
106
|
+
register_cop :RedundantRequireStatement, "#{__dir__}/lint/redundant_require_statement"
|
|
107
|
+
register_cop :RedundantSafeNavigation, "#{__dir__}/lint/redundant_safe_navigation"
|
|
108
|
+
register_cop :RedundantSplatExpansion, "#{__dir__}/lint/redundant_splat_expansion"
|
|
109
|
+
register_cop :RedundantStringCoercion, "#{__dir__}/lint/redundant_string_coercion"
|
|
110
|
+
register_cop :RedundantTypeConversion, "#{__dir__}/lint/redundant_type_conversion"
|
|
111
|
+
register_cop :RedundantWithIndex, "#{__dir__}/lint/redundant_with_index"
|
|
112
|
+
register_cop :RedundantWithObject, "#{__dir__}/lint/redundant_with_object"
|
|
113
|
+
register_cop :RefinementImportMethods, "#{__dir__}/lint/refinement_import_methods"
|
|
114
|
+
register_cop :RegexpAsCondition, "#{__dir__}/lint/regexp_as_condition"
|
|
115
|
+
register_cop :RequireParentheses, "#{__dir__}/lint/require_parentheses"
|
|
116
|
+
register_cop :RequireRangeParentheses, "#{__dir__}/lint/require_range_parentheses"
|
|
117
|
+
register_cop :RequireRelativeSelfPath, "#{__dir__}/lint/require_relative_self_path"
|
|
118
|
+
register_cop :RescueException, "#{__dir__}/lint/rescue_exception"
|
|
119
|
+
register_cop :RescueType, "#{__dir__}/lint/rescue_type"
|
|
120
|
+
register_cop :ReturnInVoidContext, "#{__dir__}/lint/return_in_void_context"
|
|
121
|
+
register_cop :SafeNavigationConsistency, "#{__dir__}/lint/safe_navigation_consistency"
|
|
122
|
+
register_cop :SafeNavigationChain, "#{__dir__}/lint/safe_navigation_chain"
|
|
123
|
+
register_cop :SafeNavigationWithEmpty, "#{__dir__}/lint/safe_navigation_with_empty"
|
|
124
|
+
register_cop :ScriptPermission, "#{__dir__}/lint/script_permission"
|
|
125
|
+
register_cop :SelfAssignment, "#{__dir__}/lint/self_assignment"
|
|
126
|
+
register_cop :SendWithMixinArgument, "#{__dir__}/lint/send_with_mixin_argument"
|
|
127
|
+
register_cop :ShadowedArgument, "#{__dir__}/lint/shadowed_argument"
|
|
128
|
+
register_cop :ShadowedException, "#{__dir__}/lint/shadowed_exception"
|
|
129
|
+
register_cop :ShadowingOuterLocalVariable, "#{__dir__}/lint/shadowing_outer_local_variable"
|
|
130
|
+
register_cop :StructNewOverride, "#{__dir__}/lint/struct_new_override"
|
|
131
|
+
register_cop :SuppressedException, "#{__dir__}/lint/suppressed_exception"
|
|
132
|
+
register_cop :SuppressedExceptionInNumberConversion, "#{__dir__}/lint/suppressed_exception_in_number_conversion"
|
|
133
|
+
register_cop :SymbolConversion, "#{__dir__}/lint/symbol_conversion"
|
|
134
|
+
register_cop :Syntax, "#{__dir__}/lint/syntax"
|
|
135
|
+
register_cop :ToEnumArguments, "#{__dir__}/lint/to_enum_arguments"
|
|
136
|
+
register_cop :ToJSON, "#{__dir__}/lint/to_json"
|
|
137
|
+
register_cop :TopLevelReturnWithArgument, "#{__dir__}/lint/top_level_return_with_argument"
|
|
138
|
+
register_cop :TrailingCommaInAttributeDeclaration, "#{__dir__}/lint/trailing_comma_in_attribute_declaration"
|
|
139
|
+
register_cop :TripleQuotes, "#{__dir__}/lint/triple_quotes"
|
|
140
|
+
register_cop :UnderscorePrefixedVariableName, "#{__dir__}/lint/underscore_prefixed_variable_name"
|
|
141
|
+
register_cop :UnescapedBracketInRegexp, "#{__dir__}/lint/unescaped_bracket_in_regexp"
|
|
142
|
+
register_cop :UnexpectedBlockArity, "#{__dir__}/lint/unexpected_block_arity"
|
|
143
|
+
register_cop :UnifiedInteger, "#{__dir__}/lint/unified_integer"
|
|
144
|
+
register_cop :UnmodifiedReduceAccumulator, "#{__dir__}/lint/unmodified_reduce_accumulator"
|
|
145
|
+
register_cop :UnreachableCode, "#{__dir__}/lint/unreachable_code"
|
|
146
|
+
register_cop :UnreachableLoop, "#{__dir__}/lint/unreachable_loop"
|
|
147
|
+
register_cop :UnreachablePatternBranch, "#{__dir__}/lint/unreachable_pattern_branch"
|
|
148
|
+
register_cop :UnusedBlockArgument, "#{__dir__}/lint/unused_block_argument"
|
|
149
|
+
register_cop :UnusedMethodArgument, "#{__dir__}/lint/unused_method_argument"
|
|
150
|
+
register_cop :UnusedPrivateMethod, "#{__dir__}/lint/unused_private_method"
|
|
151
|
+
register_cop :UriEscapeUnescape, "#{__dir__}/lint/uri_escape_unescape"
|
|
152
|
+
register_cop :UriRegexp, "#{__dir__}/lint/uri_regexp"
|
|
153
|
+
register_cop :UselessAccessModifier, "#{__dir__}/lint/useless_access_modifier"
|
|
154
|
+
register_cop :UselessAssignment, "#{__dir__}/lint/useless_assignment"
|
|
155
|
+
register_cop :UselessConstantScoping, "#{__dir__}/lint/useless_constant_scoping"
|
|
156
|
+
register_cop :UselessDefaultValueArgument, "#{__dir__}/lint/useless_default_value_argument"
|
|
157
|
+
register_cop :UselessDefined, "#{__dir__}/lint/useless_defined"
|
|
158
|
+
register_cop :UselessElseWithoutRescue, "#{__dir__}/lint/useless_else_without_rescue"
|
|
159
|
+
register_cop :UselessMethodDefinition, "#{__dir__}/lint/useless_method_definition"
|
|
160
|
+
register_cop :UselessNumericOperation, "#{__dir__}/lint/useless_numeric_operation"
|
|
161
|
+
register_cop :UselessOr, "#{__dir__}/lint/useless_or"
|
|
162
|
+
register_cop :UselessRescue, "#{__dir__}/lint/useless_rescue"
|
|
163
|
+
register_cop :UselessRuby2Keywords, "#{__dir__}/lint/useless_ruby2_keywords"
|
|
164
|
+
register_cop :UselessSetterCall, "#{__dir__}/lint/useless_setter_call"
|
|
165
|
+
register_cop :UselessTimes, "#{__dir__}/lint/useless_times"
|
|
166
|
+
register_cop :Void, "#{__dir__}/lint/void"
|
|
167
|
+
|
|
168
|
+
autoload :UnusedArgument, "#{__dir__}/mixin/unused_argument"
|
|
169
|
+
|
|
170
|
+
# Utility classes for `Lint` department cops.
|
|
171
|
+
module Utils
|
|
172
|
+
autoload :NilReceiverChecker, "#{__dir__}/lint/utils/nil_receiver_checker"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -58,7 +58,7 @@ module RuboCop
|
|
|
58
58
|
return unless node.method?(:define_method)
|
|
59
59
|
|
|
60
60
|
method_name = node.send_node.first_argument
|
|
61
|
-
return if method_name
|
|
61
|
+
return if method_name&.basic_literal? && allowed?(method_name.value)
|
|
62
62
|
|
|
63
63
|
check_code_length(node)
|
|
64
64
|
end
|
|
@@ -12,9 +12,15 @@ module RuboCop
|
|
|
12
12
|
# nodes count. In contrast to the CyclomaticComplexity cop, this cop
|
|
13
13
|
# considers `else` nodes as adding complexity.
|
|
14
14
|
#
|
|
15
|
+
# A `case`/`in` branch whose pattern is a simple literal (e.g. `in 1`, `in "red"`, `in 1..10`)
|
|
16
|
+
# or a constant/type (e.g. `in Integer`) and has no guard is just as easy to read as a `when`
|
|
17
|
+
# branch, so it is discounted the same way. Branches with structural patterns (e.g. array,
|
|
18
|
+
# hash, or find patterns), bindings, alternatives, or a guard add the full complexity of
|
|
19
|
+
# a decision point.
|
|
20
|
+
#
|
|
15
21
|
# @example
|
|
16
22
|
#
|
|
17
|
-
# def
|
|
23
|
+
# def example_1 # 1
|
|
18
24
|
# if cond # 1
|
|
19
25
|
# case var # 2 (0.8 + 4 * 0.2, rounded)
|
|
20
26
|
# when 1 then func_one
|
|
@@ -26,33 +32,58 @@ module RuboCop
|
|
|
26
32
|
# do_something until a && b # 2
|
|
27
33
|
# end # ===
|
|
28
34
|
# end # 7 complexity points
|
|
35
|
+
#
|
|
36
|
+
# def example_2 # 1
|
|
37
|
+
# case color # 1 (3 * 0.2, rounded)
|
|
38
|
+
# in "red" then func_red
|
|
39
|
+
# in "blue" then func_blue
|
|
40
|
+
# in "green" then func_green
|
|
41
|
+
# end # ===
|
|
42
|
+
# end # 2 complexity points
|
|
29
43
|
class PerceivedComplexity < CyclomaticComplexity
|
|
30
44
|
MSG = 'Perceived complexity for `%<method>s` is too high. [%<complexity>d/%<max>d]'
|
|
31
45
|
|
|
32
|
-
COUNTED_NODES = (
|
|
46
|
+
COUNTED_NODES = (
|
|
47
|
+
CyclomaticComplexity::COUNTED_NODES - %i[when in_pattern] + %i[case case_match]
|
|
48
|
+
).freeze
|
|
33
49
|
|
|
34
50
|
private
|
|
35
51
|
|
|
52
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
36
53
|
def complexity_score_for(node)
|
|
37
54
|
case node.type
|
|
38
55
|
when :case
|
|
39
|
-
# If cond is nil, that means each when has an expression that
|
|
40
|
-
#
|
|
41
|
-
# if/elsif/elsif... so the when nodes count.
|
|
56
|
+
# If cond is nil, that means each when has an expression that evaluates to true or
|
|
57
|
+
# false. It's just an alternative to if/elsif/elsif... so the when nodes count.
|
|
42
58
|
nb_branches = node.when_branches.length + (node.else_branch ? 1 : 0)
|
|
43
59
|
if node.condition.nil?
|
|
44
60
|
nb_branches
|
|
45
61
|
else
|
|
46
|
-
# Otherwise, the case node gets 0.8 complexity points and each
|
|
47
|
-
# when gets 0.2.
|
|
62
|
+
# Otherwise, the case node gets 0.8 complexity points and each when gets 0.2.
|
|
48
63
|
((nb_branches * 0.2) + 0.8).round
|
|
49
64
|
end
|
|
65
|
+
when :case_match
|
|
66
|
+
# Simple `in` branches are discounted like `when`, while structural patterns keep
|
|
67
|
+
# the full complexity of a decision point.
|
|
68
|
+
score = node.in_pattern_branches.sum { |branch| simple_in_pattern?(branch) ? 0.2 : 1 }
|
|
69
|
+
score += 0.2 if node.else_branch
|
|
70
|
+
score.round
|
|
50
71
|
when :if
|
|
51
72
|
node.else? && !node.elsif? ? 2 : 1
|
|
52
73
|
else
|
|
53
74
|
super
|
|
54
75
|
end
|
|
55
76
|
end
|
|
77
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
78
|
+
|
|
79
|
+
def simple_in_pattern?(in_pattern_node)
|
|
80
|
+
# `in_pattern_node.children[1]` is the guard (`if`/`unless`), or `nil`.
|
|
81
|
+
return false unless in_pattern_node.children[1].nil?
|
|
82
|
+
|
|
83
|
+
# A scalar literal, a literal range, or a constant/type is as easy to read as a `when`.
|
|
84
|
+
pattern = in_pattern_node.pattern
|
|
85
|
+
pattern.literal? || pattern.const_type?
|
|
86
|
+
end
|
|
56
87
|
end
|
|
57
88
|
end
|
|
58
89
|
end
|
|
@@ -189,7 +189,7 @@ module RuboCop
|
|
|
189
189
|
def source_from_node_with_heredoc(node)
|
|
190
190
|
last_line = -1
|
|
191
191
|
node.each_descendant do |descendant|
|
|
192
|
-
next
|
|
192
|
+
next if descendant.loc.nil? || descendant.source_range.nil?
|
|
193
193
|
|
|
194
194
|
descendant_last_line =
|
|
195
195
|
if heredoc_node?(descendant)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Cops for the `Metrics` department. The department's cops are registered for lazy loading
|
|
6
|
+
# and their files are loaded on demand.
|
|
7
|
+
module Metrics
|
|
8
|
+
extend LazyLoader
|
|
9
|
+
|
|
10
|
+
register_cop :CyclomaticComplexity, "#{__dir__}/metrics/cyclomatic_complexity"
|
|
11
|
+
register_cop :AbcSize, "#{__dir__}/metrics/abc_size"
|
|
12
|
+
register_cop :BlockLength, "#{__dir__}/metrics/block_length"
|
|
13
|
+
register_cop :BlockNesting, "#{__dir__}/metrics/block_nesting"
|
|
14
|
+
register_cop :ClassLength, "#{__dir__}/metrics/class_length"
|
|
15
|
+
register_cop :CollectionLiteralLength, "#{__dir__}/metrics/collection_literal_length"
|
|
16
|
+
register_cop :MethodLength, "#{__dir__}/metrics/method_length"
|
|
17
|
+
register_cop :ModuleLength, "#{__dir__}/metrics/module_length"
|
|
18
|
+
register_cop :ParameterLists, "#{__dir__}/metrics/parameter_lists"
|
|
19
|
+
register_cop :PerceivedComplexity, "#{__dir__}/metrics/perceived_complexity"
|
|
20
|
+
|
|
21
|
+
# Utility classes for `Metrics` department cops.
|
|
22
|
+
module Utils
|
|
23
|
+
autoload :AbcSizeCalculator, "#{__dir__}/metrics/utils/abc_size_calculator"
|
|
24
|
+
autoload :CodeLengthCalculator, "#{__dir__}/metrics/utils/code_length_calculator"
|
|
25
|
+
autoload :IteratingBlock, "#{__dir__}/metrics/utils/iterating_block"
|
|
26
|
+
autoload :RepeatedAttributeDiscount, "#{__dir__}/metrics/utils/repeated_attribute_discount"
|
|
27
|
+
autoload :RepeatedCsendDiscount, "#{__dir__}/metrics/utils/repeated_csend_discount"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Cops for the `Migration` department. The department's cops are registered for lazy loading
|
|
6
|
+
# and their files are loaded on demand.
|
|
7
|
+
module Migration
|
|
8
|
+
extend LazyLoader
|
|
9
|
+
|
|
10
|
+
register_cop :DepartmentName, "#{__dir__}/migration/department_name"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -25,11 +25,11 @@ module RuboCop
|
|
|
25
25
|
|
|
26
26
|
# @api public
|
|
27
27
|
def allowed_methods
|
|
28
|
-
if cop_config_deprecated_values.any?(Regexp)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
@allowed_methods ||= if cop_config_deprecated_values.any?(Regexp)
|
|
29
|
+
cop_config_allowed_methods
|
|
30
|
+
else
|
|
31
|
+
cop_config_allowed_methods + cop_config_deprecated_values
|
|
32
|
+
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def cop_config_allowed_methods
|
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def matches_allowed_pattern?(line)
|
|
30
|
-
|
|
30
|
+
allowed_pattern_regexps.any? { |pattern| pattern.match?(line) }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @deprecated Use matches_allowed_pattern? instead
|
|
@@ -49,6 +49,10 @@ module RuboCop
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def allowed_pattern_regexps
|
|
53
|
+
@allowed_pattern_regexps ||= allowed_patterns.map { |pattern| Regexp.new(pattern) }
|
|
54
|
+
end
|
|
55
|
+
|
|
52
56
|
def cop_config_patterns_values
|
|
53
57
|
@cop_config_patterns_values ||=
|
|
54
58
|
Array(cop_config.fetch('AllowedPatterns', [])) +
|
|
@@ -61,11 +61,13 @@ module RuboCop
|
|
|
61
61
|
# @api private
|
|
62
62
|
def extract_breakable_node_from_elements(node, elements, max)
|
|
63
63
|
return unless breakable_collection?(node, elements)
|
|
64
|
-
return if safe_to_ignore?(node)
|
|
65
64
|
|
|
65
|
+
# Check the cheap conditions first, `safe_to_ignore?` may traverse all elements of
|
|
66
|
+
# a containing collection.
|
|
66
67
|
line = processed_source.lines[node.first_line - 1]
|
|
68
|
+
return if max && line.length <= max
|
|
67
69
|
return if processed_source.line_with_comment?(node.loc.line)
|
|
68
|
-
return if
|
|
70
|
+
return if safe_to_ignore?(node)
|
|
69
71
|
|
|
70
72
|
extract_first_element_over_column_limit(node, elements, max)
|
|
71
73
|
end
|
|
@@ -173,20 +175,36 @@ module RuboCop
|
|
|
173
175
|
node.each_ancestor.find do |ancestor|
|
|
174
176
|
if ancestor.type?(:hash, :array) &&
|
|
175
177
|
breakable_collection?(ancestor, ancestor.children)
|
|
176
|
-
return children_could_be_broken_up?(ancestor.children)
|
|
178
|
+
return children_could_be_broken_up?(ancestor, ancestor.children)
|
|
177
179
|
end
|
|
178
180
|
|
|
179
181
|
next unless ancestor.call_type?
|
|
180
182
|
|
|
181
183
|
args = process_args(ancestor.arguments)
|
|
182
|
-
|
|
184
|
+
if breakable_collection?(ancestor, args)
|
|
185
|
+
return children_could_be_broken_up?(ancestor, args)
|
|
186
|
+
end
|
|
183
187
|
end
|
|
184
188
|
|
|
185
189
|
false
|
|
186
190
|
end
|
|
187
191
|
|
|
188
192
|
# @api private
|
|
189
|
-
|
|
193
|
+
# The result depends only on the given node, but the check may traverse all children of
|
|
194
|
+
# a large collection and is repeated for each contained element, so memoize it per node.
|
|
195
|
+
def children_could_be_broken_up?(node, children)
|
|
196
|
+
if @check_line_breakable_processed_source != processed_source
|
|
197
|
+
@check_line_breakable_processed_source = processed_source
|
|
198
|
+
@children_could_be_broken_up_cache = {}.compare_by_identity
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
@children_could_be_broken_up_cache.fetch(node) do
|
|
202
|
+
@children_could_be_broken_up_cache[node] = compute_children_could_be_broken_up?(children)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# @api private
|
|
207
|
+
def compute_children_could_be_broken_up?(children)
|
|
190
208
|
return false if all_on_same_line?(children)
|
|
191
209
|
|
|
192
210
|
last_seen_line = -1
|
|
@@ -5,20 +5,28 @@ module RuboCop
|
|
|
5
5
|
# Common functionality for rewriting endless methods to normal method definitions
|
|
6
6
|
module EndlessMethodRewriter
|
|
7
7
|
def correct_to_multiline(corrector, node)
|
|
8
|
-
replacement =
|
|
9
|
-
def #{node.method_name}#{arguments(node)}
|
|
10
|
-
|
|
11
|
-
end
|
|
12
|
-
|
|
8
|
+
replacement = [
|
|
9
|
+
"def #{receiver(node)}#{node.method_name}#{arguments(node)}",
|
|
10
|
+
"#{indent(node, offset: configured_indentation_width)}#{node.body.source}",
|
|
11
|
+
"#{indent(node)}end"
|
|
12
|
+
].join("\n")
|
|
13
13
|
|
|
14
14
|
corrector.replace(node, replacement)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
|
+
def receiver(node)
|
|
20
|
+
node.receiver ? "#{node.receiver.source}#{node.loc.operator.source}" : ''
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
def arguments(node, missing = '')
|
|
20
24
|
node.arguments.any? ? node.arguments.source : missing
|
|
21
25
|
end
|
|
26
|
+
|
|
27
|
+
def configured_indentation_width
|
|
28
|
+
cop_config['IndentationWidth'] || config.for_cop('Layout/IndentationWidth')['Width'] || 2
|
|
29
|
+
end
|
|
22
30
|
end
|
|
23
31
|
end
|
|
24
32
|
end
|
|
@@ -5,12 +5,16 @@ module RuboCop
|
|
|
5
5
|
# This module encapsulates the ability to forbid certain patterns in a cop.
|
|
6
6
|
module ForbiddenPattern
|
|
7
7
|
def forbidden_pattern?(name)
|
|
8
|
-
|
|
8
|
+
forbidden_pattern_regexps.any? { |pattern| pattern.match?(name) }
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def forbidden_patterns
|
|
12
12
|
cop_config.fetch('ForbiddenPatterns', [])
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
def forbidden_pattern_regexps
|
|
16
|
+
@forbidden_pattern_regexps ||= forbidden_patterns.map { |pattern| Regexp.new(pattern) }
|
|
17
|
+
end
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
end
|
|
@@ -96,20 +96,37 @@ module RuboCop
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def hash_rocket_delta(first_pair, current_pair)
|
|
99
|
-
first_pair.loc.column
|
|
100
|
-
current_pair.loc.operator.column
|
|
99
|
+
target_operator_column(first_pair) - current_pair.loc.operator.column
|
|
101
100
|
end
|
|
102
101
|
|
|
103
102
|
def value_delta(first_pair, current_pair)
|
|
104
|
-
correct_value_column = first_pair
|
|
105
|
-
|
|
106
|
-
max_delimiter_width(first_pair.parent)
|
|
103
|
+
correct_value_column = target_operator_column(first_pair) +
|
|
104
|
+
max_delimiter_width(first_pair.parent) - 1
|
|
107
105
|
|
|
108
106
|
current_pair.value_omission? ? 0 : correct_value_column - current_pair.value.loc.column
|
|
109
107
|
end
|
|
110
108
|
|
|
109
|
+
# The column the separator should land on: the shared key margin
|
|
110
|
+
# plus the widest single-line key, or, if larger, a multiline key's
|
|
111
|
+
# own last-line end column. The latter can't be measured from a
|
|
112
|
+
# multiline key's (newline-including) source length, so it's a
|
|
113
|
+
# separate candidate rather than folded into `max_key_width`.
|
|
114
|
+
def target_operator_column(first_pair)
|
|
115
|
+
hash_node = first_pair.parent
|
|
116
|
+
candidates = multiline_key_end_columns(hash_node)
|
|
117
|
+
|
|
118
|
+
key_width = max_key_width(hash_node)
|
|
119
|
+
candidates << (first_pair.loc.column + key_width + 1) if key_width.positive?
|
|
120
|
+
|
|
121
|
+
candidates.max
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def multiline_key_end_columns(hash_node)
|
|
125
|
+
hash_node.keys.reject(&:single_line?).map { |key| key.source_range.end.column + 1 }
|
|
126
|
+
end
|
|
127
|
+
|
|
111
128
|
def max_key_width(hash_node)
|
|
112
|
-
hash_node.keys.map { |key| key.source.length }.max
|
|
129
|
+
hash_node.keys.select(&:single_line?).map { |key| key.source.length }.max || 0
|
|
113
130
|
end
|
|
114
131
|
|
|
115
132
|
def max_delimiter_width(hash_node)
|
|
@@ -182,10 +182,18 @@ module RuboCop
|
|
|
182
182
|
return ":\"#{value.source}\"" if value.dsym_type?
|
|
183
183
|
return "\"#{value.source}\"" if value.dstr_type?
|
|
184
184
|
return ":#{value.source}" if value.sym_type?
|
|
185
|
+
# The element of a `%w` array can contain characters that are special
|
|
186
|
+
# inside a single-quoted string (e.g. a `'`), so escape them rather than
|
|
187
|
+
# wrapping the raw source.
|
|
188
|
+
return to_single_quoted(value.value) if value.str_type?
|
|
185
189
|
|
|
186
190
|
"'#{value.source}'"
|
|
187
191
|
end
|
|
188
192
|
|
|
193
|
+
def to_single_quoted(string)
|
|
194
|
+
"'#{string.gsub(/['\\]/) { |character| "\\#{character}" }}'"
|
|
195
|
+
end
|
|
196
|
+
|
|
189
197
|
def except_key(node)
|
|
190
198
|
key_arg = node.argument_list.first.source
|
|
191
199
|
body, = extract_body_if_negated(node.body)
|
|
@@ -94,6 +94,10 @@ module RuboCop
|
|
|
94
94
|
|
|
95
95
|
return unless captures.use_transformed_argname?
|
|
96
96
|
|
|
97
|
+
# A splat transforming expression (e.g. `[k, *v]`) can't be used as a
|
|
98
|
+
# standalone block return value, so the rewrite would produce invalid Ruby.
|
|
99
|
+
return if captures.transforming_body_expr.splat_type?
|
|
100
|
+
|
|
97
101
|
message = "Prefer `#{new_method_name}` over `#{match_desc}`."
|
|
98
102
|
add_offense(node, message: message) do |corrector|
|
|
99
103
|
correction = prepare_correction(node)
|