rubocop 1.7.0 → 1.10.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/LICENSE.txt +1 -1
- data/README.md +4 -3
- data/config/default.yml +137 -31
- data/config/obsoletion.yml +4 -0
- data/lib/rubocop.rb +14 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
- data/lib/rubocop/comment_config.rb +6 -6
- data/lib/rubocop/config.rb +5 -2
- data/lib/rubocop/config_loader.rb +7 -14
- data/lib/rubocop/config_store.rb +12 -1
- data/lib/rubocop/cop/base.rb +2 -1
- data/lib/rubocop/cop/exclude_limit.rb +26 -0
- data/lib/rubocop/cop/gemspec/date_assignment.rb +56 -0
- data/lib/rubocop/cop/generator.rb +1 -3
- data/lib/rubocop/cop/internal_affairs.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +38 -18
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
- data/lib/rubocop/cop/layout/line_length.rb +2 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +26 -0
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +19 -16
- data/lib/rubocop/cop/lint/debugger.rb +58 -14
- data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +13 -4
- data/lib/rubocop/cop/lint/duplicate_require.rb +2 -2
- data/lib/rubocop/cop/lint/else_layout.rb +1 -1
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
- data/lib/rubocop/cop/lint/multiple_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
- data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +5 -3
- data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
- data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
- data/lib/rubocop/cop/message_annotator.rb +4 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
- data/lib/rubocop/cop/mixin/code_length.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
- data/lib/rubocop/cop/mixin/preferred_delimiters.rb +2 -2
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
- data/lib/rubocop/cop/naming/variable_name.rb +2 -0
- data/lib/rubocop/cop/naming/variable_number.rb +2 -9
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/severity.rb +3 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
- data/lib/rubocop/cop/style/constant_visibility.rb +27 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
- data/lib/rubocop/cop/style/double_negation.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +6 -2
- data/lib/rubocop/cop/style/endless_method.rb +102 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +138 -49
- data/lib/rubocop/cop/style/explicit_block_argument.rb +11 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +6 -7
- data/lib/rubocop/cop/style/float_division.rb +3 -0
- data/lib/rubocop/cop/style/format_string_token.rb +18 -2
- data/lib/rubocop/cop/style/hash_conversion.rb +81 -0
- data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
- data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
- data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +3 -2
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +32 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +30 -1
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +5 -2
- data/lib/rubocop/runner.rb +1 -0
- data/lib/rubocop/target_ruby.rb +47 -11
- data/lib/rubocop/version.rb +2 -2
- metadata +24 -7
@@ -6,6 +6,9 @@ module RuboCop
|
|
6
6
|
# This cop enforces the use of explicit block argument to avoid writing
|
7
7
|
# block literal that just passes its arguments to another block.
|
8
8
|
#
|
9
|
+
# NOTE: This cop only registers an offense if the block args match the
|
10
|
+
# yield args exactly.
|
11
|
+
#
|
9
12
|
# @example
|
10
13
|
# # bad
|
11
14
|
# def with_tmp_dir
|
@@ -75,7 +78,14 @@ module RuboCop
|
|
75
78
|
private
|
76
79
|
|
77
80
|
def yielding_arguments?(block_args, yield_args)
|
81
|
+
yield_args = yield_args.dup.fill(
|
82
|
+
nil,
|
83
|
+
yield_args.length, block_args.length - yield_args.length
|
84
|
+
)
|
85
|
+
|
78
86
|
yield_args.zip(block_args).all? do |yield_arg, block_arg|
|
87
|
+
next false unless yield_arg && block_arg
|
88
|
+
|
79
89
|
block_arg && yield_arg.children.first == block_arg.children.first
|
80
90
|
end
|
81
91
|
end
|
@@ -87,7 +97,7 @@ module RuboCop
|
|
87
97
|
replacement = ' &block'
|
88
98
|
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
|
89
99
|
corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
|
90
|
-
elsif node.call_type?
|
100
|
+
elsif node.call_type? || node.zsuper_type?
|
91
101
|
corrector.insert_after(node, '(&block)')
|
92
102
|
else
|
93
103
|
corrector.insert_after(node.loc.name, '(&block)')
|
@@ -5,13 +5,12 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop enforces consistency when using exponential notation
|
7
7
|
# for numbers in the code (eg 1.2e4). Different styles are supported:
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# * `engineering` which enforces the exponent to be a multiple of 3
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# without trailing zeroes.
|
8
|
+
#
|
9
|
+
# * `scientific` which enforces a mantissa between 1 (inclusive) and 10 (exclusive).
|
10
|
+
# * `engineering` which enforces the exponent to be a multiple of 3 and the mantissa
|
11
|
+
# to be between 0.1 (inclusive) and 10 (exclusive).
|
12
|
+
# * `integral` which enforces the mantissa to always be a whole number without
|
13
|
+
# trailing zeroes.
|
15
14
|
#
|
16
15
|
# @example EnforcedStyle: scientific (default)
|
17
16
|
# # Enforces a mantissa between 1 (inclusive) and 10 (exclusive).
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# It is recommended to either always use `fdiv` or coerce one side only.
|
8
8
|
# This cop also provides other options for code consistency.
|
9
9
|
#
|
10
|
+
# This cop is marked as unsafe, because if operand variable is a string object
|
11
|
+
# then `.to_f` will be removed and an error will occur.
|
12
|
+
#
|
10
13
|
# @example EnforcedStyle: single_coerce (default)
|
11
14
|
# # bad
|
12
15
|
# a.to_f / b.to_f
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
# The reason is that _unannotated_ format is very similar
|
12
12
|
# to encoded URLs or Date/Time formatting strings.
|
13
13
|
#
|
14
|
+
# This cop can be customized ignored methods with `IgnoredMethods`.
|
15
|
+
#
|
14
16
|
# @example EnforcedStyle: annotated (default)
|
15
17
|
#
|
16
18
|
# # bad
|
@@ -58,12 +60,18 @@ module RuboCop
|
|
58
60
|
#
|
59
61
|
# # good
|
60
62
|
# format('%06d', 10)
|
63
|
+
#
|
64
|
+
# @example IgnoredMethods: [redirect]
|
65
|
+
#
|
66
|
+
# # good
|
67
|
+
# redirect('foo/%{bar_id}')
|
68
|
+
#
|
61
69
|
class FormatStringToken < Base
|
62
70
|
include ConfigurableEnforcedStyle
|
71
|
+
include IgnoredMethods
|
63
72
|
|
64
73
|
def on_str(node)
|
65
|
-
return
|
66
|
-
return if node.each_ancestor(:xstr, :regexp).any?
|
74
|
+
return if format_string_token?(node) || use_ignored_method?(node)
|
67
75
|
|
68
76
|
detections = collect_detections(node)
|
69
77
|
return if detections.empty?
|
@@ -88,6 +96,14 @@ module RuboCop
|
|
88
96
|
}
|
89
97
|
PATTERN
|
90
98
|
|
99
|
+
def format_string_token?(node)
|
100
|
+
!node.value.include?('%') || node.each_ancestor(:xstr, :regexp).any?
|
101
|
+
end
|
102
|
+
|
103
|
+
def use_ignored_method?(node)
|
104
|
+
(parent = node.parent) && parent.send_type? && ignored_method?(parent.method_name)
|
105
|
+
end
|
106
|
+
|
91
107
|
def unannotated_format?(node, detected_style)
|
92
108
|
detected_style == :unannotated && !format_string_in_typical_context?(node)
|
93
109
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks the usage of pre-2.1 `Hash[args]` method of converting enumerables and
|
7
|
+
# sequences of values to hashes.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# Hash[ary]
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# ary.to_h
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# Hash[key1, value1, key2, value2]
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# {key1 => value1, key2 => value2}
|
21
|
+
class HashConversion < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG_TO_H = 'Prefer ary.to_h to Hash[ary].'
|
25
|
+
MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...].'
|
26
|
+
MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...].'
|
27
|
+
MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array].'
|
28
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
29
|
+
|
30
|
+
def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return unless hash_from_array?(node)
|
34
|
+
|
35
|
+
# There are several cases:
|
36
|
+
# If there is one argument:
|
37
|
+
# Hash[ary] => ary.to_h
|
38
|
+
# Hash[*ary] => don't suggest corrections
|
39
|
+
# If there is 0 or 2+ arguments:
|
40
|
+
# Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
|
41
|
+
# ...but don't suggest correction if there is odd number of them (it is a bug)
|
42
|
+
node.arguments.count == 1 ? single_argument(node) : multi_argument(node)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def single_argument(node)
|
48
|
+
first_argument = node.first_argument
|
49
|
+
if first_argument.hash_type?
|
50
|
+
add_offense(node, message: MSG_LITERAL_HASH_ARG) do |corrector|
|
51
|
+
corrector.replace(node, "{#{first_argument.source}}")
|
52
|
+
end
|
53
|
+
elsif first_argument.splat_type?
|
54
|
+
add_offense(node, message: MSG_SPLAT)
|
55
|
+
else
|
56
|
+
add_offense(node, message: MSG_TO_H) do |corrector|
|
57
|
+
corrector.replace(node, "#{first_argument.source}.to_h")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def multi_argument(node)
|
63
|
+
if node.arguments.count.odd?
|
64
|
+
add_offense(node, message: MSG_LITERAL_MULTI_ARG)
|
65
|
+
else
|
66
|
+
add_offense(node, message: MSG_LITERAL_MULTI_ARG) do |corrector|
|
67
|
+
corrector.replace(node, args_to_hash(node.arguments))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def args_to_hash(args)
|
73
|
+
content = args.each_slice(2)
|
74
|
+
.map { |arg1, arg2| "#{arg1.source} => #{arg2.source}" }
|
75
|
+
.join(', ')
|
76
|
+
"{#{content}}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -68,7 +68,8 @@ module RuboCop
|
|
68
68
|
length = cop_config['MinBranchesCount'] || 3
|
69
69
|
return length if length.is_a?(Integer) && length.positive?
|
70
70
|
|
71
|
-
|
71
|
+
warn Rainbow('`MinBranchesCount` needs to be a positive integer!').red
|
72
|
+
exit!
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
@@ -82,15 +82,14 @@ module RuboCop
|
|
82
82
|
def autocorrect(corrector, node)
|
83
83
|
if node.modifier_form?
|
84
84
|
correct_to_elsif_from_modifier_form(corrector, node)
|
85
|
-
end_range = node.parent.loc.end
|
86
85
|
else
|
87
86
|
correct_to_elsif_from_if_inside_else_form(corrector, node, node.condition)
|
88
|
-
end_range = node.loc.end
|
89
87
|
end
|
90
|
-
corrector.remove(range_by_whole_lines(
|
91
|
-
|
92
|
-
|
93
|
-
)
|
88
|
+
corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
|
89
|
+
return unless (if_branch = node.if_branch)
|
90
|
+
|
91
|
+
range = range_by_whole_lines(if_branch.source_range, include_final_newline: true)
|
92
|
+
corrector.remove(range)
|
94
93
|
end
|
95
94
|
|
96
95
|
def correct_to_elsif_from_modifier_form(corrector, node)
|
@@ -103,13 +102,26 @@ module RuboCop
|
|
103
102
|
|
104
103
|
def correct_to_elsif_from_if_inside_else_form(corrector, node, condition)
|
105
104
|
corrector.replace(node.parent.loc.else, "elsif #{condition.source}")
|
106
|
-
if_condition_range =
|
107
|
-
|
108
|
-
|
109
|
-
|
105
|
+
if_condition_range = if_condition_range(node, condition)
|
106
|
+
if (if_branch = node.if_branch)
|
107
|
+
corrector.replace(if_condition_range, if_branch.source)
|
108
|
+
else
|
109
|
+
corrector.remove(range_by_whole_lines(if_condition_range, include_final_newline: true))
|
110
|
+
end
|
110
111
|
corrector.remove(condition)
|
111
112
|
end
|
112
113
|
|
114
|
+
def find_end_range(node)
|
115
|
+
end_range = node.loc.end
|
116
|
+
return end_range if end_range
|
117
|
+
|
118
|
+
find_end_range(node.parent)
|
119
|
+
end
|
120
|
+
|
121
|
+
def if_condition_range(node, condition)
|
122
|
+
range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
|
123
|
+
end
|
124
|
+
|
113
125
|
def allow_if_modifier_in_else_branch?(else_branch)
|
114
126
|
allow_if_modifier? && else_branch&.modifier_form?
|
115
127
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for redundant `if` with boolean literal branches.
|
7
|
+
# It checks only conditions to return boolean value (`true` or `false`) for safe detection.
|
8
|
+
# The conditions to be checked are comparison methods, predicate methods, and double negative.
|
9
|
+
# However, auto-correction is unsafe because there is no guarantee that all predicate methods
|
10
|
+
# will return boolean value. Those methods can be allowed with `AllowedMethods` config.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# if foo == bar
|
15
|
+
# true
|
16
|
+
# else
|
17
|
+
# false
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# foo == bar ? true : false
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# foo == bar
|
25
|
+
#
|
26
|
+
# @example AllowedMethods: ['nonzero?']
|
27
|
+
# # good
|
28
|
+
# num.nonzero? ? true : false
|
29
|
+
#
|
30
|
+
class IfWithBooleanLiteralBranches < Base
|
31
|
+
include AllowedMethods
|
32
|
+
extend AutoCorrector
|
33
|
+
|
34
|
+
MSG = 'Remove redundant %<keyword>s with boolean literal branches.'
|
35
|
+
MSG_FOR_ELSIF = 'Use `else` instead of redundant `elsif` with boolean literal branches.'
|
36
|
+
|
37
|
+
def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
|
38
|
+
(if #return_boolean_value? {(true) (false) | (false) (true)})
|
39
|
+
PATTERN
|
40
|
+
def_node_matcher :double_negative?, '(send (send _ :!) :!)'
|
41
|
+
|
42
|
+
def on_if(node)
|
43
|
+
return unless if_with_boolean_literal_branches?(node)
|
44
|
+
|
45
|
+
condition = node.condition
|
46
|
+
range, keyword = offense_range_with_keyword(node, condition)
|
47
|
+
|
48
|
+
add_offense(range, message: message(node, keyword)) do |corrector|
|
49
|
+
replacement = replacement_condition(node, condition)
|
50
|
+
|
51
|
+
if node.elsif?
|
52
|
+
corrector.insert_before(node, "else\n")
|
53
|
+
corrector.replace(node, "#{indent(node.if_branch)}#{replacement}")
|
54
|
+
else
|
55
|
+
corrector.replace(node, replacement)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def offense_range_with_keyword(node, condition)
|
63
|
+
if node.ternary?
|
64
|
+
range = condition.source_range.end.join(node.source_range.end)
|
65
|
+
|
66
|
+
[range, 'ternary operator']
|
67
|
+
else
|
68
|
+
keyword = node.loc.keyword
|
69
|
+
|
70
|
+
[keyword, "`#{keyword.source}`"]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def message(node, keyword)
|
75
|
+
message_template = node.elsif? ? MSG_FOR_ELSIF : MSG
|
76
|
+
|
77
|
+
format(message_template, keyword: keyword)
|
78
|
+
end
|
79
|
+
|
80
|
+
def return_boolean_value?(condition)
|
81
|
+
if condition.begin_type?
|
82
|
+
return_boolean_value?(condition.children.first)
|
83
|
+
elsif condition.or_type?
|
84
|
+
return_boolean_value?(condition.lhs) && return_boolean_value?(condition.rhs)
|
85
|
+
elsif condition.and_type?
|
86
|
+
return_boolean_value?(condition.rhs)
|
87
|
+
else
|
88
|
+
assume_boolean_value?(condition)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def assume_boolean_value?(condition)
|
93
|
+
return false unless condition.send_type?
|
94
|
+
return false if allowed_method?(condition.method_name)
|
95
|
+
|
96
|
+
condition.comparison_method? || condition.predicate_method? || double_negative?(condition)
|
97
|
+
end
|
98
|
+
|
99
|
+
def replacement_condition(node, condition)
|
100
|
+
bang = '!' if opposite_condition?(node)
|
101
|
+
|
102
|
+
if bang && require_parentheses?(condition)
|
103
|
+
"#{bang}(#{condition.source})"
|
104
|
+
else
|
105
|
+
"#{bang}#{condition.source}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def opposite_condition?(node)
|
110
|
+
!node.unless? && node.if_branch.false_type? || node.unless? && node.if_branch.true_type?
|
111
|
+
end
|
112
|
+
|
113
|
+
def require_parentheses?(condition)
|
114
|
+
condition.and_type? || condition.or_type? ||
|
115
|
+
condition.send_type? && condition.comparison_method?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -157,6 +157,10 @@ module RuboCop
|
|
157
157
|
include OmitParentheses
|
158
158
|
extend AutoCorrector
|
159
159
|
|
160
|
+
def self.autocorrect_incompatible_with
|
161
|
+
[Style::NestedParenthesizedCalls]
|
162
|
+
end
|
163
|
+
|
160
164
|
def on_send(node)
|
161
165
|
send(style, node) # call require_parentheses or omit_parentheses
|
162
166
|
end
|
@@ -8,6 +8,9 @@ module RuboCop
|
|
8
8
|
# With `IncludeSemanticChanges` set to `false` by default, this cop
|
9
9
|
# does not report offenses for `!x.nil?` and does no changes that might
|
10
10
|
# change behavior.
|
11
|
+
# Also `IncludeSemanticChanges` set to `false` with `EnforcedStyle: comparison` of
|
12
|
+
# `Style/NilComparison` cop, this cop does not report offenses for `x != nil` and
|
13
|
+
# does no changes to `!x.nil?` style.
|
11
14
|
#
|
12
15
|
# With `IncludeSemanticChanges` set to `true`, this cop reports offenses
|
13
16
|
# for `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which
|
@@ -41,6 +44,9 @@ module RuboCop
|
|
41
44
|
class NonNilCheck < Base
|
42
45
|
extend AutoCorrector
|
43
46
|
|
47
|
+
MSG_FOR_REPLACEMENT = 'Prefer `%<prefer>s` over `%<current>s`.'
|
48
|
+
MSG_FOR_REDUNDANCY = 'Explicit non-nil checks are usually redundant.'
|
49
|
+
|
44
50
|
RESTRICT_ON_SEND = %i[!= nil? !].freeze
|
45
51
|
|
46
52
|
def_node_matcher :not_equal_to_nil?, '(send _ :!= nil)'
|
@@ -49,11 +55,12 @@ module RuboCop
|
|
49
55
|
def_node_matcher :not_and_nil_check?, '(send (send _ :nil?) :!)'
|
50
56
|
|
51
57
|
def on_send(node)
|
52
|
-
return if ignored_node?(node)
|
53
|
-
|
58
|
+
return if ignored_node?(node) ||
|
59
|
+
!include_semantic_changes? && nil_comparison_style == 'comparison'
|
60
|
+
return unless register_offense?(node)
|
54
61
|
|
55
62
|
message = message(node)
|
56
|
-
add_offense(
|
63
|
+
add_offense(node, message: message) do |corrector|
|
57
64
|
autocorrect(corrector, node)
|
58
65
|
end
|
59
66
|
end
|
@@ -73,13 +80,9 @@ module RuboCop
|
|
73
80
|
|
74
81
|
private
|
75
82
|
|
76
|
-
def
|
77
|
-
|
78
|
-
node
|
79
|
-
elsif include_semantic_changes? &&
|
80
|
-
(not_and_nil_check?(node) || unless_and_nil_check?(node))
|
81
|
-
node
|
82
|
-
end
|
83
|
+
def register_offense?(node)
|
84
|
+
not_equal_to_nil?(node) ||
|
85
|
+
include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node))
|
83
86
|
end
|
84
87
|
|
85
88
|
def autocorrect(corrector, node)
|
@@ -101,10 +104,11 @@ module RuboCop
|
|
101
104
|
end
|
102
105
|
|
103
106
|
def message(node)
|
104
|
-
if node.method?(:!=)
|
105
|
-
|
107
|
+
if node.method?(:!=) && !include_semantic_changes?
|
108
|
+
prefer = "!#{node.receiver.source}.nil?"
|
109
|
+
format(MSG_FOR_REPLACEMENT, prefer: prefer, current: node.source)
|
106
110
|
else
|
107
|
-
|
111
|
+
MSG_FOR_REDUNDANCY
|
108
112
|
end
|
109
113
|
end
|
110
114
|
|
@@ -138,6 +142,12 @@ module RuboCop
|
|
138
142
|
corrector.replace(node.parent.loc.keyword, 'if')
|
139
143
|
corrector.replace(node, receiver.source)
|
140
144
|
end
|
145
|
+
|
146
|
+
def nil_comparison_style
|
147
|
+
nil_comparison_conf = config.for_cop('Style/NilComparison')
|
148
|
+
|
149
|
+
nil_comparison_conf['Enabled'] && nil_comparison_conf['EnforcedStyle']
|
150
|
+
end
|
141
151
|
end
|
142
152
|
end
|
143
153
|
end
|