rubocop 0.67.2 → 0.68.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 +1 -1
- data/config/default.yml +86 -233
- data/exe/rubocop +0 -12
- data/lib/rubocop.rb +13 -30
- data/lib/rubocop/ast/builder.rb +4 -0
- data/lib/rubocop/ast/node/alias_node.rb +24 -0
- data/lib/rubocop/ast/node/class_node.rb +31 -0
- data/lib/rubocop/ast/node/module_node.rb +24 -0
- data/lib/rubocop/ast/node/range_node.rb +7 -0
- data/lib/rubocop/ast/node/resbody_node.rb +12 -0
- data/lib/rubocop/ast/node/self_class_node.rb +24 -0
- data/lib/rubocop/cli.rb +40 -4
- data/lib/rubocop/config.rb +9 -7
- data/lib/rubocop/config_loader.rb +48 -7
- data/lib/rubocop/config_loader_resolver.rb +5 -4
- data/lib/rubocop/cop/commissioner.rb +24 -0
- data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +18 -6
- data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +12 -14
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +9 -20
- data/lib/rubocop/cop/layout/align_arguments.rb +93 -0
- data/lib/rubocop/cop/layout/align_parameters.rb +57 -33
- data/lib/rubocop/cop/layout/class_structure.rb +5 -5
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -8
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +3 -6
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +1 -2
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +292 -0
- data/lib/rubocop/cop/layout/{first_parameter_indentation.rb → indent_first_argument.rb} +11 -12
- data/lib/rubocop/cop/layout/{indent_array.rb → indent_first_array_element.rb} +2 -2
- data/lib/rubocop/cop/layout/{indent_hash.rb → indent_first_hash_element.rb} +2 -2
- data/lib/rubocop/cop/layout/indent_first_parameter.rb +96 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -16
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -4
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -16
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +6 -8
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +4 -8
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +157 -0
- data/lib/rubocop/cop/lint/inherit_exception.rb +3 -4
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -5
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +25 -5
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -6
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -2
- data/lib/rubocop/cop/message_annotator.rb +1 -0
- data/lib/rubocop/cop/metrics/line_length.rb +139 -28
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +3 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +190 -0
- data/lib/rubocop/cop/mixin/{array_hash_indentation.rb → multiline_element_indentation.rb} +3 -2
- data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -7
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +33 -4
- data/lib/rubocop/cop/rails/active_record_override.rb +23 -8
- data/lib/rubocop/cop/rails/delegate.rb +5 -8
- data/lib/rubocop/cop/rails/environment_comparison.rb +5 -3
- data/lib/rubocop/cop/rails/find_each.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
- data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/skips_model_validations.rb +6 -7
- data/lib/rubocop/cop/rails/time_zone.rb +3 -10
- data/lib/rubocop/cop/rails/validation.rb +3 -0
- data/lib/rubocop/cop/registry.rb +3 -3
- data/lib/rubocop/cop/style/alias.rb +13 -7
- data/lib/rubocop/cop/style/block_delimiters.rb +20 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -21
- data/lib/rubocop/cop/style/class_methods.rb +16 -24
- data/lib/rubocop/cop/style/conditional_assignment.rb +20 -49
- data/lib/rubocop/cop/style/documentation.rb +3 -7
- data/lib/rubocop/cop/style/format_string.rb +18 -21
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +4 -0
- data/lib/rubocop/cop/style/lambda.rb +12 -8
- data/lib/rubocop/cop/style/mixin_grouping.rb +8 -10
- data/lib/rubocop/cop/style/module_function.rb +2 -3
- data/lib/rubocop/cop/style/next.rb +10 -14
- data/lib/rubocop/cop/style/one_line_conditional.rb +5 -3
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -4
- data/lib/rubocop/cop/style/random_with_offset.rb +44 -47
- data/lib/rubocop/cop/style/redundant_return.rb +6 -14
- data/lib/rubocop/cop/style/redundant_sort_by.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +3 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +2 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +20 -40
- data/lib/rubocop/cop/style/unless_else.rb +1 -2
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -7
- data/lib/rubocop/cop/util.rb +2 -4
- data/lib/rubocop/file_finder.rb +5 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -0
- data/lib/rubocop/node_pattern.rb +304 -170
- data/lib/rubocop/options.rb +4 -1
- data/lib/rubocop/rspec/shared_contexts.rb +3 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +1 -1
- metadata +26 -50
- data/lib/rubocop/cop/performance/caller.rb +0 -69
- data/lib/rubocop/cop/performance/case_when_splat.rb +0 -177
- data/lib/rubocop/cop/performance/casecmp.rb +0 -108
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +0 -78
- data/lib/rubocop/cop/performance/compare_with_block.rb +0 -122
- data/lib/rubocop/cop/performance/count.rb +0 -102
- data/lib/rubocop/cop/performance/detect.rb +0 -110
- data/lib/rubocop/cop/performance/double_start_end_with.rb +0 -94
- data/lib/rubocop/cop/performance/end_with.rb +0 -56
- data/lib/rubocop/cop/performance/fixed_size.rb +0 -97
- data/lib/rubocop/cop/performance/flat_map.rb +0 -78
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +0 -99
- data/lib/rubocop/cop/performance/open_struct.rb +0 -46
- data/lib/rubocop/cop/performance/range_include.rb +0 -50
- data/lib/rubocop/cop/performance/redundant_block_call.rb +0 -93
- data/lib/rubocop/cop/performance/redundant_match.rb +0 -56
- data/lib/rubocop/cop/performance/redundant_merge.rb +0 -183
- data/lib/rubocop/cop/performance/regexp_match.rb +0 -265
- data/lib/rubocop/cop/performance/reverse_each.rb +0 -42
- data/lib/rubocop/cop/performance/size.rb +0 -77
- data/lib/rubocop/cop/performance/start_with.rb +0 -59
- data/lib/rubocop/cop/performance/string_replacement.rb +0 -173
- data/lib/rubocop/cop/performance/times_map.rb +0 -71
- data/lib/rubocop/cop/performance/unfreeze_string.rb +0 -50
- data/lib/rubocop/cop/performance/uri_default_parser.rb +0 -47
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# This cop checks for double `#start_with?` or `#end_with?` calls
|
7
|
-
# separated by `||`. In some cases such calls can be replaced
|
8
|
-
# with an single `#start_with?`/`#end_with?` call.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# # bad
|
12
|
-
# str.start_with?("a") || str.start_with?(Some::CONST)
|
13
|
-
# str.start_with?("a", "b") || str.start_with?("c")
|
14
|
-
# str.end_with?(var1) || str.end_with?(var2)
|
15
|
-
#
|
16
|
-
# # good
|
17
|
-
# str.start_with?("a", Some::CONST)
|
18
|
-
# str.start_with?("a", "b", "c")
|
19
|
-
# str.end_with?(var1, var2)
|
20
|
-
class DoubleStartEndWith < Cop
|
21
|
-
MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` ' \
|
22
|
-
'instead of `%<original_code>s`.'.freeze
|
23
|
-
|
24
|
-
def on_or(node)
|
25
|
-
receiver,
|
26
|
-
method,
|
27
|
-
first_call_args,
|
28
|
-
second_call_args = process_source(node)
|
29
|
-
|
30
|
-
return unless receiver && second_call_args.all?(&:pure?)
|
31
|
-
|
32
|
-
combined_args = combine_args(first_call_args, second_call_args)
|
33
|
-
|
34
|
-
add_offense_for_double_call(node, receiver, method, combined_args)
|
35
|
-
end
|
36
|
-
|
37
|
-
def autocorrect(node)
|
38
|
-
_receiver, _method,
|
39
|
-
first_call_args, second_call_args = process_source(node)
|
40
|
-
|
41
|
-
combined_args = combine_args(first_call_args, second_call_args)
|
42
|
-
first_argument = first_call_args.first.loc.expression
|
43
|
-
last_argument = second_call_args.last.loc.expression
|
44
|
-
range = first_argument.join(last_argument)
|
45
|
-
|
46
|
-
lambda do |corrector|
|
47
|
-
corrector.replace(range, combined_args)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def process_source(node)
|
54
|
-
if check_for_active_support_aliases?
|
55
|
-
check_with_active_support_aliases(node)
|
56
|
-
else
|
57
|
-
two_start_end_with_calls(node)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def combine_args(first_call_args, second_call_args)
|
62
|
-
(first_call_args + second_call_args).map(&:source).join(', ')
|
63
|
-
end
|
64
|
-
|
65
|
-
def add_offense_for_double_call(node, receiver, method, combined_args)
|
66
|
-
msg = format(MSG, receiver: receiver.source,
|
67
|
-
method: method,
|
68
|
-
combined_args: combined_args,
|
69
|
-
original_code: node.source)
|
70
|
-
|
71
|
-
add_offense(node, message: msg)
|
72
|
-
end
|
73
|
-
|
74
|
-
def check_for_active_support_aliases?
|
75
|
-
cop_config['IncludeActiveSupportAliases']
|
76
|
-
end
|
77
|
-
|
78
|
-
def_node_matcher :two_start_end_with_calls, <<-PATTERN
|
79
|
-
(or
|
80
|
-
(send $_recv [{:start_with? :end_with?} $_method] $...)
|
81
|
-
(send _recv _method $...))
|
82
|
-
PATTERN
|
83
|
-
|
84
|
-
def_node_matcher :check_with_active_support_aliases, <<-PATTERN
|
85
|
-
(or
|
86
|
-
(send $_recv
|
87
|
-
[{:start_with? :starts_with? :end_with? :ends_with?} $_method]
|
88
|
-
$...)
|
89
|
-
(send _recv _method $...))
|
90
|
-
PATTERN
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# This cop identifies unnecessary use of a regex where `String#end_with?`
|
7
|
-
# would suffice.
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# # bad
|
11
|
-
# 'abc'.match?(/bc\Z/)
|
12
|
-
# 'abc' =~ /bc\Z/
|
13
|
-
# 'abc'.match(/bc\Z/)
|
14
|
-
#
|
15
|
-
# # good
|
16
|
-
# 'abc'.end_with?('bc')
|
17
|
-
class EndWith < Cop
|
18
|
-
MSG = 'Use `String#end_with?` instead of a regex match anchored to ' \
|
19
|
-
'the end of the string.'.freeze
|
20
|
-
SINGLE_QUOTE = "'".freeze
|
21
|
-
|
22
|
-
def_node_matcher :redundant_regex?, <<-PATTERN
|
23
|
-
{(send $!nil? {:match :=~ :match?} (regexp (str $#literal_at_end?) (regopt)))
|
24
|
-
(send (regexp (str $#literal_at_end?) (regopt)) {:match :=~} $_)}
|
25
|
-
PATTERN
|
26
|
-
|
27
|
-
def literal_at_end?(regex_str)
|
28
|
-
# is this regexp 'literal' in the sense of only matching literal
|
29
|
-
# chars, rather than using metachars like . and * and so on?
|
30
|
-
# also, is it anchored at the end of the string?
|
31
|
-
regex_str =~ /\A(?:#{LITERAL_REGEX})+\\z\z/
|
32
|
-
end
|
33
|
-
|
34
|
-
def on_send(node)
|
35
|
-
return unless redundant_regex?(node)
|
36
|
-
|
37
|
-
add_offense(node)
|
38
|
-
end
|
39
|
-
|
40
|
-
def autocorrect(node)
|
41
|
-
redundant_regex?(node) do |receiver, regex_str|
|
42
|
-
receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
|
43
|
-
regex_str = regex_str[0..-3] # drop \Z anchor
|
44
|
-
regex_str = interpret_string_escapes(regex_str)
|
45
|
-
|
46
|
-
lambda do |corrector|
|
47
|
-
new_source = receiver.source + '.end_with?(' +
|
48
|
-
to_string_literal(regex_str) + ')'
|
49
|
-
corrector.replace(node.source_range, new_source)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# Do not compute the size of statically sized objects.
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# # String methods
|
10
|
-
# # bad
|
11
|
-
# 'foo'.size
|
12
|
-
# %q[bar].count
|
13
|
-
# %(qux).length
|
14
|
-
#
|
15
|
-
# # Symbol methods
|
16
|
-
# # bad
|
17
|
-
# :fred.size
|
18
|
-
# :'baz'.length
|
19
|
-
#
|
20
|
-
# # Array methods
|
21
|
-
# # bad
|
22
|
-
# [1, 2, thud].count
|
23
|
-
# %W(1, 2, bar).size
|
24
|
-
#
|
25
|
-
# # Hash methods
|
26
|
-
# # bad
|
27
|
-
# { a: corge, b: grault }.length
|
28
|
-
#
|
29
|
-
# # good
|
30
|
-
# foo.size
|
31
|
-
# bar.count
|
32
|
-
# qux.length
|
33
|
-
#
|
34
|
-
# # good
|
35
|
-
# :"#{fred}".size
|
36
|
-
# CONST = :baz.length
|
37
|
-
#
|
38
|
-
# # good
|
39
|
-
# [1, 2, *thud].count
|
40
|
-
# garply = [1, 2, 3]
|
41
|
-
# garly.size
|
42
|
-
#
|
43
|
-
# # good
|
44
|
-
# { a: corge, **grault }.length
|
45
|
-
# waldo = { a: corge, b: grault }
|
46
|
-
# waldo.size
|
47
|
-
#
|
48
|
-
class FixedSize < Cop
|
49
|
-
MSG = 'Do not compute the size of statically sized objects.'.freeze
|
50
|
-
|
51
|
-
def_node_matcher :counter, <<-MATCHER
|
52
|
-
(send ${array hash str sym} {:count :length :size} $...)
|
53
|
-
MATCHER
|
54
|
-
|
55
|
-
def on_send(node)
|
56
|
-
return if allowed_parent?(node.parent)
|
57
|
-
|
58
|
-
counter(node) do |var, arg|
|
59
|
-
return if allowed_variable?(var) || allowed_argument?(arg)
|
60
|
-
|
61
|
-
add_offense(node)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def allowed_variable?(var)
|
68
|
-
contains_splat?(var) || contains_double_splat?(var)
|
69
|
-
end
|
70
|
-
|
71
|
-
def allowed_argument?(arg)
|
72
|
-
arg && non_string_argument?(arg.first)
|
73
|
-
end
|
74
|
-
|
75
|
-
def allowed_parent?(node)
|
76
|
-
node && (node.casgn_type? || node.block_type?)
|
77
|
-
end
|
78
|
-
|
79
|
-
def contains_splat?(node)
|
80
|
-
return unless node.array_type?
|
81
|
-
|
82
|
-
node.each_child_node(:splat).any?
|
83
|
-
end
|
84
|
-
|
85
|
-
def contains_double_splat?(node)
|
86
|
-
return unless node.hash_type?
|
87
|
-
|
88
|
-
node.each_child_node(:kwsplat).any?
|
89
|
-
end
|
90
|
-
|
91
|
-
def non_string_argument?(node)
|
92
|
-
node && !node.str_type?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# This cop is used to identify usages of
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# # bad
|
10
|
-
# [1, 2, 3, 4].map { |e| [e, e] }.flatten(1)
|
11
|
-
# [1, 2, 3, 4].collect { |e| [e, e] }.flatten(1)
|
12
|
-
#
|
13
|
-
# # good
|
14
|
-
# [1, 2, 3, 4].flat_map { |e| [e, e] }
|
15
|
-
# [1, 2, 3, 4].map { |e| [e, e] }.flatten
|
16
|
-
# [1, 2, 3, 4].collect { |e| [e, e] }.flatten
|
17
|
-
class FlatMap < Cop
|
18
|
-
include RangeHelp
|
19
|
-
|
20
|
-
MSG = 'Use `flat_map` instead of `%<method>s...%<flatten>s`.'.freeze
|
21
|
-
FLATTEN_MULTIPLE_LEVELS = ' Beware, `flat_map` only flattens 1 level ' \
|
22
|
-
'and `flatten` can be used to flatten ' \
|
23
|
-
'multiple levels.'.freeze
|
24
|
-
|
25
|
-
def_node_matcher :flat_map_candidate?, <<-PATTERN
|
26
|
-
(send (block $(send _ ${:collect :map}) ...) ${:flatten :flatten!} $...)
|
27
|
-
PATTERN
|
28
|
-
|
29
|
-
def on_send(node)
|
30
|
-
flat_map_candidate?(node) do |map_node, first_method, flatten, params|
|
31
|
-
flatten_level, = *params.first
|
32
|
-
if cop_config['EnabledForFlattenWithoutParams'] && !flatten_level
|
33
|
-
offense_for_levels(node, map_node, first_method, flatten)
|
34
|
-
elsif flatten_level == 1
|
35
|
-
offense_for_method(node, map_node, first_method, flatten)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def autocorrect(node)
|
41
|
-
map_node, _first_method, _flatten, params = flat_map_candidate?(node)
|
42
|
-
flatten_level, = *params.first
|
43
|
-
|
44
|
-
return unless flatten_level
|
45
|
-
|
46
|
-
range = range_between(node.loc.dot.begin_pos,
|
47
|
-
node.source_range.end_pos)
|
48
|
-
|
49
|
-
lambda do |corrector|
|
50
|
-
corrector.remove(range)
|
51
|
-
corrector.replace(map_node.loc.selector, 'flat_map')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def offense_for_levels(node, map_node, first_method, flatten)
|
58
|
-
message = MSG + FLATTEN_MULTIPLE_LEVELS
|
59
|
-
register_offense(node, map_node, first_method, flatten, message)
|
60
|
-
end
|
61
|
-
|
62
|
-
def offense_for_method(node, map_node, first_method, flatten)
|
63
|
-
register_offense(node, map_node, first_method, flatten, MSG)
|
64
|
-
end
|
65
|
-
|
66
|
-
def register_offense(node, map_node, first_method, flatten, message)
|
67
|
-
range = range_between(map_node.loc.selector.begin_pos,
|
68
|
-
node.loc.expression.end_pos)
|
69
|
-
|
70
|
-
add_offense(node,
|
71
|
-
location: range,
|
72
|
-
message: format(message, method: first_method,
|
73
|
-
flatten: flatten))
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# This cop checks for inefficient searching of keys and values within
|
7
|
-
# hashes.
|
8
|
-
#
|
9
|
-
# `Hash#keys.include?` is less efficient than `Hash#key?` because
|
10
|
-
# the former allocates a new array and then performs an O(n) search
|
11
|
-
# through that array, while `Hash#key?` does not allocate any array and
|
12
|
-
# performs a faster O(1) search for the key.
|
13
|
-
#
|
14
|
-
# `Hash#values.include?` is less efficient than `Hash#value?`. While they
|
15
|
-
# both perform an O(n) search through all of the values, calling `values`
|
16
|
-
# allocates a new array while using `value?` does not.
|
17
|
-
#
|
18
|
-
# @example
|
19
|
-
# # bad
|
20
|
-
# { a: 1, b: 2 }.keys.include?(:a)
|
21
|
-
# { a: 1, b: 2 }.keys.include?(:z)
|
22
|
-
# h = { a: 1, b: 2 }; h.keys.include?(100)
|
23
|
-
#
|
24
|
-
# # good
|
25
|
-
# { a: 1, b: 2 }.key?(:a)
|
26
|
-
# { a: 1, b: 2 }.has_key?(:z)
|
27
|
-
# h = { a: 1, b: 2 }; h.key?(100)
|
28
|
-
#
|
29
|
-
# # bad
|
30
|
-
# { a: 1, b: 2 }.values.include?(2)
|
31
|
-
# { a: 1, b: 2 }.values.include?('garbage')
|
32
|
-
# h = { a: 1, b: 2 }; h.values.include?(nil)
|
33
|
-
#
|
34
|
-
# # good
|
35
|
-
# { a: 1, b: 2 }.value?(2)
|
36
|
-
# { a: 1, b: 2 }.has_value?('garbage')
|
37
|
-
# h = { a: 1, b: 2 }; h.value?(nil)
|
38
|
-
#
|
39
|
-
class InefficientHashSearch < Cop
|
40
|
-
def_node_matcher :inefficient_include?, <<-PATTERN
|
41
|
-
(send (send $_ {:keys :values}) :include? _)
|
42
|
-
PATTERN
|
43
|
-
|
44
|
-
def on_send(node)
|
45
|
-
inefficient_include?(node) do |receiver|
|
46
|
-
return if receiver.nil?
|
47
|
-
|
48
|
-
add_offense(node)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def autocorrect(node)
|
53
|
-
lambda do |corrector|
|
54
|
-
# Replace `keys.include?` or `values.include?` with the appropriate
|
55
|
-
# `key?`/`value?` method.
|
56
|
-
corrector.replace(
|
57
|
-
node.loc.expression,
|
58
|
-
"#{autocorrect_hash_expression(node)}."\
|
59
|
-
"#{autocorrect_method(node)}(#{autocorrect_argument(node)})"
|
60
|
-
)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def message(node)
|
67
|
-
"Use `##{autocorrect_method(node)}` instead of "\
|
68
|
-
"`##{current_method(node)}.include?`."
|
69
|
-
end
|
70
|
-
|
71
|
-
def autocorrect_method(node)
|
72
|
-
case current_method(node)
|
73
|
-
when :keys then use_long_method ? 'has_key?' : 'key?'
|
74
|
-
when :values then use_long_method ? 'has_value?' : 'value?'
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def current_method(node)
|
79
|
-
node.receiver.method_name
|
80
|
-
end
|
81
|
-
|
82
|
-
def use_long_method
|
83
|
-
preferred_config = config.for_all_cops['Style/PreferredHashMethods']
|
84
|
-
preferred_config &&
|
85
|
-
preferred_config['EnforcedStyle'] == 'long' &&
|
86
|
-
preferred_config['Enabled']
|
87
|
-
end
|
88
|
-
|
89
|
-
def autocorrect_argument(node)
|
90
|
-
node.arguments.first.source
|
91
|
-
end
|
92
|
-
|
93
|
-
def autocorrect_hash_expression(node)
|
94
|
-
node.receiver.receiver.source
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Performance
|
6
|
-
# This cop checks for `OpenStruct.new` calls.
|
7
|
-
# Instantiation of an `OpenStruct` invalidates
|
8
|
-
# Ruby global method cache as it causes dynamic method
|
9
|
-
# definition during program runtime.
|
10
|
-
# This could have an effect on performance,
|
11
|
-
# especially in case of single-threaded
|
12
|
-
# applications with multiple `OpenStruct` instantiations.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# # bad
|
16
|
-
# class MyClass
|
17
|
-
# def my_method
|
18
|
-
# OpenStruct.new(my_key1: 'my_value1', my_key2: 'my_value2')
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# # good
|
23
|
-
# class MyClass
|
24
|
-
# MyStruct = Struct.new(:my_key1, :my_key2)
|
25
|
-
# def my_method
|
26
|
-
# MyStruct.new('my_value1', 'my_value2')
|
27
|
-
# end
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
class OpenStruct < Cop
|
31
|
-
MSG = 'Consider using `Struct` over `OpenStruct` ' \
|
32
|
-
'to optimize the performance.'.freeze
|
33
|
-
|
34
|
-
def_node_matcher :open_struct, <<-PATTERN
|
35
|
-
(send (const {nil? cbase} :OpenStruct) :new ...)
|
36
|
-
PATTERN
|
37
|
-
|
38
|
-
def on_send(node)
|
39
|
-
open_struct(node) do |method|
|
40
|
-
add_offense(node, location: :selector, message: format(MSG, method))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|