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.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -16
  3. data/config/default.yml +276 -82
  4. data/config/obsoletion.yml +196 -0
  5. data/exe/rubocop +1 -1
  6. data/lib/rubocop.rb +31 -2
  7. data/lib/rubocop/cli.rb +5 -1
  8. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  9. data/lib/rubocop/cli/command/execute_runner.rb +26 -11
  10. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  11. data/lib/rubocop/cli/command/version.rb +1 -1
  12. data/lib/rubocop/comment_config.rb +1 -1
  13. data/lib/rubocop/config.rb +4 -0
  14. data/lib/rubocop/config_loader.rb +34 -8
  15. data/lib/rubocop/config_loader_resolver.rb +12 -6
  16. data/lib/rubocop/config_obsoletion.rb +65 -247
  17. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  18. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  19. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  21. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  22. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  23. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  24. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  25. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  26. data/lib/rubocop/config_regeneration.rb +1 -1
  27. data/lib/rubocop/config_validator.rb +25 -10
  28. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  29. data/lib/rubocop/cop/badge.rb +9 -24
  30. data/lib/rubocop/cop/base.rb +33 -16
  31. data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
  32. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  33. data/lib/rubocop/cop/commissioner.rb +37 -23
  34. data/lib/rubocop/cop/cop.rb +2 -2
  35. data/lib/rubocop/cop/corrector.rb +3 -1
  36. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  37. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  38. data/lib/rubocop/cop/force.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
  40. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
  41. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  42. data/lib/rubocop/cop/generator.rb +3 -10
  43. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  44. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
  45. data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
  46. data/lib/rubocop/cop/layout/class_structure.rb +22 -3
  47. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  49. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +80 -10
  50. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  51. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  52. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  53. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  54. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  55. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  56. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  59. data/lib/rubocop/cop/layout/line_length.rb +10 -13
  60. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  62. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  64. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  65. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  66. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
  67. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +26 -2
  68. data/lib/rubocop/cop/lint/debugger.rb +17 -28
  69. data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
  70. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
  71. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  72. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  73. data/lib/rubocop/cop/lint/empty_block.rb +82 -0
  74. data/lib/rubocop/cop/lint/empty_class.rb +93 -0
  75. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  76. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  77. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +39 -7
  78. data/lib/rubocop/cop/lint/loop.rb +4 -4
  79. data/lib/rubocop/cop/lint/missing_super.rb +7 -4
  80. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  81. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  82. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  83. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  84. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
  85. data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
  86. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  87. data/lib/rubocop/cop/lint/to_enum_arguments.rb +86 -0
  88. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  89. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  90. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +199 -0
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  92. data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
  93. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  94. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  95. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  96. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  97. data/lib/rubocop/cop/metrics/parameter_lists.rb +68 -2
  98. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  99. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  100. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  101. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  102. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  103. data/lib/rubocop/cop/mixin/configurable_numbering.rb +4 -3
  104. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  105. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  106. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  107. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  108. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
  110. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  111. data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
  112. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  113. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  114. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  116. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  117. data/lib/rubocop/cop/naming/variable_number.rb +100 -8
  118. data/lib/rubocop/cop/offense.rb +3 -3
  119. data/lib/rubocop/cop/security/open.rb +12 -10
  120. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  121. data/lib/rubocop/cop/style/and_or.rb +11 -3
  122. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  123. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  124. data/lib/rubocop/cop/style/case_like_if.rb +0 -4
  125. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  126. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  127. data/lib/rubocop/cop/style/collection_compact.rb +91 -0
  128. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +169 -0
  129. data/lib/rubocop/cop/style/documentation.rb +12 -1
  130. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  131. data/lib/rubocop/cop/style/float_division.rb +44 -1
  132. data/lib/rubocop/cop/style/format_string.rb +8 -3
  133. data/lib/rubocop/cop/style/format_string_token.rb +47 -2
  134. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  135. data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
  136. data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
  137. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -3
  138. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  139. data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
  140. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  141. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  142. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  143. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +8 -13
  144. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  145. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  146. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  147. data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
  148. data/lib/rubocop/cop/style/negated_if_else_condition.rb +106 -0
  149. data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
  150. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  151. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  152. data/lib/rubocop/cop/style/raise_args.rb +21 -6
  153. data/lib/rubocop/cop/style/redundant_argument.rb +88 -0
  154. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  155. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  156. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
  157. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  158. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  159. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  160. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  161. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  162. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  163. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  164. data/lib/rubocop/cop/style/static_class.rb +97 -0
  165. data/lib/rubocop/cop/style/string_concatenation.rb +39 -2
  166. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  167. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  168. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  169. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  170. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  171. data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
  172. data/lib/rubocop/cop/team.rb +6 -1
  173. data/lib/rubocop/cop/util.rb +6 -2
  174. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  175. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  176. data/lib/rubocop/core_ext/hash.rb +20 -0
  177. data/lib/rubocop/ext/regexp_node.rb +36 -11
  178. data/lib/rubocop/ext/regexp_parser.rb +95 -0
  179. data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
  180. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  181. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  182. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  183. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  184. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  185. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  186. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  187. data/lib/rubocop/lockfile.rb +40 -0
  188. data/lib/rubocop/magic_comment.rb +2 -2
  189. data/lib/rubocop/options.rb +11 -1
  190. data/lib/rubocop/rake_task.rb +2 -2
  191. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  192. data/lib/rubocop/runner.rb +1 -1
  193. data/lib/rubocop/target_finder.rb +1 -1
  194. data/lib/rubocop/target_ruby.rb +65 -1
  195. data/lib/rubocop/version.rb +56 -6
  196. metadata +50 -9
  197. data/bin/console +0 -10
  198. data/bin/rubocop-profile +0 -32
  199. data/bin/setup +0 -7
