rubocop 1.75.5 → 1.77.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -14
  3. data/config/default.yml +74 -7
  4. data/config/obsoletion.yml +6 -3
  5. data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
  6. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  7. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  8. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  9. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
  10. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  11. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  12. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  13. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
  14. data/lib/rubocop/cop/layout/class_structure.rb +35 -0
  15. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  16. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -3
  17. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  18. data/lib/rubocop/cop/layout/line_length.rb +26 -5
  19. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -38
  20. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +8 -2
  21. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  22. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  23. data/lib/rubocop/cop/lint/duplicate_methods.rb +84 -2
  24. data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
  25. data/lib/rubocop/cop/lint/float_comparison.rb +31 -4
  26. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  27. data/lib/rubocop/cop/lint/literal_as_condition.rb +19 -27
  28. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  29. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  30. data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
  31. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  32. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  33. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
  34. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  35. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  36. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  37. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  38. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  39. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  40. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  41. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  42. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  43. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  44. data/lib/rubocop/cop/naming/predicate_method.rb +281 -0
  45. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  46. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
  47. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  48. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  49. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  50. data/lib/rubocop/cop/style/comparable_between.rb +3 -0
  51. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
  52. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  53. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  54. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  55. data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
  56. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  57. data/lib/rubocop/cop/style/hash_conversion.rb +12 -3
  58. data/lib/rubocop/cop/style/if_unless_modifier.rb +33 -6
  59. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  60. data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
  61. data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
  62. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  63. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  64. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  65. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  66. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  67. data/lib/rubocop/cop/style/redundant_format.rb +6 -1
  68. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  69. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -5
  70. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  71. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  72. data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
  73. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -3
  74. data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
  75. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  76. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  77. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  78. data/lib/rubocop/cop/team.rb +1 -1
  79. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  80. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
  81. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  82. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  83. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  84. data/lib/rubocop/lsp/diagnostic.rb +4 -4
  85. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  86. data/lib/rubocop/version.rb +1 -1
  87. data/lib/rubocop.rb +8 -1
  88. data/lib/ruby_lsp/rubocop/addon.rb +2 -2
  89. metadata +15 -11
@@ -23,6 +23,14 @@ module RuboCop
23
23
  # # good (method calls possibly can return different results)
24
24
  # hash[foo] = hash[foo]
25
25
  #
26
+ # @example AllowRBSInlineAnnotation:true
27
+ # # good
28
+ # foo = foo #: Integer
29
+ # foo, bar = foo, bar #: Integer
30
+ # Foo = Foo #: Integer
31
+ # hash['foo'] = hash['foo'] #: Integer
32
+ # obj.attr = obj.attr #: Integer
33
+ #
26
34
  class SelfAssignment < Base
27
35
  MSG = 'Self-assignment detected.'
28
36
 
@@ -34,6 +42,8 @@ module RuboCop
34
42
  }.freeze
35
43
 
36
44
  def on_send(node)
45
+ return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.receiver)
46
+
37
47
  if node.method?(:[]=)
38
48
  handle_key_assignment(node) if node.arguments.size == 2
39
49
  elsif node.assignment_method?
@@ -44,6 +54,7 @@ module RuboCop
44
54
 
45
55
  def on_lvasgn(node)
46
56
  return unless node.rhs
57
+ return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.rhs)
47
58
 
48
59
  rhs_type = ASSIGNMENT_TYPE_TO_RHS_TYPE[node.type]
49
60
 
@@ -55,16 +66,22 @@ module RuboCop
55
66
 
56
67
  def on_casgn(node)
57
68
  return unless node.rhs&.const_type?
69
+ return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.rhs)
58
70
 
59
71
  add_offense(node) if node.namespace == node.rhs.namespace &&
60
72
  node.short_name == node.rhs.short_name
61
73
  end
62
74
 
63
75
  def on_masgn(node)
76
+ first_lhs = node.lhs.assignments.first
77
+ return if allow_rbs_inline_annotation? && rbs_inline_annotation?(first_lhs)
78
+
64
79
  add_offense(node) if multiple_self_assignment?(node)
65
80
  end
66
81
 
67
82
  def on_or_asgn(node)
83
+ return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.lhs)
84
+
68
85
  add_offense(node) if rhs_matches_lhs?(node.rhs, node.lhs)
69
86
  end
70
87
  alias on_and_asgn on_or_asgn
