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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +86 -233
  4. data/exe/rubocop +0 -12
  5. data/lib/rubocop.rb +13 -30
  6. data/lib/rubocop/ast/builder.rb +4 -0
  7. data/lib/rubocop/ast/node/alias_node.rb +24 -0
  8. data/lib/rubocop/ast/node/class_node.rb +31 -0
  9. data/lib/rubocop/ast/node/module_node.rb +24 -0
  10. data/lib/rubocop/ast/node/range_node.rb +7 -0
  11. data/lib/rubocop/ast/node/resbody_node.rb +12 -0
  12. data/lib/rubocop/ast/node/self_class_node.rb +24 -0
  13. data/lib/rubocop/cli.rb +40 -4
  14. data/lib/rubocop/config.rb +9 -7
  15. data/lib/rubocop/config_loader.rb +48 -7
  16. data/lib/rubocop/config_loader_resolver.rb +5 -4
  17. data/lib/rubocop/cop/commissioner.rb +24 -0
  18. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +18 -6
  19. data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +12 -14
  20. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +9 -20
  21. data/lib/rubocop/cop/layout/align_arguments.rb +93 -0
  22. data/lib/rubocop/cop/layout/align_parameters.rb +57 -33
  23. data/lib/rubocop/cop/layout/class_structure.rb +5 -5
  24. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -8
  25. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +3 -6
  26. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +1 -2
  27. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -0
  28. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +292 -0
  29. data/lib/rubocop/cop/layout/{first_parameter_indentation.rb → indent_first_argument.rb} +11 -12
  30. data/lib/rubocop/cop/layout/{indent_array.rb → indent_first_array_element.rb} +2 -2
  31. data/lib/rubocop/cop/layout/{indent_hash.rb → indent_first_hash_element.rb} +2 -2
  32. data/lib/rubocop/cop/layout/indent_first_parameter.rb +96 -0
  33. data/lib/rubocop/cop/layout/indentation_width.rb +4 -16
  34. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -4
  35. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -16
  36. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -2
  37. data/lib/rubocop/cop/lint/duplicate_methods.rb +6 -8
  38. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +4 -8
  39. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +157 -0
  40. data/lib/rubocop/cop/lint/inherit_exception.rb +3 -4
  41. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  42. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -5
  43. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +25 -5
  44. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -6
  45. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -2
  46. data/lib/rubocop/cop/message_annotator.rb +1 -0
  47. data/lib/rubocop/cop/metrics/line_length.rb +139 -28
  48. data/lib/rubocop/cop/metrics/perceived_complexity.rb +3 -4
  49. data/lib/rubocop/cop/mixin/check_line_breakable.rb +190 -0
  50. data/lib/rubocop/cop/mixin/{array_hash_indentation.rb → multiline_element_indentation.rb} +3 -2
  51. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -7
  52. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +33 -4
  53. data/lib/rubocop/cop/rails/active_record_override.rb +23 -8
  54. data/lib/rubocop/cop/rails/delegate.rb +5 -8
  55. data/lib/rubocop/cop/rails/environment_comparison.rb +5 -3
  56. data/lib/rubocop/cop/rails/find_each.rb +1 -1
  57. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
  58. data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
  59. data/lib/rubocop/cop/rails/skips_model_validations.rb +6 -7
  60. data/lib/rubocop/cop/rails/time_zone.rb +3 -10
  61. data/lib/rubocop/cop/rails/validation.rb +3 -0
  62. data/lib/rubocop/cop/registry.rb +3 -3
  63. data/lib/rubocop/cop/style/alias.rb +13 -7
  64. data/lib/rubocop/cop/style/block_delimiters.rb +20 -0
  65. data/lib/rubocop/cop/style/class_and_module_children.rb +19 -21
  66. data/lib/rubocop/cop/style/class_methods.rb +16 -24
  67. data/lib/rubocop/cop/style/conditional_assignment.rb +20 -49
  68. data/lib/rubocop/cop/style/documentation.rb +3 -7
  69. data/lib/rubocop/cop/style/format_string.rb +18 -21
  70. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  71. data/lib/rubocop/cop/style/inverse_methods.rb +4 -0
  72. data/lib/rubocop/cop/style/lambda.rb +12 -8
  73. data/lib/rubocop/cop/style/mixin_grouping.rb +8 -10
  74. data/lib/rubocop/cop/style/module_function.rb +2 -3
  75. data/lib/rubocop/cop/style/next.rb +10 -14
  76. data/lib/rubocop/cop/style/one_line_conditional.rb +5 -3
  77. data/lib/rubocop/cop/style/optional_arguments.rb +1 -4
  78. data/lib/rubocop/cop/style/random_with_offset.rb +44 -47
  79. data/lib/rubocop/cop/style/redundant_return.rb +6 -14
  80. data/lib/rubocop/cop/style/redundant_sort_by.rb +1 -1
  81. data/lib/rubocop/cop/style/safe_navigation.rb +3 -0
  82. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -3
  83. data/lib/rubocop/cop/style/symbol_proc.rb +20 -40
  84. data/lib/rubocop/cop/style/unless_else.rb +1 -2
  85. data/lib/rubocop/cop/style/yoda_condition.rb +8 -7
  86. data/lib/rubocop/cop/util.rb +2 -4
  87. data/lib/rubocop/file_finder.rb +5 -10
  88. data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -0
  89. data/lib/rubocop/node_pattern.rb +304 -170
  90. data/lib/rubocop/options.rb +4 -1
  91. data/lib/rubocop/rspec/shared_contexts.rb +3 -0
  92. data/lib/rubocop/version.rb +1 -1
  93. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  94. metadata +26 -50
  95. data/lib/rubocop/cop/performance/caller.rb +0 -69
  96. data/lib/rubocop/cop/performance/case_when_splat.rb +0 -177
  97. data/lib/rubocop/cop/performance/casecmp.rb +0 -108
  98. data/lib/rubocop/cop/performance/chain_array_allocation.rb +0 -78
  99. data/lib/rubocop/cop/performance/compare_with_block.rb +0 -122
  100. data/lib/rubocop/cop/performance/count.rb +0 -102
  101. data/lib/rubocop/cop/performance/detect.rb +0 -110
  102. data/lib/rubocop/cop/performance/double_start_end_with.rb +0 -94
  103. data/lib/rubocop/cop/performance/end_with.rb +0 -56
  104. data/lib/rubocop/cop/performance/fixed_size.rb +0 -97
  105. data/lib/rubocop/cop/performance/flat_map.rb +0 -78
  106. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +0 -99
  107. data/lib/rubocop/cop/performance/open_struct.rb +0 -46
  108. data/lib/rubocop/cop/performance/range_include.rb +0 -50
  109. data/lib/rubocop/cop/performance/redundant_block_call.rb +0 -93
  110. data/lib/rubocop/cop/performance/redundant_match.rb +0 -56
  111. data/lib/rubocop/cop/performance/redundant_merge.rb +0 -183
  112. data/lib/rubocop/cop/performance/regexp_match.rb +0 -265
  113. data/lib/rubocop/cop/performance/reverse_each.rb +0 -42
  114. data/lib/rubocop/cop/performance/size.rb +0 -77
  115. data/lib/rubocop/cop/performance/start_with.rb +0 -59
  116. data/lib/rubocop/cop/performance/string_replacement.rb +0 -173
  117. data/lib/rubocop/cop/performance/times_map.rb +0 -71
  118. data/lib/rubocop/cop/performance/unfreeze_string.rb +0 -50
  119. 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