@@ -6,7 +6,12 @@ module RuboCop
6
6
  module Utils
7
7
  # @api private
8
8
  #
9
- # Helps to calculate code length for the provided node.
9
+ # Identifies repetitions `&.` on the same variable:
10
+ #
11
+ # my_var&.foo
12
+ # my_var&.bar # => repeated
13
+ # my_var = baz # => reset
14
+ # my_var&.qux # => not repeated
10
15
  module RepeatedCsendDiscount
11
16
  def reset_repeated_csend
12
17
  @repeated_csend = {}
@@ -71,7 +71,7 @@ module RuboCop
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
74
- legacy_cop_names = RuboCop::ConfigObsoletion::OBSOLETE_COPS.keys
74
+ legacy_cop_names = RuboCop::ConfigObsoletion.legacy_cop_names
75
75
 
76
76
  legacy_cop_names.detect do |legacy_cop_name|
77
77
  legacy_cop_name.split('/')[1] == cop_name
@@ -103,7 +103,7 @@ module RuboCop
103
103
  # hashes wrapped in a set of curly braces like {foo: 1}.
104
104
  # That is, not a kwargs hash. For method calls, this ensures
105
105
  # the method call is made with parens.
106
- starts_with_bracket = node.loc.begin
106
+ starts_with_bracket = !node.hash_type? || node.loc.begin
107
107
 
108
108
  # If the call has a second argument, we can insert a line
109
109
  # break before the second argument and the rest of the
@@ -7,10 +7,11 @@ module RuboCop
7
7
  module ConfigurableNumbering
8
8
  include ConfigurableFormatting
9
9
 
10
+ implicit_param = /\A_\d+\z/
10
11
  FORMATS = {
11
- snake_case: /(?:[[[:lower:]]_]|_\d+)$/,
12
- normalcase: /(?:_\D*|[[[:upper:]][[:lower:]]]\d*)$/,
13
- non_integer: /[[[:upper:]][[:lower:]]_]$/
12
+ snake_case: /(?:\D|_\d+|\A\d+)\z/,
13
+ normalcase: /(?:\D|[^_\d]\d+|\A\d+)\z|#{implicit_param}/,
14
+ non_integer: /(\D|\A\d+)\z|#{implicit_param}/
14
15
  }.freeze