@@ -108,6 +125,14 @@ module RuboCop
108
125
  add_offense(node)
109
126
  end
110
127
  end
128
+
129
+ def rbs_inline_annotation?(node)
130
+ processed_source.ast_with_comments[node].any? { |comment| comment.text.start_with?('#:') }
131
+ end
132
+
133
+ def allow_rbs_inline_annotation?
134
+ cop_config['AllowRBSInlineAnnotation']
135
+ end
111
136
  end
112
137
  end
113
138
  end
@@ -8,6 +8,11 @@ module RuboCop
8
8
  # given by `ruby -cw` prior to Ruby 2.6:
9
9
  # "shadowing outer local variable - foo".
10
10
  #
11
+ # The cop is now disabled by default to match the upstream Ruby behavior.
12
+ # It's useful, however, if you'd like to avoid shadowing variables from outer
13
+ # scopes, which some people consider an anti-pattern that makes it harder
14
+ # to keep track of what's going on in a program.
15
+ #
11
16
  # NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
12
17
  # because `Ractor` should not access outer variables.
13
18
  # eg. following style is encouraged:
@@ -4,10 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Lint
6
6
  # Checks for redundant access modifiers, including those with no
7
- # code, those which are repeated, and leading `public` modifiers in a
8
- # class or module body. Conditionally-defined methods are considered as
9
- # always being defined, and thus access modifiers guarding such methods
10
- # are not redundant.
7
+ # code, those which are repeated, those which are on top-level, and
8
+ # leading `public` modifiers in a class or module body.
9
+ # Conditionally-defined methods are considered as always being defined,
10
+ # and thus access modifiers guarding such methods are not redundant.
11
11
  #
12
12
  # This cop has `ContextCreatingMethods` option. The default setting value
13
13
  # is an empty array that means no method is specified.
@@ -58,6 +58,12 @@ module RuboCop
58
58
  # private # this is redundant (no following methods are defined)
59
59
  # end
60
60
  #
61
+ # # bad
62
+ # private # this is useless (access modifiers have no effect on top-level)
63
+ #
64
+ # def method
65
+ # end
66
+ #
61
67
  # # good
62
68
  # class Foo
63
69
  # private # this is not redundant (a method is defined)
@@ -145,6 +151,17 @@ module RuboCop
145
151
  alias on_numblock on_block
146
152
  alias on_itblock on_block
147
153
 
154
+ def on_begin(node)
155
+ return if node.parent
156
+
157
+ node.child_nodes.each do |child|
158
+ next unless child.send_type? && access_modifier?(child)
159
+
160
+ # This call always registers an offense for access modifier `child.method_name`
161
+ check_send_node(child, child.method_name, true)
162
+ end
163
+ end
164
+
148
165
  private
149
166
 
150
167
  def autocorrect(corrector, node)
@@ -257,6 +274,10 @@ module RuboCop
257
274
 
258
275
  def any_method_definition?(child)
259
276
  cop_config.fetch('MethodCreatingMethods', []).any? do |m|
277
+ # Some users still have `"included"` in their `MethodCreatingMethods` configurations,
278
+ # so to prevent Ruby method redefinition warnings let's just skip this value.
279
+ next if m == 'included'
280
+
260
281
  matcher_name = :"#{m}_method?"
261
282
  unless respond_to?(matcher_name)
262
283
  self.class.def_node_matcher matcher_name, <<~PATTERN
@@ -279,7 +300,11 @@ module RuboCop
279
300
  end
280
301
 
281
302
  def any_context_creating_methods?(child)
303
+ # Some users still have `"included"` in their `ContextCreatingMethods` configurations,
304
+ # so to prevent Ruby method redefinition warnings let's just skip this value.
282
305
  cop_config.fetch('ContextCreatingMethods', []).any? do |m|
306
+ next if m == 'included'
307
+
283
308
  matcher_name = :"#{m}_block?"
284
309
  unless respond_to?(matcher_name)
285
310
  self.class.def_node_matcher matcher_name, <<~PATTERN
@@ -104,6 +104,8 @@ module RuboCop
104
104
  end
105
105
 
106
106
  def chained_assignment?(node)
107
+ return true if node.lvasgn_type? && node.expression&.send_type?
108
+
107
109
  node.respond_to?(:expression) && node.expression&.lvasgn_type?
108
110
  end
