rubocop 0.91.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -5
- data/config/default.yml +143 -56
- data/lib/rubocop.rb +17 -5
- data/lib/rubocop/cached_data.rb +2 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/version.rb +1 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +19 -2
- data/lib/rubocop/config_loader_resolver.rb +7 -5
- data/lib/rubocop/config_regeneration.rb +33 -0
- data/lib/rubocop/config_validator.rb +7 -6
- data/lib/rubocop/cop/badge.rb +9 -24
- data/lib/rubocop/cop/base.rb +16 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +23 -3
- data/lib/rubocop/cop/commissioner.rb +36 -22
- data/lib/rubocop/cop/corrector.rb +3 -1
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/force.rb +1 -1
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +6 -9
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -7
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -3
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
- data/lib/rubocop/cop/lint/empty_block.rb +46 -0
- data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +17 -3
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
- data/lib/rubocop/cop/lint/to_json.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/metrics/block_length.rb +3 -1
- data/lib/rubocop/cop/metrics/class_length.rb +14 -6
- data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
- data/lib/rubocop/cop/offense.rb +18 -5
- data/lib/rubocop/cop/security/open.rb +12 -10
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
- data/lib/rubocop/cop/style/array_coercion.rb +4 -0
- data/lib/rubocop/cop/style/case_like_if.rb +20 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
- data/lib/rubocop/cop/style/date_time.rb +12 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +67 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
- data/lib/rubocop/cop/style/for.rb +0 -4
- data/lib/rubocop/cop/style/format_string_token.rb +48 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
- data/lib/rubocop/cop/style/mixin_usage.rb +7 -27
- data/lib/rubocop/cop/style/multiple_comparison.rb +54 -7
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +11 -3
- data/lib/rubocop/cop/style/raise_args.rb +0 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +45 -24
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
- data/lib/rubocop/cop/style/redundant_self.rb +3 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
- data/lib/rubocop/cop/style/semicolon.rb +3 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
- data/lib/rubocop/cop/style/swap_values.rb +108 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/team.rb +6 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +0 -4
- data/lib/rubocop/ext/regexp_node.rb +29 -10
- data/lib/rubocop/ext/regexp_parser.rb +77 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +12 -5
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +2 -2
- data/lib/rubocop/options.rb +22 -17
- data/lib/rubocop/result_cache.rb +8 -2
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +5 -5
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/runner.rb +9 -5
- data/lib/rubocop/target_finder.rb +27 -26
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +61 -6
- metadata +21 -16
- data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# By default it enforces accessors to be placed in grouped declarations,
|
8
8
|
# but it can be configured to enforce separating them in multiple declarations.
|
9
9
|
#
|
10
|
+
# NOTE: `Sorbet` is not compatible with "grouped" style. Consider "separated" style
|
11
|
+
# or disabling this cop.
|
12
|
+
#
|
10
13
|
# @example EnforcedStyle: grouped (default)
|
11
14
|
# # bad
|
12
15
|
# class Foo
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# In Ruby 2.7, arguments forwarding has been added.
|
7
|
+
#
|
8
|
+
# This cop identifies places where `do_something(*args, &block)`
|
9
|
+
# can be replaced by `do_something(...)`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# def foo(*args, &block)
|
14
|
+
# bar(*args, &block)
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# def foo(*args, **kwargs, &block)
|
19
|
+
# bar(*args, **kwargs, &block)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# def foo(...)
|
24
|
+
# bar(...)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example AllowOnlyRestArgument: true (default)
|
28
|
+
# # good
|
29
|
+
# def foo(*args)
|
30
|
+
# bar(*args)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @example AllowOnlyRestArgument: false
|
34
|
+
# # bad
|
35
|
+
# # The following code can replace the arguments with `...`,
|
36
|
+
# # but it will change the behavior. Because `...` forwards block also.
|
37
|
+
# def foo(*args)
|
38
|
+
# bar(*args)
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
class ArgumentsForwarding < Base
|
42
|
+
include RangeHelp
|
43
|
+
extend AutoCorrector
|
44
|
+
extend TargetRubyVersion
|
45
|
+
|
46
|
+
minimum_target_ruby_version 2.7
|
47
|
+
|
48
|
+
MSG = 'Use arguments forwarding.'
|
49
|
+
|
50
|
+
def_node_matcher :use_rest_arguments?, <<~PATTERN
|
51
|
+
(args (restarg $_) $...)
|
52
|
+
PATTERN
|
53
|
+
|
54
|
+
def_node_matcher :only_rest_arguments?, <<~PATTERN
|
55
|
+
(send _ _ (splat (lvar %1)))
|
56
|
+
PATTERN
|
57
|
+
|
58
|
+
def_node_matcher :forwarding_method_arguments?, <<~PATTERN
|
59
|
+
{
|
60
|
+
(send _ _
|
61
|
+
(splat (lvar %1))
|
62
|
+
(block-pass (lvar %2)))
|
63
|
+
(send _ _
|
64
|
+
(splat (lvar %1))
|
65
|
+
(hash (kwsplat (lvar %3)))
|
66
|
+
(block-pass (lvar %2)))
|
67
|
+
}
|
68
|
+
PATTERN
|
69
|
+
|
70
|
+
def on_def(node)
|
71
|
+
return unless node.body
|
72
|
+
return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
|
73
|
+
|
74
|
+
node.each_descendant(:send) do |send_node|
|
75
|
+
kwargs_name, block_name = extract_argument_names_from(args)
|
76
|
+
|
77
|
+
next unless forwarding_method?(send_node, rest_args_name, kwargs_name, block_name) &&
|
78
|
+
all_lvars_as_forwarding_method_arguments?(node, send_node)
|
79
|
+
|
80
|
+
register_offense_to_forwarding_method_arguments(send_node)
|
81
|
+
register_offense_to_method_definition_arguments(node)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias on_defs on_def
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def extract_argument_names_from(args)
|
89
|
+
kwargs_name = args.first.source.delete('**') if args.first&.kwrestarg_type?
|
90
|
+
block_arg_name = args.last.source.delete('&') if args.last&.blockarg_type?
|
91
|
+
|
92
|
+
[kwargs_name, block_arg_name].map { |name| name&.to_sym }
|
93
|
+
end
|
94
|
+
|
95
|
+
def forwarding_method?(node, rest_arg, kwargs, block_arg)
|
96
|
+
return only_rest_arguments?(node, rest_arg) unless allow_only_rest_arguments?
|
97
|
+
|
98
|
+
forwarding_method_arguments?(node, rest_arg, block_arg, kwargs)
|
99
|
+
end
|
100
|
+
|
101
|
+
def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method)
|
102
|
+
lvars = def_node.body.each_descendant(:lvar, :lvasgn)
|
103
|
+
|
104
|
+
begin_pos = forwarding_method.source_range.begin_pos
|
105
|
+
end_pos = forwarding_method.source_range.end_pos
|
106
|
+
|
107
|
+
lvars.all? do |lvar|
|
108
|
+
lvar.source_range.begin_pos.between?(begin_pos, end_pos)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def register_offense_to_forwarding_method_arguments(forwarding_method)
|
113
|
+
add_offense(arguments_range(forwarding_method)) do |corrector|
|
114
|
+
range = range_between(
|
115
|
+
forwarding_method.loc.selector.end_pos, forwarding_method.source_range.end_pos
|
116
|
+
)
|
117
|
+
corrector.replace(range, '(...)')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def register_offense_to_method_definition_arguments(method_definition)
|
122
|
+
add_offense(arguments_range(method_definition)) do |corrector|
|
123
|
+
arguments_range = range_with_surrounding_space(
|
124
|
+
range: method_definition.arguments.source_range, side: :left
|
125
|
+
)
|
126
|
+
corrector.replace(arguments_range, '(...)')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def arguments_range(node)
|
131
|
+
arguments = node.arguments
|
132
|
+
|
133
|
+
range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
|
134
|
+
end
|
135
|
+
|
136
|
+
def allow_only_rest_arguments?
|
137
|
+
cop_config.fetch('AllowOnlyRestArgument', true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -5,6 +5,10 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`.
|
7
7
|
#
|
8
|
+
# This cop is disabled by default because false positive will occur if
|
9
|
+
# the argument of `Array()` is not an array (e.g. Hash, Set),
|
10
|
+
# an array will be returned as an incompatibility result.
|
11
|
+
#
|
8
12
|
# @example
|
9
13
|
# # bad
|
10
14
|
# paths = [paths] unless paths.is_a?(Array)
|
@@ -42,6 +42,8 @@ module RuboCop
|
|
42
42
|
convertible = true
|
43
43
|
|
44
44
|
branch_conditions(node).each do |branch_condition|
|
45
|
+
return false if regexp_with_working_captures?(branch_condition)
|
46
|
+
|
45
47
|
conditions << []
|
46
48
|
convertible = collect_conditions(branch_condition, target, conditions.last)
|
47
49
|
break unless convertible
|
@@ -49,9 +51,7 @@ module RuboCop
|
|
49
51
|
|
50
52
|
return unless convertible
|
51
53
|
|
52
|
-
add_offense(node)
|
53
|
-
autocorrect(corrector, node)
|
54
|
-
end
|
54
|
+
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
55
55
|
end
|
56
56
|
|
57
57
|
private
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
when :include?, :cover?
|
108
108
|
receiver = deparenthesize(node.receiver)
|
109
109
|
node.arguments.first if receiver.range_type?
|
110
|
-
when :match, :match
|
110
|
+
when :match, :match?, :=~
|
111
111
|
find_target_in_match_node(node)
|
112
112
|
end
|
113
113
|
end
|
@@ -230,6 +230,22 @@ module RuboCop
|
|
230
230
|
def indent(node)
|
231
231
|
' ' * node.loc.column
|
232
232
|
end
|
233
|
+
|
234
|
+
# Named captures work with `=~` (if regexp is on lhs) and with `match` (both sides)
|
235
|
+
def regexp_with_working_captures?(node)
|
236
|
+
case node.type
|
237
|
+
when :match_with_lvasgn
|
238
|
+
lhs, _rhs = *node
|
239
|
+
node.loc.selector.source == '=~' && regexp_with_named_captures?(lhs)
|
240
|
+
when :send
|
241
|
+
lhs, method, rhs = *node
|
242
|
+
method == :match && [lhs, rhs].any? { |n| regexp_with_named_captures?(n) }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def regexp_with_named_captures?(node)
|
247
|
+
node.regexp_type? && node.each_capture(named: true).count.positive?
|
248
|
+
end
|
233
249
|
end
|
234
250
|
end
|
235
251
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop enforces the use of `Object#instance_of?` instead of class comparison
|
7
|
+
# for equality.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# var.class == Date
|
12
|
+
# var.class.equal?(Date)
|
13
|
+
# var.class.eql?(Date)
|
14
|
+
# var.class.name == 'Date'
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# var.instance_of?(Date)
|
18
|
+
#
|
19
|
+
class ClassEqualityComparison < Base
|
20
|
+
include RangeHelp
|
21
|
+
include IgnoredMethods
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG = 'Use `instance_of?(%<class_name>s)` instead of comparing classes.'
|
25
|
+
|
26
|
+
RESTRICT_ON_SEND = %i[== equal? eql?].freeze
|
27
|
+
|
28
|
+
def_node_matcher :class_comparison_candidate?, <<~PATTERN
|
29
|
+
(send
|
30
|
+
{$(send _ :class) (send $(send _ :class) :name)}
|
31
|
+
{:== :equal? :eql?} $_)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_send(node)
|
35
|
+
def_node = node.each_ancestor(:def, :defs).first
|
36
|
+
return if def_node && ignored_method?(def_node.method_name)
|
37
|
+
|
38
|
+
class_comparison_candidate?(node) do |receiver_node, class_node|
|
39
|
+
range = offense_range(receiver_node, node)
|
40
|
+
class_name = class_name(class_node, node)
|
41
|
+
|
42
|
+
add_offense(range, message: format(MSG, class_name: class_name)) do |corrector|
|
43
|
+
corrector.replace(range, "instance_of?(#{class_name})")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def class_name(class_node, node)
|
51
|
+
if node.children.first.method?(:name)
|
52
|
+
class_node.source.delete('"').delete("'")
|
53
|
+
else
|
54
|
+
class_node.source
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def offense_range(receiver_node, node)
|
59
|
+
range_between(receiver_node.loc.selector.begin_pos, node.source_range.end_pos)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -49,6 +49,12 @@ module RuboCop
|
|
49
49
|
# end
|
50
50
|
# end
|
51
51
|
#
|
52
|
+
# # good
|
53
|
+
# def method
|
54
|
+
# each_slice(2) { |slice| do_something(slice) }
|
55
|
+
# each_slice(3) { |slice| do_something(slice) }
|
56
|
+
# end
|
57
|
+
#
|
52
58
|
class CombinableLoops < Base
|
53
59
|
MSG = 'Combine this loop with the previous loop.'
|
54
60
|
|
@@ -76,7 +82,8 @@ module RuboCop
|
|
76
82
|
def same_collection_looping?(node, sibling)
|
77
83
|
sibling&.block_type? &&
|
78
84
|
sibling.send_node.method?(node.method_name) &&
|
79
|
-
sibling.send_node.receiver == node.send_node.receiver
|
85
|
+
sibling.send_node.receiver == node.send_node.receiver &&
|
86
|
+
sibling.send_node.arguments == node.send_node.arguments
|
80
87
|
end
|
81
88
|
end
|
82
89
|
end
|
@@ -6,6 +6,12 @@ module RuboCop
|
|
6
6
|
# This cop checks that comment annotation keywords are written according
|
7
7
|
# to guidelines.
|
8
8
|
#
|
9
|
+
# NOTE: With a multiline comment block (where each line is only a
|
10
|
+
# comment), only the first line will be able to register an offense, even
|
11
|
+
# if an annotation keyword starts another line. This is done to prevent
|
12
|
+
# incorrect registering of keywords (eg. `review`) inside a paragraph as an
|
13
|
+
# annotation.
|
14
|
+
#
|
9
15
|
# @example
|
10
16
|
# # bad
|
11
17
|
# # TODO make better
|
@@ -42,6 +42,8 @@ module RuboCop
|
|
42
42
|
# # good
|
43
43
|
# something.to_time
|
44
44
|
class DateTime < Base
|
45
|
+
extend AutoCorrector
|
46
|
+
|
45
47
|
CLASS_MSG = 'Prefer Time over DateTime.'
|
46
48
|
COERCION_MSG = 'Do not use #to_datetime.'
|
47
49
|
|
@@ -63,7 +65,10 @@ module RuboCop
|
|
63
65
|
return if historic_date?(node)
|
64
66
|
|
65
67
|
message = to_datetime?(node) ? COERCION_MSG : CLASS_MSG
|
66
|
-
|
68
|
+
|
69
|
+
add_offense(node, message: message) do |corrector|
|
70
|
+
autocorrect(corrector, node)
|
71
|
+
end
|
67
72
|
end
|
68
73
|
|
69
74
|
private
|
@@ -71,6 +76,12 @@ module RuboCop
|
|
71
76
|
def disallow_coercion?
|
72
77
|
!cop_config['AllowCoercion']
|
73
78
|
end
|
79
|
+
|
80
|
+
def autocorrect(corrector, node)
|
81
|
+
return if to_datetime?(node)
|
82
|
+
|
83
|
+
corrector.replace(node.receiver.loc.name, 'Time')
|
84
|
+
end
|
74
85
|
end
|
75
86
|
end
|
76
87
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# When using `class_eval` (or other `eval`) with string interpolation,
|
7
|
+
# add a comment block showing its appearance if interpolated (a practice used in Rails code).
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # from activesupport/lib/active_support/core_ext/string/output_safety.rb
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# UNSAFE_STRING_METHODS.each do |unsafe_method|
|
14
|
+
# if 'String'.respond_to?(unsafe_method)
|
15
|
+
# class_eval <<-EOT, __FILE__, __LINE__ + 1
|
16
|
+
# def #{unsafe_method}(*params, &block)
|
17
|
+
# to_str.#{unsafe_method}(*params, &block)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def #{unsafe_method}!(*params)
|
21
|
+
# @dirty = true
|
22
|
+
# super
|
23
|
+
# end
|
24
|
+
# EOT
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# UNSAFE_STRING_METHODS.each do |unsafe_method|
|
30
|
+
# if 'String'.respond_to?(unsafe_method)
|
31
|
+
# class_eval <<-EOT, __FILE__, __LINE__ + 1
|
32
|
+
# def #{unsafe_method}(*params, &block) # def capitalize(*params, &block)
|
33
|
+
# to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block)
|
34
|
+
# end # end
|
35
|
+
#
|
36
|
+
# def #{unsafe_method}!(*params) # def capitalize!(*params)
|
37
|
+
# @dirty = true # @dirty = true
|
38
|
+
# super # super
|
39
|
+
# end # end
|
40
|
+
# EOT
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
class DocumentDynamicEvalDefinition < Base
|
45
|
+
MSG = 'Add a comment block showing its appearance if interpolated.'
|
46
|
+
|
47
|
+
RESTRICT_ON_SEND = %i[eval class_eval module_eval instance_eval].freeze
|
48
|
+
|
49
|
+
def on_send(node)
|
50
|
+
arg_node = node.first_argument
|
51
|
+
return unless arg_node&.dstr_type?
|
52
|
+
|
53
|
+
add_offense(node.loc.selector) unless comment_docs?(arg_node)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def comment_docs?(node)
|
59
|
+
node.each_child_node(:begin).all? do |begin_node|
|
60
|
+
source_line = processed_source.lines[begin_node.first_line - 1]
|
61
|
+
source_line.match?(/\s*#[^{]+/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -57,12 +57,16 @@ module RuboCop
|
|
57
57
|
yielding_block?(block_node) do |send_node, block_args, yield_args|
|
58
58
|
return unless yielding_arguments?(block_args, yield_args)
|
59
59
|
|
60
|
+
def_node = block_node.each_ancestor(:def, :defs).first
|
61
|
+
# if `yield` is being called outside of a method context, ignore
|
62
|
+
# this is not a valid ruby pattern, but can happen in haml or erb,
|
63
|
+
# so this can cause crashes in haml_lint
|
64
|
+
return unless def_node
|
65
|
+
|
60
66
|
add_offense(block_node) do |corrector|
|
61
67
|
corrector.remove(block_body_range(block_node, send_node))
|
62
68
|
|
63
69
|
add_block_argument(send_node, corrector)
|
64
|
-
|
65
|
-
def_node = block_node.each_ancestor(:def, :defs).first
|
66
70
|
add_block_argument(def_node, corrector) if @def_nodes.add?(def_node)
|
67
71
|
end
|
68
72
|
end
|
@@ -49,8 +49,6 @@ module RuboCop
|
|
49
49
|
|
50
50
|
def on_for(node)
|
51
51
|
if style == :each
|
52
|
-
return unless opposite_style_detected
|
53
|
-
|
54
52
|
add_offense(node, message: PREFER_EACH) do |corrector|
|
55
53
|
ForToEachCorrector.new(node).call(corrector)
|
56
54
|
end
|
@@ -63,8 +61,6 @@ module RuboCop
|
|
63
61
|
return unless suspect_enumerable?(node)
|
64
62
|
|
65
63
|
if style == :for
|
66
|
-
return unless opposite_style_detected
|
67
|
-
|
68
64
|
add_offense(node, message: PREFER_FOR) do |corrector|
|
69
65
|
EachToForCorrector.new(node).call(corrector)
|
70
66
|
end
|