15
16
  end
16
17
  end
@@ -2,7 +2,15 @@
2
2
 
3
3
  module RuboCop
4
4
  module Cop
5
- # Common functionality for enforcing a specific superclass
5
+ # Common functionality for enforcing a specific superclass.
6
+ #
7
+ # IMPORTANT: RuboCop core depended on this module when it supported Rails department.
8
+ # Rails department has been extracted to RuboCop Rails gem.
9
+ # This module is deprecated and will be removed by RuboCop 2.0.
10
+ # It will not be updated to `RuboCop::Cop::Base` v1 API to maintain compatibility
11
+ # with existing RuboCop Rails 2.8 or lower.
12
+ #
13
+ # @api private
6
14
  module EnforceSuperclass
7
15
  def self.included(base)
8
16
  base.def_node_matcher :class_definition, <<~PATTERN
@@ -4,15 +4,48 @@ module RuboCop
4
4
  module Cop
5
5
  # This module encapsulates the ability to ignore certain methods when
6
6
  # parsing.
7
+ # Cops that use `IgnoredMethods` can accept either strings or regexes to match
8
+ # against.
7
9
  module IgnoredMethods
8
- private
10
+ # Configuration for IgnoredMethods. It is added to classes that include
11
+ # the module so that configuration can be set using the `ignored_methods`
12
+ # class macro.
13
+ module Config
14
+ attr_accessor :deprecated_key
15
+
16
+ def ignored_methods(**config)
17
+ self.deprecated_key = config[:deprecated_key]
18
+ end
19
+ end
20
+
21
+ def self.included(base)
22
+ base.extend(Config)
23
+ end
9
24
 
10
25
  def ignored_method?(name)
11
- ignored_methods.include?(name.to_s)
26
+ ignored_methods.any? do |value|
27
+ case value
28
+ when Regexp
29
+ value.match? String(name)
30
+ else
31
+ value == String(name)
32
+ end
33
+ end
12
34
  end
13
35
 
14
36
  def ignored_methods
15
- cop_config.fetch('IgnoredMethods', [])
37
+ keys = %w[IgnoredMethods]
38
+ keys << deprecated_key if deprecated_key
39
+
40
+ cop_config.slice(*keys).values.reduce(&:concat)
41
+ end
42
+
43
+ private
44
+
45
+ def deprecated_key
46
+ return unless self.class.respond_to?(:deprecated_key)
47
+
48
+ self.class.deprecated_key&.to_s
16
49
  end
17
50
  end
18
51
  end
@@ -57,7 +57,7 @@ module RuboCop
57
57
  def indentation_difference(line)
58
58
  return 0 unless tab_indentation_width
59
59
 
60
- line.match(/^\t*/)[0].size * (tab_indentation_width - 1)
60
+ (line.index(/[^\t]/) || 0) * (tab_indentation_width - 1)
61
61
  end
62
62
 
63
63
  def tab_indentation_width
@@ -11,6 +11,12 @@ module RuboCop
11
11
  include Metrics::Utils::RepeatedCsendDiscount
12
12
  extend NodePattern::Macros
13
13
 
14
+ # Ensure cops that include `MethodComplexity` have the config
15
+ # `attr_accessor`s that `ignored_method?` needs.
16
+ def self.included(base)
17
+ base.extend(IgnoredMethods::Config)
18
+ end
19
+
14
20
  def on_def(node)
15
21
  return if ignored_method?(node.method_name)
16
22
 
@@ -31,7 +31,7 @@ module RuboCop
31
31
  # b c { block }. <-- b is indented relative to a
32
32
  # d <-- d is indented relative to a
33
33
  def left_hand_side(lhs)