109
111
 
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for usage of method `fetch` or `Array.new` with default value argument
7
+ # and block. In such cases, block will always be used as default value.
8
+ #
9
+ # This cop emulates Ruby warning "block supersedes default value argument" which
10
+ # applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
11
+ # `Thread#fetch`.
12
+ #
13
+ # A `fetch` call without a receiver is considered a custom method and does not register
14
+ # an offense.
15
+ #
16
+ # @safety
17
+ # This cop is unsafe because the receiver could have nonstandard implementation
18
+ # of `fetch`, or be a class other than the one listed above.
19
+ #
20
+ # It is also unsafe because default value argument could have side effects:
21
+ #
22
+ # [source,ruby]
23
+ # ----
24
+ # def x(a) = puts "side effect"
25
+ # Array.new(5, x(1)) { 2 }
26
+ # ----
27
+ #
28
+ # so removing it would change behavior.
29
+ #
30
+ # @example
31
+ # # bad
32
+ # x.fetch(key, default_value) { block_value }
33
+ # Array.new(size, default_value) { block_value }
34
+ #
35
+ # # good
36
+ # x.fetch(key) { block_value }
37
+ # Array.new(size) { block_value }
38
+ #
39
+ # # also good - in case default value argument is desired instead
40
+ # x.fetch(key, default_value)
41
+ # Array.new(size, default_value)
42
+ #
43
+ # # good - keyword arguments aren't registered as offenses
44
+ # x.fetch(key, keyword: :arg) { block_value }
45
+ #
46
+ # @example AllowedReceivers: ['Rails.cache']
47
+ # # good
48
+ # Rails.cache.fetch(name, options) { block }
49
+ #
50
+ class UselessDefaultValueArgument < Base
51
+ include AllowedReceivers
52
+ extend AutoCorrector
53
+
54
+ MSG = 'Block supersedes default value argument.'
55
+
56
+ RESTRICT_ON_SEND = %i[fetch new].freeze
57
+
58
+ # @!method default_value_argument_and_block(node)
59
+ def_node_matcher :default_value_argument_and_block, <<~PATTERN
60
+ (any_block
61
+ {
62
+ (call !nil? :fetch $_key $_default_value)
63
+ (send (const _ :Array) :new $_size $_default_value)
64
+ }
65
+ _args
66
+ _block_body)
67
+ PATTERN
68
+
69
+ def on_send(node)
70
+ unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
71
+ return
72
+ end
73
+ return if allowed_receiver?(node.receiver)
74
+ return if hash_without_braces?(default_value_node)
75
+
76
+ add_offense(default_value_node) do |corrector|
77
+ corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
78
+ end
79
+ end
80
+ alias on_csend on_send
81
+
82
+ private
83
+
84
+ def hash_without_braces?(node)
85
+ node.hash_type? && !node.braces?
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for useless OR (`||` and `or`) expressions.
7
+ #
8
+ # Some methods always return a truthy value, even when called
9
+ # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
+ # appended after these methods will never evaluate.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # x.to_a || fallback
16
+ # x.to_c || fallback
17
+ # x.to_d || fallback
18
+ # x.to_i || fallback
19
+ # x.to_f || fallback
20
+ # x.to_h || fallback
21
+ # x.to_r || fallback
22
+ # x.to_s || fallback
23
+ # x.to_sym || fallback
24
+ # x.intern || fallback
25
+ # x.inspect || fallback
26
+ # x.hash || fallback
27
+ # x.object_id || fallback
28
+ # x.__id__ || fallback
29
+ #
30
+ # x.to_s or fallback
31
+ #
32
+ # # good - if fallback is same as return value of method called on nil
33
+ # x.to_a # nil.to_a returns []
34
+ # x.to_c # nil.to_c returns (0+0i)
35
+ # x.to_d # nil.to_d returns 0.0
36
+ # x.to_i # nil.to_i returns 0
37
+ # x.to_f # nil.to_f returns 0.0
38
+ # x.to_h # nil.to_h returns {}
39
+ # x.to_r # nil.to_r returns (0/1)
40
+ # x.to_s # nil.to_s returns ''
41
+ # x.to_sym # nil.to_sym raises an error
42
+ # x.intern # nil.intern raises an error
43
+ # x.inspect # nil.inspect returns "nil"
44
+ # x.hash # nil.hash returns an Integer
45
+ # x.object_id # nil.object_id returns an Integer
46
+ # x.__id__ # nil.object_id returns an Integer
47
+ #
48
+ # # good - if the intention is not to call the method on nil
49
+ # x&.to_a || fallback
50
+ # x&.to_c || fallback
51
+ # x&.to_d || fallback
52
+ # x&.to_i || fallback
53
+ # x&.to_f || fallback
54
+ # x&.to_h || fallback
55
+ # x&.to_r || fallback
56
+ # x&.to_s || fallback
57
+ # x&.to_sym || fallback
58
+ # x&.intern || fallback
59
+ # x&.inspect || fallback
60
+ # x&.hash || fallback
61
+ # x&.object_id || fallback
62
+ # x&.__id__ || fallback
63
+ #
64
+ # x&.to_s or fallback
65
+ #
66
+ class UselessOr < Base
67
+ MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
+
69
+ TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
70
+ :to_s, :to_sym, :intern, :inspect, :hash, :object_id,
71
+ :__id__].freeze
72
+
73
+ # @!method truthy_return_value_method?(node)
74
+ def_node_matcher :truthy_return_value_method?, <<~PATTERN
75
+ (send _ %TRUTHY_RETURN_VALUE_METHODS)
76
+ PATTERN
77
+
78
+ def on_or(node)
79
+ if truthy_return_value_method?(node.lhs)
80
+ report_offense(node, node.lhs)
81
+ elsif truthy_return_value_method?(node.rhs)
82
+ parent = node.parent
83
+ parent = parent.parent if parent&.begin_type?
84
+
85
+ report_offense(parent, node.rhs) if parent&.or_type?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def report_offense(or_node, truthy_node)
92
+ add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -89,7 +89,7 @@ module RuboCop
89
89
  private
