rubocop 1.20.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +19 -6
- data/lib/rubocop/cop/base.rb +2 -2
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +12 -11
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +107 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +7 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +11 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/collection_methods.rb +2 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +23 -8
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_unless.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
- data/lib/rubocop/cop/style/not.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +17 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -1
- data/lib/rubocop/cop/style/static_class.rb +1 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -7
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +1 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -1
- metadata +5 -3
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
|
52
52
|
def on_case_match(node)
|
53
53
|
node.in_pattern_branches.each do |branch|
|
54
|
-
next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
|
54
|
+
next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
|
55
55
|
|
56
56
|
add_offense(branch)
|
57
57
|
end
|
@@ -118,7 +118,7 @@ module RuboCop
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def correct_arguments?(arguments)
|
121
|
-
arguments.size == 1 || arguments.size == 2 && arguments[1].hash_type?
|
121
|
+
arguments.size == 1 || (arguments.size == 2 && arguments[1].hash_type?)
|
122
122
|
end
|
123
123
|
|
124
124
|
def build_kwargs(node)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
#
|
7
|
+
# This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# IO.select([io], [], [], timeout)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# io.wait_readable(timeout)
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# IO.select([], [io], [], timeout)
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# io.wait_writable(timeout)
|
22
|
+
#
|
23
|
+
class IncompatibleIoSelectWithFiberScheduler < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Use `%<preferred>s` instead of `%<current>s`.'
|
27
|
+
RESTRICT_ON_SEND = %i[select].freeze
|
28
|
+
|
29
|
+
# @!method io_select(node)
|
30
|
+
def_node_matcher :io_select, <<~PATTERN
|
31
|
+
(send
|
32
|
+
(const {nil? cbase} :IO) :select $_ $_ {(array) nil} $...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless (read, write, timeout = io_select(node))
|
37
|
+
return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
|
38
|
+
|
39
|
+
preferred = preferred_method(read, write, timeout)
|
40
|
+
message = format(MSG, preferred: preferred, current: node.source)
|
41
|
+
|
42
|
+
add_offense(node, message: message) do |corrector|
|
43
|
+
corrector.replace(node, preferred)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def scheduler_compatible?(io1, io2)
|
50
|
+
return false unless io1.array_type? && io1.values.size == 1
|
51
|
+
|
52
|
+
io2.array_type? ? io2.values.empty? : io2.nil_type?
|
53
|
+
end
|
54
|
+
|
55
|
+
def preferred_method(read, write, timeout)
|
56
|
+
timeout_argument = timeout.empty? ? '' : "(#{timeout[0].source})"
|
57
|
+
|
58
|
+
if read.array_type? && read.values[0]
|
59
|
+
"#{read.values[0].source}.wait_readable#{timeout_argument}"
|
60
|
+
else
|
61
|
+
"#{write.values[0].source}.wait_writable#{timeout_argument}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -60,6 +60,7 @@ module RuboCop
|
|
60
60
|
'class parsing, instead of using '\
|
61
61
|
'`%<current>s`, use stricter '\
|
62
62
|
'`%<corrected_method>s`.'
|
63
|
+
CONVERSION_METHODS = %i[Integer Float Complex to_i to_f to_c].freeze
|
63
64
|
METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
|
64
65
|
|
65
66
|
# @!method to_method(node)
|
@@ -127,7 +128,8 @@ module RuboCop
|
|
127
128
|
end
|
128
129
|
|
129
130
|
def ignore_receiver?(receiver)
|
130
|
-
if receiver.
|
131
|
+
if receiver.numeric_type? || (receiver.send_type? &&
|
132
|
+
(conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
|
131
133
|
true
|
132
134
|
elsif (receiver = top_receiver(receiver))
|
133
135
|
receiver.const_type? && ignored_class?(receiver.const_name)
|
@@ -142,6 +144,10 @@ module RuboCop
|
|
142
144
|
receiver
|
143
145
|
end
|
144
146
|
|
147
|
+
def conversion_method?(method_name)
|
148
|
+
CONVERSION_METHODS.include?(method_name)
|
149
|
+
end
|
150
|
+
|
145
151
|
def ignored_classes
|
146
152
|
cop_config.fetch('IgnoredClasses', [])
|
147
153
|
end
|
@@ -87,9 +87,8 @@ module RuboCop
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def ignored_method?(body)
|
90
|
-
cop_config['IgnoreEmptyMethods'] && body.nil? ||
|
91
|
-
cop_config['IgnoreNotImplementedMethods'] &&
|
92
|
-
not_implemented?(body)
|
90
|
+
(cop_config['IgnoreEmptyMethods'] && body.nil?) ||
|
91
|
+
(cop_config['IgnoreNotImplementedMethods'] && not_implemented?(body))
|
93
92
|
end
|
94
93
|
|
95
94
|
def message(variable)
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
visit_depth_last(@node) { |child| calculate_node(child) }
|
47
47
|
|
48
48
|
[
|
49
|
-
Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2),
|
49
|
+
Math.sqrt((@assignment**2) + (@branch**2) + (@condition**2)).round(2),
|
50
50
|
"<#{@assignment}, #{@branch}, #{@condition}>"
|
51
51
|
]
|
52
52
|
end
|
@@ -147,7 +147,7 @@ module RuboCop
|
|
147
147
|
|
148
148
|
# Returns true for lines that shall not be included in the count.
|
149
149
|
def irrelevant_line?(source_line)
|
150
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
150
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
151
151
|
end
|
152
152
|
|
153
153
|
def count_comments?
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
|
44
44
|
# Returns true for lines that shall not be included in the count.
|
45
45
|
def irrelevant_line(source_line)
|
46
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
46
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
47
47
|
end
|
48
48
|
|
49
49
|
def build_code_length_calculator(node)
|
@@ -9,9 +9,8 @@ module RuboCop
|
|
9
9
|
FROZEN_STRING_LITERAL = '# frozen_string_literal:'
|
10
10
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
11
11
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
12
|
-
FROZEN_STRING_LITERAL_TYPES_RUBY30 = %i[str].freeze
|
13
12
|
|
14
|
-
private_constant :FROZEN_STRING_LITERAL_TYPES_RUBY27
|
13
|
+
private_constant :FROZEN_STRING_LITERAL_TYPES_RUBY27
|
15
14
|
|
16
15
|
def frozen_string_literal_comment_exists?
|
17
16
|
leading_comment_lines.any? { |line| MagicComment.parse(line).valid_literal_value? }
|
@@ -20,13 +19,19 @@ module RuboCop
|
|
20
19
|
private
|
21
20
|
|
22
21
|
def frozen_string_literal?(node)
|
23
|
-
|
24
|
-
|
22
|
+
frozen_string = if target_ruby_version >= 3.0
|
23
|
+
node.str_type? || frozen_heredoc?(node)
|
25
24
|
else
|
26
|
-
FROZEN_STRING_LITERAL_TYPES_RUBY27
|
25
|
+
FROZEN_STRING_LITERAL_TYPES_RUBY27.include?(node.type)
|
27
26
|
end
|
28
27
|
|
29
|
-
|
28
|
+
frozen_string && frozen_string_literals_enabled?
|
29
|
+
end
|
30
|
+
|
31
|
+
def frozen_heredoc?(node)
|
32
|
+
return false unless node.dstr_type? && node.heredoc?
|
33
|
+
|
34
|
+
node.children.all?(&:str_type?)
|
30
35
|
end
|
31
36
|
|
32
37
|
def frozen_string_literals_enabled?
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
|
135
135
|
next if a.setter_method?
|
136
136
|
next unless kind == :with_or_without_parentheses ||
|
137
|
-
kind == :with_parentheses && parentheses?(a)
|
137
|
+
(kind == :with_parentheses && parentheses?(a))
|
138
138
|
|
139
139
|
a.arguments.any? { |arg| within_node?(node, arg) }
|
140
140
|
end
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
156
156
|
|
157
157
|
def disqualified_rhs?(candidate, ancestor)
|
158
158
|
UNALIGNED_RHS_TYPES.include?(ancestor.type) ||
|
159
|
-
ancestor.block_type? && part_of_block_body?(candidate, ancestor)
|
159
|
+
(ancestor.block_type? && part_of_block_body?(candidate, ancestor))
|
160
160
|
end
|
161
161
|
|
162
162
|
def valid_rhs?(candidate, ancestor)
|
@@ -93,7 +93,15 @@ module RuboCop
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def aligned_assignment?(range, line)
|
96
|
-
range.source[-1] == '=' && line[range.last_column - 1] == '='
|
96
|
+
(range.source[-1] == '=' && line[range.last_column - 1] == '=') ||
|
97
|
+
aligned_with_append_operator?(range, line)
|
98
|
+
end
|
99
|
+
|
100
|
+
def aligned_with_append_operator?(range, line)
|
101
|
+
last_column = range.last_column
|
102
|
+
|
103
|
+
(range.source == '<<' && line[last_column - 1] == '=') ||
|
104
|
+
(range.source[-1] == '=' && line[(last_column - 2)..(last_column - 1)] == '<<')
|
97
105
|
end
|
98
106
|
|
99
107
|
def aligned_identical?(range, line)
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def allowed_assignment?(value)
|
57
|
-
value && %i[block const casgn].include?(value.type) ||
|
57
|
+
(value && %i[block const casgn].include?(value.type)) ||
|
58
58
|
allowed_method_call_on_rhs?(value) ||
|
59
59
|
class_or_struct_return_method?(value) ||
|
60
60
|
allowed_conditional_expression_on_rhs?(value)
|
@@ -70,6 +70,8 @@ module RuboCop
|
|
70
70
|
include RangeHelp
|
71
71
|
|
72
72
|
EMPTY_ARRAY = [].freeze
|
73
|
+
MSG = "Consider replacing '%<term>s'%<suffix>s."
|
74
|
+
MSG_FOR_FILE_PATH = "Consider replacing '%<term>s' in file path%<suffix>s."
|
73
75
|
|
74
76
|
WordLocation = Struct.new(:word, :position)
|
75
77
|
|
@@ -197,12 +199,11 @@ module RuboCop
|
|
197
199
|
end
|
198
200
|
|
199
201
|
def create_single_word_message_for_file(word)
|
200
|
-
create_message(word
|
202
|
+
create_message(word, MSG_FOR_FILE_PATH)
|
201
203
|
end
|
202
204
|
|
203
205
|
def create_multiple_word_message_for_file(words)
|
204
|
-
|
205
|
-
"Consider replacing problematic terms #{quoted_words.join(', ')} in file path."
|
206
|
+
format(MSG_FOR_FILE_PATH, term: words.join("', '"), suffix: ' with other terms')
|
206
207
|
end
|
207
208
|
|
208
209
|
def scan_for_words(input)
|
@@ -223,9 +224,12 @@ module RuboCop
|
|
223
224
|
safe_str.gsub(@allowed_regex) { |match| '*' * match.size }
|
224
225
|
end
|
225
226
|
|
226
|
-
def create_message(word)
|
227
|
+
def create_message(word, message = MSG)
|
227
228
|
flagged_term = find_flagged_term(word)
|
228
|
-
|
229
|
+
suggestions = flagged_term['SuggestionString']
|
230
|
+
suggestions = ' with another term' if suggestions.blank?
|
231
|
+
|
232
|
+
format(message, term: word, suffix: suggestions)
|
229
233
|
end
|
230
234
|
|
231
235
|
def find_flagged_term(word)
|
@@ -235,10 +239,6 @@ module RuboCop
|
|
235
239
|
flagged_term
|
236
240
|
end
|
237
241
|
|
238
|
-
def create_message_for_file(word)
|
239
|
-
create_message(word).sub(/\.$/, ' in file path.')
|
240
|
-
end
|
241
|
-
|
242
242
|
def preprocess_suggestions(suggestions)
|
243
243
|
return '' if suggestions.nil? ||
|
244
244
|
(suggestions.is_a?(String) && suggestions.strip.empty?) || suggestions.empty?
|
@@ -59,8 +59,8 @@ module RuboCop
|
|
59
59
|
|
60
60
|
def check(send_node)
|
61
61
|
return if previous_line_comment?(send_node)
|
62
|
-
return unless grouped_style? && sibling_accessors(send_node).size > 1 ||
|
63
|
-
separated_style? && send_node.arguments.size > 1
|
62
|
+
return unless (grouped_style? && sibling_accessors(send_node).size > 1) ||
|
63
|
+
(separated_style? && send_node.arguments.size > 1)
|
64
64
|
|
65
65
|
message = message(send_node)
|
66
66
|
add_offense(send_node, message: message) do |corrector|
|
@@ -7,6 +7,10 @@ module RuboCop
|
|
7
7
|
# `||` instead. It can be configured to check only in conditions or in
|
8
8
|
# all contexts.
|
9
9
|
#
|
10
|
+
# It is marked as unsafe auto-correction because it may change the
|
11
|
+
# operator precedence between logical operators (`&&` and `||`) and
|
12
|
+
# semantic operators (`and` and `or`).
|
13
|
+
#
|
10
14
|
# @example EnforcedStyle: always
|
11
15
|
# # bad
|
12
16
|
# foo.save and return
|
@@ -5,9 +5,11 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for uses of the case equality operator(===).
|
7
7
|
#
|
8
|
+
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
9
|
+
# the case equality operator is a constant.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# # bad
|
10
|
-
# Array === something
|
11
13
|
# (1..100) === 7
|
12
14
|
# /something/ === some_string
|
13
15
|
#
|
@@ -16,18 +18,13 @@ module RuboCop
|
|
16
18
|
# (1..100).include?(7)
|
17
19
|
# /something/.match?(some_string)
|
18
20
|
#
|
19
|
-
# @example AllowOnConstant
|
20
|
-
# # Style/CaseEquality:
|
21
|
-
# # AllowOnConstant: true
|
22
|
-
#
|
21
|
+
# @example AllowOnConstant: false (default)
|
23
22
|
# # bad
|
24
|
-
#
|
25
|
-
# /something/ === some_string
|
23
|
+
# Array === something
|
26
24
|
#
|
25
|
+
# @example AllowOnConstant: true
|
27
26
|
# # good
|
28
27
|
# Array === something
|
29
|
-
# (1..100).include?(7)
|
30
|
-
# /something/.match?(some_string)
|
31
28
|
#
|
32
29
|
class CaseEquality < Base
|
33
30
|
extend AutoCorrector
|
@@ -68,7 +68,8 @@ module RuboCop
|
|
68
68
|
return false unless node.arguments.any?
|
69
69
|
|
70
70
|
node.last_argument.block_pass_type? ||
|
71
|
-
node.last_argument.sym_type? &&
|
71
|
+
(node.last_argument.sym_type? &&
|
72
|
+
methods_accepting_symbol.include?(node.method_name.to_s))
|
72
73
|
end
|
73
74
|
|
74
75
|
def message(node)
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
return unless arg_node&.dstr_type? && interpolated?(arg_node)
|
88
88
|
return if inline_comment_docs?(arg_node) ||
|
89
|
-
arg_node.heredoc? && comment_block_docs?(arg_node)
|
89
|
+
(arg_node.heredoc? && comment_block_docs?(arg_node))
|
90
90
|
|
91
91
|
add_offense(node.loc.selector)
|
92
92
|
end
|
@@ -71,8 +71,9 @@ module RuboCop
|
|
71
71
|
#
|
72
72
|
class Documentation < Base
|
73
73
|
include DocumentationComment
|
74
|
+
include RangeHelp
|
74
75
|
|
75
|
-
MSG = 'Missing top-level
|
76
|
+
MSG = 'Missing top-level documentation comment for `%<type>s %<identifier>s`.'
|
76
77
|
|
77
78
|
# @!method constant_definition?(node)
|
78
79
|
def_node_matcher :constant_definition?, '{class module casgn}'
|
@@ -88,33 +89,35 @@ module RuboCop
|
|
88
89
|
def on_class(node)
|
89
90
|
return unless node.body
|
90
91
|
|
91
|
-
check(node, node.body
|
92
|
+
check(node, node.body)
|
92
93
|
end
|
93
94
|
|
94
95
|
def on_module(node)
|
95
|
-
check(node, node.body
|
96
|
+
check(node, node.body)
|
96
97
|
end
|
97
98
|
|
98
99
|
private
|
99
100
|
|
100
|
-
def check(node, body
|
101
|
+
def check(node, body)
|
101
102
|
return if namespace?(body)
|
102
103
|
return if documentation_comment?(node)
|
103
104
|
return if constant_allowed?(node)
|
104
105
|
return if nodoc_self_or_outer_module?(node)
|
105
106
|
return if macro_only?(body)
|
106
107
|
|
107
|
-
|
108
|
+
range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
|
109
|
+
message = format(MSG, type: node.type, identifier: identifier(node))
|
110
|
+
add_offense(range, message: message)
|
108
111
|
end
|
109
112
|
|
110
113
|
def nodoc_self_or_outer_module?(node)
|
111
114
|
nodoc_comment?(node) ||
|
112
|
-
compact_namespace?(node) && nodoc_comment?(outer_module(node).first)
|
115
|
+
(compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
|
113
116
|
end
|
114
117
|
|
115
118
|
def macro_only?(body)
|
116
|
-
body.respond_to?(:macro?) && body.macro? ||
|
117
|
-
body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
|
119
|
+
(body.respond_to?(:macro?) && body.macro?) ||
|
120
|
+
(body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) })
|
118
121
|
end
|
119
122
|
|
120
123
|
def namespace?(node)
|
@@ -165,6 +168,18 @@ module RuboCop
|
|
165
168
|
def allowed_constants
|
166
169
|
@allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
|
167
170
|
end
|
171
|
+
|
172
|
+
def identifier(node)
|
173
|
+
# Get the fully qualified identifier for a class/module
|
174
|
+
nodes = [node, *node.each_ancestor(:class, :module)]
|
175
|
+
nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
|
176
|
+
end
|
177
|
+
|
178
|
+
def qualify_const(node)
|
179
|
+
return if node.nil?
|
180
|
+
|
181
|
+
[qualify_const(node.namespace), node.short_name].compact
|
182
|
+
end
|
168
183
|
end
|
169
184
|
end
|
170
185
|
end
|