34
- lhs = lhs.parent while lhs.parent&.send_type?
34
+ lhs = lhs.parent while lhs.parent&.send_type? && lhs.parent.loc.dot
35
35
  lhs
36
36
  end
37
37
 
@@ -19,7 +19,8 @@ module RuboCop
19
19
  def non_eligible_node?(node)
20
20
  node.modifier_form? ||
21
21
  node.nonempty_line_count > 3 ||
22
- processed_source.line_with_comment?(node.loc.last_line)
22
+ processed_source.line_with_comment?(node.loc.last_line) ||
23
+ (first_line_comment(node) && code_after(node))
23
24
  end
24
25
 
25
26
  def non_eligible_body?(body)
@@ -41,11 +42,9 @@ module RuboCop
41
42
 
42
43
  def length_in_modifier_form(node)
43
44
  keyword_element = node.loc.keyword
44
- end_element = node.loc.end
45
45
  code_before = keyword_element.source_line[0...keyword_element.column]
46
- code_after = end_element.source_line[end_element.last_column..-1]
47
46
  expression = to_modifier_form(node)
48
- line_length("#{code_before}#{expression}#{code_after}")
47
+ line_length("#{code_before}#{expression}#{code_after(node)}")
49
48
  end
50
49
 
51
50
  def to_modifier_form(node)
@@ -64,6 +63,12 @@ module RuboCop
64
63
  comment_source unless comment_disables_cop?(comment_source)
65
64
  end
66
65
 
66
+ def code_after(node)
67
+ end_element = node.loc.end
68
+ code = end_element.source_line[end_element.last_column..-1]
69
+ code unless code.empty?
70
+ end
71
+
67
72
  def parenthesize?(node)
68
73
  # Parenthesize corrected expression if changing to modifier-if form
69
74
  # would change the meaning of the parent expression
@@ -14,7 +14,10 @@ module RuboCop
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
17
- add_offense(node) { opposite_style_detected }
17
+ add_offense(node) do |corrector|
18
+ opposite_style_detected
19
+ autocorrect(corrector, node) if respond_to?(:autocorrect, true)
20
+ end
18
21
  else
19
22
  correct_style_detected
20
23
  end
@@ -16,9 +16,7 @@ module RuboCop
16
16
  end
17
17
 
18
18
  def find_visibility_start(node)
19
- node.left_siblings
20
- .reverse
21
- .find(&method(:visibility_block?))
19
+ node.left_siblings.reverse.find { |sibling| visibility_block?(sibling) }
22
20
  end
23
21
 
24
22
  # Navigate to find the last protected method
@@ -3,7 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cop makes sure that accessor methods are named properly.
6
+ # This cop makes sure that accessor methods are named properly. Applies
7
+ # to both instance and class methods.
8
+ #
9
+ # NOTE: Offenses are only registered for methods with the expected
10
+ # arity. Getters (`get_attribute`) must have no arguments to be
11
+ # registered, and setters (`set_attribute(value)`) must have exactly
12
+ # one.
7
13
  #
8
14
  # @example
9
15
  # # bad
@@ -21,6 +27,14 @@ module RuboCop
21
27
  # # good
22
28
  # def attribute
23
29
  # end
30
+ #
31
+ # # accepted, incorrect arity for getter
32
+ # def get_value(attr)
33
+ # end
34
+ #
35
+ # # accepted, incorrect arity for setter
36
+ # def set_value
37
+ # end
24
38
  class AccessorMethodName < Base
25
39
  MSG_READER = 'Do not prefix reader method names with `get_`.'
26
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
@@ -14,11 +14,13 @@ module RuboCop
14
14
  # # good
15
15
  # def +(other); end
16
16
  class BinaryOperatorParameterName < Base
17
+ extend AutoCorrector
18
+
17
19
  MSG = 'When defining the `%<opr>s` operator, ' \
18
20
  'name its argument `other`.'
19
21
 