90
90
 
91
91
  def inspect_def(node, def_node)
92
- return if allowed_arguments(def_node.arguments)
92
+ return if allowed_arguments?(def_node.arguments)
93
93
 
94
94
  add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
95
95
  end
@@ -101,7 +101,7 @@ module RuboCop
101
101
  definition = find_method_definition(node, method_name)
102
102
 
103
103
  return unless definition
104
- return if allowed_arguments(definition.arguments)
104
+ return if allowed_arguments?(definition.arguments)
105
105
 
106
106
  add_offense(node, message: format(MSG, method_name: method_name))
107
107
  end
@@ -115,7 +115,7 @@ module RuboCop
115
115
  end
116
116
 
117
117
  # `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
118
- def allowed_arguments(arguments)
118
+ def allowed_arguments?(arguments)
119
119
  return false if arguments.empty?
120
120
 
121
121
  arguments.each_child_node(:restarg).any? &&
@@ -39,7 +39,7 @@ module RuboCop
39
39
  class AbcSize < Base
40
40
  include MethodComplexity
41
41
 
42
- MSG = 'Assignment Branch Condition size for %<method>s is too high. ' \
42
+ MSG = 'Assignment Branch Condition size for `%<method>s` is too high. ' \
43
43
  '[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
44
44
 
45
45
  private
@@ -66,7 +66,7 @@ module RuboCop
66
66
  end
67
67
 
68
68
  # @deprecated Use processed_source.line_with_comment?(line)
69
- def end_of_line_comment(line)
69
+ def end_of_line_comment(line) # rubocop:disable Naming/PredicateMethod
70
70
  warn Rainbow(<<~WARNING).yellow, uplevel: 1
71
71
  `end_of_line_comment` is deprecated. Use `processed_source.line_with_comment?` instead.
72
72
  WARNING
@@ -89,7 +89,7 @@ module RuboCop
89
89
 
90
90
  if first_non_comment_token
91
91
  # `line` is 1-indexed so we need to subtract 1 to get the array index
92
- processed_source.lines[0...first_non_comment_token.line - 1]
92
+ processed_source.lines[0...(first_non_comment_token.line - 1)]
93
93
  else
94
94
  processed_source.lines
95
95
  end
@@ -25,6 +25,28 @@ module RuboCop
25
25
  (args
26
26
  (arg $_)) ...)
27
27
  PATTERN
