rubocop 0.67.2 → 0.68.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 +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
|