rubocop 1.8.1 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +37 -4
- data/lib/rubocop.rb +6 -0
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
- 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/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 +37 -17
- 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/space_before_brackets.rb +9 -4
- data/lib/rubocop/cop/lint/deprecated_constants.rb +5 -0
- 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/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/check_line_breakable.rb +5 -0
- data/lib/rubocop/cop/mixin/code_length.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +0 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
- data/lib/rubocop/cop/naming/variable_number.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/disable_cops_within_source_code_directive.rb +49 -9
- data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
- 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/if_inside_else.rb +14 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -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/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +26 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -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/version.rb +2 -2
- metadata +13 -3
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
module Style
|
8
8
|
# This cop checks for non-ascii (non-English) characters
|
9
9
|
# in comments. You could set an array of allowed non-ascii chars in
|
10
|
-
# AllowedChars attribute (
|
10
|
+
# `AllowedChars` attribute (copyright notice "©" by default).
|
11
11
|
#
|
12
12
|
# @example
|
13
13
|
# # bad
|
@@ -9,37 +9,77 @@ module RuboCop
|
|
9
9
|
# This is useful if want to make sure that every RuboCop error gets fixed
|
10
10
|
# and not quickly disabled with a comment.
|
11
11
|
#
|
12
|
+
# Specific cops can be allowed with the `AllowedCops` configuration. Note that
|
13
|
+
# if this configuration is set, `rubocop:disable all` is still disallowed.
|
14
|
+
#
|
12
15
|
# @example
|
13
16
|
# # bad
|
14
17
|
# # rubocop:disable Metrics/AbcSize
|
15
|
-
# def
|
18
|
+
# def foo
|
16
19
|
# end
|
17
20
|
# # rubocop:enable Metrics/AbcSize
|
18
21
|
#
|
19
22
|
# # good
|
20
|
-
# def
|
23
|
+
# def foo
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @example AllowedCops: [Metrics/AbcSize]
|
27
|
+
# # good
|
28
|
+
# # rubocop:disable Metrics/AbcSize
|
29
|
+
# def foo
|
21
30
|
# end
|
31
|
+
# # rubocop:enable Metrics/AbcSize
|
22
32
|
#
|
23
33
|
class DisableCopsWithinSourceCodeDirective < Base
|
24
34
|
extend AutoCorrector
|
25
35
|
|
26
36
|
# rubocop:enable Lint/RedundantCopDisableDirective
|
27
|
-
MSG = '
|
37
|
+
MSG = 'Rubocop disable/enable directives are not permitted.'
|
38
|
+
MSG_FOR_COPS = 'Rubocop disable/enable directives for %<cops>s are not permitted.'
|
28
39
|
|
29
40
|
def on_new_investigation
|
30
41
|
processed_source.comments.each do |comment|
|
31
|
-
|
42
|
+
directive_cops = directive_cops(comment)
|
43
|
+
disallowed_cops = directive_cops - allowed_cops
|
32
44
|
|
33
|
-
|
34
|
-
|
35
|
-
|
45
|
+
next unless disallowed_cops.any?
|
46
|
+
|
47
|
+
register_offense(comment, directive_cops, disallowed_cops)
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
39
51
|
private
|
40
52
|
|
41
|
-
def
|
42
|
-
|
53
|
+
def register_offense(comment, directive_cops, disallowed_cops)
|
54
|
+
message = if any_cops_allowed?
|
55
|
+
format(MSG_FOR_COPS, cops: "`#{disallowed_cops.join('`, `')}`")
|
56
|
+
else
|
57
|
+
MSG
|
58
|
+
end
|
59
|
+
|
60
|
+
add_offense(comment, message: message) do |corrector|
|
61
|
+
replacement = ''
|
62
|
+
|
63
|
+
if directive_cops.length != disallowed_cops.length
|
64
|
+
replacement = comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
|
65
|
+
.sub(/,\s*$/, '')
|
66
|
+
end
|
67
|
+
|
68
|
+
corrector.replace(comment, replacement)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def directive_cops(comment)
|
73
|
+
match = CommentConfig::COMMENT_DIRECTIVE_REGEXP.match(comment.text)
|
74
|
+
match && match[2] ? match[2].split(',').map(&:strip) : []
|
75
|
+
end
|
76
|
+
|
77
|
+
def allowed_cops
|
78
|
+
Array(cop_config['AllowedCops'])
|
79
|
+
end
|
80
|
+
|
81
|
+
def any_cops_allowed?
|
82
|
+
allowed_cops.any?
|
43
83
|
end
|
44
84
|
end
|
45
85
|
end
|
@@ -3,9 +3,14 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# This cop ensures that eval methods (`eval`, `instance_eval`, `class_eval`
|
7
|
+
# and `module_eval`) are given filename and line number values (`__FILE__`
|
8
|
+
# and `__LINE__`). This data is used to ensure that any errors raised
|
9
|
+
# within the evaluated code will be given the correct identification
|
10
|
+
# in a backtrace.
|
11
|
+
#
|
12
|
+
# The cop also checks that the line number given relative to `__LINE__` is
|
13
|
+
# correct.
|
9
14
|
#
|
10
15
|
# @example
|
11
16
|
# # bad
|
@@ -32,27 +37,17 @@ module RuboCop
|
|
32
37
|
# end
|
33
38
|
# RUBY
|
34
39
|
class EvalWithLocation < Base
|
35
|
-
MSG = 'Pass `__FILE__` and `__LINE__` to
|
36
|
-
|
37
|
-
|
38
|
-
'
|
40
|
+
MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
|
41
|
+
MSG_EVAL = 'Pass a binding, `__FILE__` and `__LINE__` to `eval`.'
|
42
|
+
MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
|
43
|
+
'use `%<expected>s` instead of `%<actual>s`.'
|
44
|
+
MSG_INCORRECT_LINE = 'Incorrect line number for `%<method_name>s`; ' \
|
45
|
+
'use `%<expected>s` instead of `%<actual>s`.'
|
39
46
|
|
40
47
|
RESTRICT_ON_SEND = %i[eval class_eval module_eval instance_eval].freeze
|
41
48
|
|
42
|
-
def_node_matcher :
|
43
|
-
{
|
44
|
-
(send nil? :eval ${str dstr})
|
45
|
-
(send nil? :eval ${str dstr} _)
|
46
|
-
(send nil? :eval ${str dstr} _ #special_file_keyword?)
|
47
|
-
(send nil? :eval ${str dstr} _ #special_file_keyword? _)
|
48
|
-
|
49
|
-
(send _ {:class_eval :module_eval :instance_eval}
|
50
|
-
${str dstr})
|
51
|
-
(send _ {:class_eval :module_eval :instance_eval}
|
52
|
-
${str dstr} #special_file_keyword?)
|
53
|
-
(send _ {:class_eval :module_eval :instance_eval}
|
54
|
-
${str dstr} #special_file_keyword? _)
|
55
|
-
}
|
49
|
+
def_node_matcher :valid_eval_receiver?, <<~PATTERN
|
50
|
+
{ nil? (const {nil? cbase} :Kernel) }
|
56
51
|
PATTERN
|
57
52
|
|
58
53
|
def_node_matcher :line_with_offset?, <<~PATTERN
|
@@ -63,17 +58,31 @@ module RuboCop
|
|
63
58
|
PATTERN
|
64
59
|
|
65
60
|
def on_send(node)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
61
|
+
# Classes should not redefine eval, but in case one does, it shouldn't
|
62
|
+
# register an offense. Only `eval` without a receiver and `Kernel.eval`
|
63
|
+
# are considered.
|
64
|
+
return if node.method?(:eval) && !valid_eval_receiver?(node.receiver)
|
65
|
+
|
66
|
+
code = node.arguments.first
|
67
|
+
return unless code && (code.str_type? || code.dstr_type?)
|
68
|
+
|
69
|
+
file, line = file_and_line(node)
|
70
|
+
|
71
|
+
if line
|
72
|
+
check_file(node, file)
|
73
|
+
check_line(node, code)
|
74
|
+
else
|
75
|
+
register_offense(node)
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
75
79
|
private
|
76
80
|
|
81
|
+
def register_offense(node)
|
82
|
+
msg = node.method?(:eval) ? MSG_EVAL : format(MSG, method_name: node.method_name)
|
83
|
+
add_offense(node, message: msg)
|
84
|
+
end
|
85
|
+
|
77
86
|
def special_file_keyword?(node)
|
78
87
|
node.str_type? &&
|
79
88
|
node.source == '__FILE__'
|
@@ -84,6 +93,11 @@ module RuboCop
|
|
84
93
|
node.source == '__LINE__'
|
85
94
|
end
|
86
95
|
|
96
|
+
def file_and_line(node)
|
97
|
+
base = node.method?(:eval) ? 2 : 1
|
98
|
+
[node.arguments[base], node.arguments[base + 1]]
|
99
|
+
end
|
100
|
+
|
87
101
|
# FIXME: It's a Style/ConditionalAssignment's false positive.
|
88
102
|
# rubocop:disable Style/ConditionalAssignment
|
89
103
|
def with_lineno?(node)
|
@@ -95,17 +109,32 @@ module RuboCop
|
|
95
109
|
end
|
96
110
|
# rubocop:enable Style/ConditionalAssignment
|
97
111
|
|
98
|
-
def message_incorrect_line(actual, sign, line_diff)
|
112
|
+
def message_incorrect_line(method_name, actual, sign, line_diff)
|
99
113
|
expected =
|
100
114
|
if line_diff.zero?
|
101
115
|
'__LINE__'
|
102
116
|
else
|
103
117
|
"__LINE__ #{sign} #{line_diff}"
|
104
118
|
end
|
105
|
-
|
119
|
+
|
120
|
+
format(MSG_INCORRECT_LINE,
|
121
|
+
method_name: method_name,
|
122
|
+
actual: actual.source,
|
123
|
+
expected: expected)
|
124
|
+
end
|
125
|
+
|
126
|
+
def check_file(node, file_node)
|
127
|
+
return true if special_file_keyword?(file_node)
|
128
|
+
|
129
|
+
message = format(MSG_INCORRECT_FILE,
|
130
|
+
method_name: node.method_name,
|
131
|
+
expected: '__FILE__',
|
132
|
+
actual: file_node.source)
|
133
|
+
|
134
|
+
add_offense(file_node, message: message)
|
106
135
|
end
|
107
136
|
|
108
|
-
def
|
137
|
+
def check_line(node, code)
|
109
138
|
line_node = node.arguments.last
|
110
139
|
lineno_range = line_node.loc.expression
|
111
140
|
line_diff = string_first_line(code) - lineno_range.first_line
|
@@ -124,22 +153,22 @@ module RuboCop
|
|
124
153
|
end
|
125
154
|
end
|
126
155
|
|
127
|
-
def add_offense_for_same_line(
|
156
|
+
def add_offense_for_same_line(node, line_node)
|
128
157
|
return if special_line_keyword?(line_node)
|
129
158
|
|
130
159
|
add_offense(
|
131
160
|
line_node.loc.expression,
|
132
|
-
message: message_incorrect_line(line_node, nil, 0)
|
161
|
+
message: message_incorrect_line(node.method_name, line_node, nil, 0)
|
133
162
|
)
|
134
163
|
end
|
135
164
|
|
136
|
-
def add_offense_for_different_line(
|
165
|
+
def add_offense_for_different_line(node, line_node, line_diff)
|
137
166
|
sign = line_diff.positive? ? :+ : :-
|
138
167
|
return if line_with_offset?(line_node, sign, line_diff.abs)
|
139
168
|
|
140
169
|
add_offense(
|
141
170
|
line_node.loc.expression,
|
142
|
-
message: message_incorrect_line(line_node, sign, line_diff.abs)
|
171
|
+
message: message_incorrect_line(node.method_name, line_node, sign, line_diff.abs)
|
143
172
|
)
|
144
173
|
end
|
145
174
|
end
|
@@ -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
|
@@ -86,9 +86,10 @@ module RuboCop
|
|
86
86
|
correct_to_elsif_from_if_inside_else_form(corrector, node, node.condition)
|
87
87
|
end
|
88
88
|
corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
|
89
|
-
|
90
|
-
|
91
|
-
)
|
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)
|
92
93
|
end
|
93
94
|
|
94
95
|
def correct_to_elsif_from_modifier_form(corrector, node)
|
@@ -101,10 +102,12 @@ module RuboCop
|
|
101
102
|
|
102
103
|
def correct_to_elsif_from_if_inside_else_form(corrector, node, condition)
|
103
104
|
corrector.replace(node.parent.loc.else, "elsif #{condition.source}")
|
104
|
-
if_condition_range =
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
108
111
|
corrector.remove(condition)
|
109
112
|
end
|
110
113
|
|
@@ -115,6 +118,10 @@ module RuboCop
|
|
115
118
|
find_end_range(node.parent)
|
116
119
|
end
|
117
120
|
|
121
|
+
def if_condition_range(node, condition)
|
122
|
+
range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
|
123
|
+
end
|
124
|
+
|
118
125
|
def allow_if_modifier_in_else_branch?(else_branch)
|
119
126
|
allow_if_modifier? && else_branch&.modifier_form?
|
120
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
|