28
+
29
+ # @!method assignment_method_declarations(node)
30
+ def_node_search :assignment_method_declarations, <<~PATTERN
31
+ (send
32
+ (lvar {#match_block_variable_name? :_1 :it}) _ ...)
33
+ PATTERN
34
+
35
+ # @!method indexed_assignment_method_declarations(node)
36
+ def_node_search :indexed_assignment_method_declarations, <<~PATTERN
37
+ (send
38
+ (send (lvar {#match_block_variable_name? :_1 :it}) _)
39
+ :[]=
40
+ literal?
41
+ _
42
+ )
43
+ PATTERN
44
+
45
+ def match_block_variable_name?(receiver_name)
46
+ gem_specification(processed_source.ast) do |block_variable_name|
47
+ return block_variable_name == receiver_name
48
+ end
49
+ end
28
50
  end
29
51
  end
30
52
  end
@@ -25,20 +25,24 @@ module RuboCop
25
25
  config.for_cop('Layout/LineLength')['AllowURI']
26
26
  end
27
27
 
28
- def allowed_uri_position?(line, uri_range)
29
- uri_range.begin < max_line_length && uri_range.end == line_length(line)
28
+ def allow_qualified_name?
29
+ config.for_cop('Layout/LineLength')['AllowQualifiedName']
30
+ end
31
+
32
+ def allowed_position?(line, range)
33
+ range.begin < max_line_length && range.end == line_length(line)
30
34
  end
31
35
 
32
36
  def line_length(line)
33
37
  line.length + indentation_difference(line)
34
38
  end
35
39
 
36
- def find_excessive_uri_range(line)
37
- last_uri_match = match_uris(line).last
38
- return nil unless last_uri_match
40
+ def find_excessive_range(line, type)
41
+ last_match = (type == :uri ? match_uris(line) : match_qualified_names(line)).last
42
+ return nil unless last_match
39
43
 
40
- begin_position, end_position = last_uri_match.offset(0)
41
- end_position = extend_uri_end_position(line, end_position)
44
+ begin_position, end_position = last_match.offset(0)
45
+ end_position = extend_end_position(line, end_position)
42
46
 
43
47
  line_indentation_difference = indentation_difference(line)
44
48
  begin_position += line_indentation_difference
@@ -57,6 +61,14 @@ module RuboCop
57
61
  matches
58
62
  end
59
63
 
64
+ def match_qualified_names(string)
65
+ matches = []
66
+ string.scan(qualified_name_regexp) do
67
+ matches << $LAST_MATCH_INFO
68
+ end
69
+ matches
70
+ end
71
+
60
72
  def indentation_difference(line)
61
73
  return 0 unless tab_indentation_width
62
74
 
@@ -70,7 +82,7 @@ module RuboCop
70
82
  index * (tab_indentation_width - 1)
71
83
  end
72
84
 
73
- def extend_uri_end_position(line, end_position)
85
+ def extend_end_position(line, end_position)
74
86
  # Extend the end position YARD comments with linked URLs of the form {<uri> <title>}
75
87
  if line&.match(/{(\s|\S)*}$/)
76
88
  match = line[end_position..line_length(line)]&.match(/(\s|\S)*}/)
@@ -101,6 +113,10 @@ module RuboCop
101
113
  end
102
114
  end
103
115
 
116
+ def qualified_name_regexp
117
+ /\b(?:[A-Z][A-Za-z0-9_]*::)+[A-Za-z_][A-Za-z0-9_]*\b/
118
+ end
119
+
104
120
  def valid_uri?(uri_ish_string)
105
121
  URI.parse(uri_ish_string)
106
122
  true
@@ -24,7 +24,7 @@ module RuboCop
24
24
  gem_canonical_name(string_a) < gem_canonical_name(string_b)
25
25
  end
26
26
 
27
- def consecutive_lines(previous, current)
27
+ def consecutive_lines?(previous, current)
28
28
  first_line = get_source_range(current, treat_comments_as_separators).first_line
29
29
  previous.source_range.last_line == first_line - 1
30
30
  end
@@ -152,7 +152,7 @@ module RuboCop
152
152
 
153
153
  const_namespace, const_name = *const
154
154
  next if name != const_name && !match_acronym?(name, const_name)
155
- next unless namespace.empty? || match_namespace(child, const_namespace, namespace)
155
+ next unless namespace.empty? || namespace_matches?(child, const_namespace, namespace)
156
156
 
157
157
  return node
158
158
  end
@@ -169,7 +169,7 @@ module RuboCop
169
169
  s(:const, namespace, name) if name
170
170
  end
171
171
 
172
- def match_namespace(node, namespace, expected)
172
+ def namespace_matches?(node, namespace, expected)
173
173
  match_partial = partial_matcher!(expected)
174
174
 
175
175
  match_partial.call(namespace)