20
22
  OP_LIKE_METHODS = %i[eql? equal?].freeze
21
- EXCLUDED = %i[+@ -@ [] []= << === `].freeze
23
+ EXCLUDED = %i[+@ -@ [] []= << === ` =~].freeze
22
24
 
23
25
  def_node_matcher :op_method_candidate?, <<~PATTERN
24
26
  (def [#op_method? $_] (args $(arg [!:other !:_other])) _)
@@ -26,7 +28,15 @@ module RuboCop
26
28
 
27
29
  def on_def(node)
28
30
  op_method_candidate?(node) do |name, arg|
29
- add_offense(arg, message: format(MSG, opr: name))
31
+ add_offense(arg, message: format(MSG, opr: name)) do |corrector|
32
+ corrector.replace(arg, 'other')
33
+ node.each_descendant(:lvar, :lvasgn) do |lvar|
34
+ lvar_location = lvar.loc.name
35
+ next unless lvar_location.source == arg.source
36
+
37
+ corrector.replace(lvar_location, 'other')
38
+ end
39
+ end
30
40
  end
31
41
  end
32
42
 
@@ -30,13 +30,19 @@ module RuboCop
30
30
  class HeredocDelimiterCase < Base
31
31
  include Heredoc
32
32
  include ConfigurableEnforcedStyle
33
+ extend AutoCorrector
33
34
 
34
35
  MSG = 'Use %<style>s heredoc delimiters.'
35
36
 
36
37
  def on_heredoc(node)
37
38
  return if correct_case_delimiters?(node)
38
39
 
39
- add_offense(node.loc.heredoc_end)
40
+ add_offense(node.loc.heredoc_end) do |corrector|
41
+ expr = node.loc.expression
42
+
43
+ corrector.replace(expr, correct_delimiters(expr.source))
44
+ corrector.replace(node.loc.heredoc_end, correct_delimiters(delimiter_string(expr)))
45
+ end
40
46
  end
41
47
 
42
48
  private
@@ -46,14 +52,14 @@ module RuboCop
46
52
  end
47
53
 
48
54
  def correct_case_delimiters?(node)
49
- delimiter_string(node) == correct_delimiters(node)
55
+ delimiter_string(node) == correct_delimiters(delimiter_string(node))
50
56
  end
51
57
 
52
- def correct_delimiters(node)
58
+ def correct_delimiters(source)
53
59
  if style == :uppercase
54
- delimiter_string(node).upcase
60
+ source.upcase
55
61
  else
56
- delimiter_string(node).downcase
62
+ source.downcase
57
63
  end
58
64
  end
59
65
  end
@@ -20,6 +20,11 @@ module RuboCop
20
20
  # @something ||= calculate_expensive_thing
21
21
  # end
22
22
  #
23
+ # def foo
24
+ # return @something if defined?(@something)
25
+ # @something = calculate_expensive_thing
26
+ # end
27
+ #
23
28
  # # good
24
29
  # def _foo
25
30
  # @foo ||= calculate_expensive_thing
@@ -54,6 +59,11 @@ module RuboCop
54
59
  # @foo ||= calculate_expensive_thing
55
60
  # end
56
61
  #
62
+ # def foo
63
+ # return @foo if defined?(@foo)
64
+ # @foo = calculate_expensive_thing
65
+ # end
66
+ #
57
67
  # # good
58
68
  # def foo
59
69
  # @_foo ||= calculate_expensive_thing
@@ -64,6 +74,11 @@ module RuboCop
64
74
  # @_foo ||= calculate_expensive_thing
65
75
  # end
66
76
  #
77
+ # def foo
78
+ # return @_foo if defined?(@_foo)
79
+ # @_foo = calculate_expensive_thing
80
+ # end
81
+ #
67
82
  # @example EnforcedStyleForLeadingUnderscores :optional
68
83
  # # bad
69
84
  # def foo
@@ -84,6 +99,12 @@ module RuboCop
84
99
  # def _foo
85
100
  # @_foo ||= calculate_expensive_thing
86
101
  # end
102
+ #
103
+ # # good
104
+ # def foo
105
+ # return @_foo if defined?(@_foo)
106
+ # @_foo = calculate_expensive_thing
107
+ # end
87
108
  class MemoizedInstanceVariableName < Base
88
109
  include ConfigurableEnforcedStyle
89
110
 
@@ -92,32 +113,60 @@ module RuboCop
92
113
  UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
93
114
  'with `_`. Use `@%<suggested_var>s` instead.'
94
115
 
95
- def self.node_pattern
96
- memo_assign = '(or_asgn $(ivasgn _) _)'
97
- memoized_at_end_of_method = "(begin ... #{memo_assign})"
98
- instance_method =
99
- "(def $_ _ {#{memo_assign} #{memoized_at_end_of_method}})"
100
- class_method =
101
- "(defs self $_ _ {#{memo_assign} #{memoized_at_end_of_method}})"
102
- "{#{instance_method} #{class_method}}"
103
- end
116
+ # rubocop:disable Metrics/AbcSize
117
+ def on_or_asgn(node)
118
+ lhs, _value = *node
119
+ return unless lhs.ivasgn_type?
120
+ return unless (method_node = node.each_ancestor(:def, :defs).first)
104
121
 
105
- private_class_method :node_pattern
106
- def_node_matcher :memoized?, node_pattern
122
+ body = method_node.body
123
+ return unless body == node || body.children.last == node
107
124
 
108
- def on_def(node)
109
- (method_name, ivar_assign) = memoized?(node)
110
- return if matches?(method_name, ivar_assign)
125
+ method_name = method_node.method_name
126
+ return if matches?(method_name, lhs)
111
127
 
112
128
  msg = format(
113
- message(ivar_assign.children.first.to_s),
114
- var: ivar_assign.children.first.to_s,
129
+ message(lhs.children.first.to_s),
130
+ var: lhs.children.first.to_s,
115
131
  suggested_var: suggested_var(method_name),
116
132
  method: method_name
117
133
  )
118
- add_offense(ivar_assign.source_range, message: msg)
134
+ add_offense(lhs, message: msg)
135
+ end
136
+ # rubocop:enable Metrics/AbcSize
137
+
138
+ def_node_matcher :defined_memoized?, <<~PATTERN
139
+ (begin
140
+ (if (defined $(ivar %1)) (return $(ivar %1)) nil?)
141
+ ...
142
+ $(ivasgn %1 _))
143
+ PATTERN
144
+
145
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
146
+ def on_defined?(node)
147
+ arg = node.arguments.first
148
+ return unless arg.ivar_type?
149
+
150
+ method_node = node.each_ancestor(:def, :defs).first
151
+ return unless method_node
152
+
153
+ var_name = arg.children.first
154
+ method_name = method_node.method_name
155
+ defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
156
+ return if matches?(method_name, ivar_assign)
157
+
158
+ msg = format(
159
+ message(var_name.to_s),
160
+ var: var_name.to_s,
161
+ suggested_var: suggested_var(method_name),
162
+ method: method_name
163
+ )
164
+ add_offense(defined_ivar, message: msg)
165
+ add_offense(return_ivar, message: msg)
166
+ add_offense(ivar_assign.loc.name, message: msg)
167
+ end
119
168
  end
120
- alias on_defs on_def
169
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
121
170
 
122
171
  private
123
172
 
@@ -67,7 +67,8 @@ module RuboCop
67
67
  private
68
68
 
69
69
  def allowed_method_name?(method_name, prefix)
70
- !method_name.match?(/^#{prefix}[^0-9]/) ||
70
+ !(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
71
+ method_name.match?(/^#{prefix}[^0-9]/)) ||
71
72
  method_name == expected_name(method_name, prefix) ||
72
73
  method_name.end_with?('=') ||
73
74
  allowed_method?(method_name)