rubocop 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +34 -4
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  6. data/lib/rubocop/config.rb +2 -2
  7. data/lib/rubocop/config_loader.rb +7 -14
  8. data/lib/rubocop/config_store.rb +12 -1
  9. data/lib/rubocop/cop/base.rb +1 -1
  10. data/lib/rubocop/cop/generator.rb +1 -3
  11. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  12. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  14. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  15. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  16. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  17. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  18. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  19. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  20. data/lib/rubocop/cop/lint/symbol_conversion.rb +102 -0
  21. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  22. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  23. data/lib/rubocop/cop/mixin/comments_help.rb +0 -1
  24. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  25. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  26. data/lib/rubocop/cop/severity.rb +3 -3
  27. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  28. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  29. data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
  30. data/lib/rubocop/cop/style/float_division.rb +3 -0
  31. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  32. data/lib/rubocop/cop/style/if_inside_else.rb +14 -7
  33. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +96 -0
  34. data/lib/rubocop/cop/style/nil_comparison.rb +1 -0
  35. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  36. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  37. data/lib/rubocop/cop/style/sole_nested_conditional.rb +26 -2
  38. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  39. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  40. data/lib/rubocop/magic_comment.rb +30 -1
  41. data/lib/rubocop/options.rb +1 -1
  42. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  43. data/lib/rubocop/runner.rb +1 -0
  44. data/lib/rubocop/version.rb +2 -2
  45. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe7ec80b8cde2a075fee5a5658abf6dc74889091dae29e88482107983d2de270
4
- data.tar.gz: 7852fe6a6d0ba9cae98439cba0dfbfda659a5a434f62eca318bcd5bc45dfd3c4
3
+ metadata.gz: ec2d9f7ba4857375232c4e42ea44accdb38b2873c83315f3029a546e315622e0
4
+ data.tar.gz: 01df5c9957cca7c79cf8cab073c1bae675d684761561835d6d93f554f3743905
5
5
  SHA512:
6
- metadata.gz: 4239a27259a39584a544ed4bfc7c6025ece2198d463f8a2918a98e5560cec9a5a2ea5b978f0d253e61ea700446bb49f705627d8b8e41d4ead0fef35b23b14d98
7
- data.tar.gz: 59746b47f6bbe92dec5f6d79395ad6cd1a175d3a186005412953f0a849192673084b426bd14f6e9ac83e11dfaa0b27fc15718857b29ca6d359e2c9d387bca9c2
6
+ metadata.gz: 55a5a8deae643b6d76dc5220c7136a7c5413ecb93ca85ec61dcd3aa9ff0adb3c1ab356ec81f72273771ab3125317fc105bfcaf0c7e1e1ae07f6295c7fa33c26e
7
+ data.tar.gz: 642d925df9f18c6c42b532eb0193965c6a85a93bd9339523757882eb6e9029052161a32bbc4421e454a210fe2ab5318ae64459dc4a9d792ee0cb5e4b259568ff
data/README.md CHANGED
@@ -51,7 +51,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
51
51
  in your `Gemfile`:
52
52
 
53
53
  ```rb
54
- gem 'rubocop', '~> 1.8', require: false
54
+ gem 'rubocop', '~> 1.9', require: false
55
55
  ```
56
56
 
57
57
  See [versioning](https://docs.rubocop.org/rubocop/1.0/versioning.html) for further details.
@@ -1806,6 +1806,17 @@ Lint/NumberConversion:
1806
1806
  - Time
1807
1807
  - DateTime
1808
1808
 
1809
+ Lint/NumberedParameterAssignment:
1810
+ Description: 'Checks for uses of numbered parameter assignment.'
1811
+ Enabled: pending
1812
+ VersionAdded: '1.9'
1813
+
1814
+ Lint/OrAssignmentToConstant:
1815
+ Description: 'Checks unintended or-assignment to constant.'
1816
+ Enabled: pending
1817
+ Safe: false
1818
+ VersionAdded: '1.9'
1819
+
1809
1820
  Lint/OrderedMagicComments:
1810
1821
  Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
1811
1822
  Enabled: true
@@ -2032,12 +2043,16 @@ Lint/SuppressedException:
2032
2043
  VersionAdded: '0.9'
2033
2044
  VersionChanged: '0.81'
2034
2045
 
2046
+ Lint/SymbolConversion:
2047
+ Description: 'Checks for unnecessary symbol conversions.'
2048
+ Enabled: pending
2049
+ VersionAdded: '1.9'
2050
+
2035
2051
  Lint/Syntax:
2036
- Description: 'Checks syntax error.'
2052
+ Description: 'Checks for syntax errors.'
2037
2053
  Enabled: true
2038
2054
  VersionAdded: '0.9'
2039
2055
 
2040
-
2041
2056
  Lint/ToEnumArguments:
2042
2057
  Description: 'This cop ensures that `to_enum`/`enum_for`, called for the current method, has correct arguments.'
2043
2058
  Enabled: pending
@@ -2058,6 +2073,11 @@ Lint/TrailingCommaInAttributeDeclaration:
2058
2073
  Enabled: true
2059
2074
  VersionAdded: '0.90'
2060
2075
 
2076
+ Lint/TripleQuotes:
2077
+ Description: 'Checks for useless triple quote constructs.'
2078
+ Enabled: pending
2079
+ VersionAdded: '1.9'
2080
+
2061
2081
  Lint/UnderscorePrefixedVariableName:
2062
2082
  Description: 'Do not use prefix `_` for a variable that is used.'
2063
2083
  Enabled: true
@@ -2689,7 +2709,8 @@ Style/AsciiComments:
2689
2709
  Enabled: true
2690
2710
  VersionAdded: '0.9'
2691
2711
  VersionChanged: '0.52'
2692
- AllowedChars: []
2712
+ AllowedChars:
2713
+ - ©
2693
2714
 
2694
2715
  Style/Attr:
2695
2716
  Description: 'Checks for uses of Module#attr.'
@@ -3120,6 +3141,8 @@ Style/DisableCopsWithinSourceCodeDirective:
3120
3141
  Forbids disabling/enabling cops within source code.
3121
3142
  Enabled: false
3122
3143
  VersionAdded: '0.82'
3144
+ VersionChanged: '1.9'
3145
+ AllowedCops: []
3123
3146
 
3124
3147
  Style/DocumentDynamicEvalDefinition:
3125
3148
  Description: >-
@@ -3291,7 +3314,8 @@ Style/FloatDivision:
3291
3314
  Reference: 'https://blog.rubystyle.guide/ruby/2019/06/21/float-division.html'
3292
3315
  Enabled: true
3293
3316
  VersionAdded: '0.72'
3294
- VersionChanged: '1.6'
3317
+ VersionChanged: '1.9'
3318
+ Safe: false
3295
3319
  EnforcedStyle: single_coerce
3296
3320
  SupportedStyles:
3297
3321
  - left_coerce
@@ -3339,6 +3363,7 @@ Style/FormatStringToken:
3339
3363
  MaxUnannotatedPlaceholdersAllowed: 1
3340
3364
  VersionAdded: '0.49'
3341
3365
  VersionChanged: '1.0'
3366
+ IgnoredMethods: []
3342
3367
 
3343
3368
  Style/FrozenStringLiteralComment:
3344
3369
  Description: >-
@@ -3492,6 +3517,11 @@ Style/IfUnlessModifierOfIfUnless:
3492
3517
  VersionAdded: '0.39'
3493
3518
  VersionChanged: '0.87'
3494
3519
 
3520
+ Style/IfWithBooleanLiteralBranches:
3521
+ Description: 'Checks for redundant `if` with boolean literal branches.'
3522
+ Enabled: pending
3523
+ VersionAdded: '1.9'
3524
+
3495
3525
  Style/IfWithSemicolon:
3496
3526
  Description: 'Do not use if x; .... Use the ternary operator instead.'
3497
3527
  StyleGuide: '#no-semicolon-ifs'
@@ -312,6 +312,8 @@ require_relative 'rubocop/cop/lint/no_return_in_begin_end_blocks'
312
312
  require_relative 'rubocop/cop/lint/non_deterministic_require_order'
313
313
  require_relative 'rubocop/cop/lint/non_local_exit_from_iterator'
314
314
  require_relative 'rubocop/cop/lint/number_conversion'
315
+ require_relative 'rubocop/cop/lint/numbered_parameter_assignment'
316
+ require_relative 'rubocop/cop/lint/or_assignment_to_constant'
315
317
  require_relative 'rubocop/cop/lint/ordered_magic_comments'
316
318
  require_relative 'rubocop/cop/lint/out_of_range_regexp_ref'
317
319
  require_relative 'rubocop/cop/lint/parentheses_as_grouped_expression'
@@ -344,11 +346,13 @@ require_relative 'rubocop/cop/lint/shadowed_exception'
344
346
  require_relative 'rubocop/cop/lint/shadowing_outer_local_variable'
345
347
  require_relative 'rubocop/cop/lint/struct_new_override'
346
348
  require_relative 'rubocop/cop/lint/suppressed_exception'
349
+ require_relative 'rubocop/cop/lint/symbol_conversion'
347
350
  require_relative 'rubocop/cop/lint/syntax'
348
351
  require_relative 'rubocop/cop/lint/to_enum_arguments'
349
352
  require_relative 'rubocop/cop/lint/to_json'
350
353
  require_relative 'rubocop/cop/lint/top_level_return_with_argument'
351
354
  require_relative 'rubocop/cop/lint/trailing_comma_in_attribute_declaration'
355
+ require_relative 'rubocop/cop/lint/triple_quotes'
352
356
  require_relative 'rubocop/cop/lint/underscore_prefixed_variable_name'
353
357
  require_relative 'rubocop/cop/lint/unexpected_block_arity'
354
358
  require_relative 'rubocop/cop/lint/unified_integer'
@@ -477,6 +481,7 @@ require_relative 'rubocop/cop/style/identical_conditional_branches'
477
481
  require_relative 'rubocop/cop/style/if_inside_else'
478
482
  require_relative 'rubocop/cop/style/if_unless_modifier'
479
483
  require_relative 'rubocop/cop/style/if_unless_modifier_of_if_unless'
484
+ require_relative 'rubocop/cop/style/if_with_boolean_literal_branches'
480
485
  require_relative 'rubocop/cop/style/if_with_semicolon'
481
486
  require_relative 'rubocop/cop/style/implicit_runtime_error'
482
487
  require_relative 'rubocop/cop/style/infinite_loop'
@@ -9,6 +9,7 @@ module RuboCop
9
9
  self.command_name = :auto_gen_config
10
10
 
11
11
  AUTO_GENERATED_FILE = '.rubocop_todo.yml'
12
+ YAML_OPTIONAL_DOC_START = /\A---(\s+#|\s*\z)/.freeze
12
13
 
13
14
  PHASE_1 = 'Phase 1 of 2: run Layout/LineLength cop'
14
15
  PHASE_2 = 'Phase 2 of 2: run all cops'
@@ -130,10 +131,10 @@ module RuboCop
130
131
  end
131
132
 
132
133
  def write_config_file(file_name, file_string, rubocop_yml_contents)
133
- File.open(file_name, 'w') do |f|
134
- f.write "inherit_from:#{file_string}\n"
135
- f.write "\n#{rubocop_yml_contents}" if /\S/.match?(rubocop_yml_contents)
136
- end
134
+ lines = /\S/.match?(rubocop_yml_contents) ? rubocop_yml_contents.split("\n", -1) : []
135
+ doc_start_index = lines.index { |line| YAML_OPTIONAL_DOC_START.match?(line) } || -1
136
+ lines.insert(doc_start_index + 1, "inherit_from:#{file_string}\n")
137
+ File.open(file_name, 'w') { |f| f.write lines.join("\n") }
137
138
  end
138
139
  end
139
140
  end
@@ -33,8 +33,8 @@ module RuboCop
33
33
  @validator = ConfigValidator.new(self)
34
34
  end
35
35
 
36
- def self.create(hash, path)
37
- new(hash, path).check
36
+ def self.create(hash, path, check: true)
37
+ new(hash, path).tap { |config| config.check if check }
38
38
  end
39
39
 
40
40
  def loaded_features
@@ -25,17 +25,18 @@ module RuboCop
25
25
  attr_accessor :debug, :ignore_parent_exclusion,
26
26
  :disable_pending_cops, :enable_pending_cops
27
27
  attr_writer :default_configuration, :project_root
28
+ attr_reader :loaded_features
28
29
 
29
30
  alias debug? debug
30
31
  alias ignore_parent_exclusion? ignore_parent_exclusion
31
32
 
32
33
  def clear_options
33
34
  @debug = nil
34
- @loaded_features = []
35
+ @loaded_features = Set.new
35
36
  FileFinder.root_level = nil
36
37
  end
37
38
 
38
- def load_file(file)
39
+ def load_file(file, check: true)
39
40
  path = file_path(file)
40
41
 
41
42
  hash = load_yaml_configuration(path)
@@ -52,7 +53,7 @@ module RuboCop
52
53
 
53
54
  hash.delete('inherit_from')
54
55
 
55
- Config.create(hash, path)
56
+ Config.create(hash, path, check: check)
56
57
  end
57
58
 
58
59
  def load_yaml_configuration(absolute_path)
@@ -99,10 +100,10 @@ module RuboCop
99
100
  find_user_xdg_config || DEFAULT_FILE
100
101
  end
101
102
 
102
- def configuration_from_file(config_file)
103
+ def configuration_from_file(config_file, check: true)
103
104
  return default_configuration if config_file == DEFAULT_FILE
104
105
 
105
- config = load_file(config_file)
106
+ config = load_file(config_file, check: check)
106
107
  if ignore_parent_exclusion?
107
108
  print 'Ignoring AllCops/Exclude from parent folders' if debug?
108
109
  else
@@ -174,19 +175,11 @@ module RuboCop
174
175
  resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
175
176
  end
176
177
 
177
- def loaded_features
178
- @loaded_features.flatten.compact.uniq
179
- end
180
-
181
178
  # @api private
182
179
  # Used to add features that were required inside a config or from
183
180
  # the CLI using `--require`.
184
181
  def add_loaded_features(loaded_features)
185
- if instance_variable_defined?(:@loaded_features)
186
- instance_variable_get(:@loaded_features) << loaded_features
187
- else
188
- instance_variable_set(:@loaded_features, [loaded_features])
189
- end
182
+ @loaded_features.merge(Array(loaded_features))
190
183
  end
191
184
 
192
185
  private
@@ -4,6 +4,9 @@ module RuboCop
4
4
  # Handles caching of configurations and association of inspected
5
5
  # ruby files to configurations.
6
6
  class ConfigStore
7
+ attr_reader :validated
8
+ alias validated? validated
9
+
7
10
  def initialize
8
11
  # @options_config stores a config that is specified in the command line.
9
12
  # This takes precedence over configs located in any directories
@@ -17,6 +20,9 @@ module RuboCop
17
20
  # @object_cache maps configuration file paths to
18
21
  # configuration objects so we only need to load them once.
19
22
  @object_cache = {}
23
+
24
+ # By default the config is validated before it can be used.
25
+ @validated = true
20
26
  end
21
27
 
22
28
  def options_config=(options_config)
@@ -29,6 +35,11 @@ module RuboCop
29
35
  @options_config = ConfigLoader.default_configuration
30
36
  end
31
37
 
38
+ def unvalidated
39
+ @validated = false
40
+ self
41
+ end
42
+
32
43
  def for_file(file)
33
44
  for_dir(File.dirname(file))
34
45
  end
@@ -55,7 +66,7 @@ module RuboCop
55
66
  path = @path_cache[dir]
56
67
  @object_cache[path] ||= begin
57
68
  print "For #{dir}: " if ConfigLoader.debug?
58
- ConfigLoader.configuration_from_file(path)
69
+ ConfigLoader.configuration_from_file(path, check: validated?)
59
70
  end
60
71
  end
61
72
  end
@@ -351,7 +351,7 @@ module RuboCop
351
351
  def use_corrector(range, corrector)
352
352
  if autocorrect?
353
353
  attempt_correction(range, corrector)
354
- elsif corrector
354
+ elsif corrector && cop_config.fetch('AutoCorrect', true)
355
355
  :uncorrected
356
356
  else
357
357
  :unsupported
@@ -81,9 +81,7 @@ module RuboCop
81
81
  SPEC_TEMPLATE = <<~SPEC
82
82
  # frozen_string_literal: true
83
83
 
84
- RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s do
85
- subject(:cop) { described_class.new(config) }
86
-
84
+ RSpec.describe RuboCop::Cop::%<department>s::%<cop_name>s, :config do
87
85
  let(:config) { RuboCop::Config.new }
88
86
 
89
87
  # TODO: Write test code
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'internal_affairs/empty_line_between_expect_offense_and_correction'
4
+ require_relative 'internal_affairs/example_description'
3
5
  require_relative 'internal_affairs/method_name_equal'
4
6
  require_relative 'internal_affairs/node_destructuring'
5
7
  require_relative 'internal_affairs/node_type_predicate'
6
8
  require_relative 'internal_affairs/offense_location_keyword'
7
- require_relative 'internal_affairs/redundant_message_argument'
9
+ require_relative 'internal_affairs/redundant_described_class_as_subject'
10
+ require_relative 'internal_affairs/redundant_let_rubocop_config_new'
8
11
  require_relative 'internal_affairs/redundant_location_argument'
12
+ require_relative 'internal_affairs/redundant_message_argument'
9
13
  require_relative 'internal_affairs/style_detected_api_use'
10
14
  require_relative 'internal_affairs/useless_message_assertion'
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # This cop checks whether `expect_offense` and correction expectation methods
7
+ # (i.e. `expect_correction` and `expect_no_corrections`) are separated by empty line.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # it 'registers and corrects an offense' do
12
+ # expect_offense(<<~RUBY)
13
+ # bad_method
14
+ # ^^^^^^^^^^ Use `good_method`.
15
+ # RUBY
16
+ # expect_correction(<<~RUBY)
17
+ # good_method
18
+ # RUBY
19
+ # end
20
+ #
21
+ # # good
22
+ # it 'registers and corrects an offense' do
23
+ # expect_offense(<<~RUBY)
24
+ # bad_method
25
+ # ^^^^^^^^^^ Use `good_method`.
26
+ # RUBY
27
+ #
28
+ # expect_correction(<<~RUBY)
29
+ # good_method
30
+ # RUBY
31
+ # end
32
+ #
33
+ class EmptyLineBetweenExpectOffenseAndCorrection < Base
34
+ extend AutoCorrector
35
+
36
+ MSG = 'Add empty line between `expect_offense` and `%<expect_correction>s`.'
37
+ RESTRICT_ON_SEND = %i[expect_offense].freeze
38
+ CORRECTION_EXPECTATION_METHODS = %i[expect_correction expect_no_corrections].freeze
39
+
40
+ def on_send(node)
41
+ return unless (next_sibling = node.right_sibling) && next_sibling.send_type?
42
+
43
+ method_name = next_sibling.method_name
44
+ return unless CORRECTION_EXPECTATION_METHODS.include?(method_name)
45
+
46
+ range = offense_range(node)
47
+ return unless range.last_line + 1 == next_sibling.loc.line
48
+
49
+ add_offense(range, message: format(MSG, expect_correction: method_name)) do |corrector|
50
+ corrector.insert_after(range, "\n")
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def offense_range(node)
57
+ first_argument = node.first_argument
58
+
59
+ if first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
60
+ first_argument.loc.heredoc_end
61
+ else
62
+ node
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks that RSpec examples that use `expects_offense`
7
+ # or `expects_no_offenses` do not have conflicting
8
+ # descriptions.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # it 'does not register an offense' do
13
+ # expect_offense('...')
14
+ # end
15
+ #
16
+ # it 'registers an offense' do
17
+ # expect_no_offenses('...')
18
+ # end
19
+ #
20
+ # # good
21
+ # it 'registers an offense' do
22
+ # expect_offense('...')
23
+ # end
24
+ #
25
+ # it 'does not register an offense' do
26
+ # expect_no_offenses('...')
27
+ # end
28
+ class ExampleDescription < Base
29
+ class << self
30
+ attr_accessor :descriptions
31
+ end
32
+
33
+ MSG = 'Description does not match use of `%<method_name>s`.'
34
+
35
+ RESTRICT_ON_SEND = %i[
36
+ expect_offense
37
+ expect_no_offenses
38
+ expect_correction
39
+ expect_no_corrections
40
+ ].to_set.freeze
41
+
42
+ EXPECT_NO_OFFENSES_INCORRECT_DESCRIPTIONS = [
43
+ /^(adds|registers|reports|finds) (an? )?offense/,
44
+ /^flags\b/
45
+ ].freeze
46
+
47
+ EXPECT_OFFENSE_INCORRECT_DESCRIPTIONS = [
48
+ /^(does not|doesn't) (register|find|flag|report)/,
49
+ /^(does not|doesn't) add (a|an|any )?offense/
50
+ ].freeze
51
+
52
+ EXPECT_NO_CORRECTIONS_INCORRECT_DESCRIPTIONS = [
53
+ /^(auto[- ]?)?correct/
54
+ ].freeze
55
+
56
+ EXPECT_CORRECTION_INCORRECT_DESCRIPTIONS = [
57
+ /\b(does not|doesn't) (auto[- ]?)?correct/
58
+ ].freeze
59
+
60
+ def_node_matcher :offense_example?, <<~PATTERN
61
+ (block
62
+ (send _ {:it :specify} $_description)
63
+ _args
64
+ `(send nil? %RESTRICT_ON_SEND ...)
65
+ )
66
+ PATTERN
67
+
68
+ def on_send(node)
69
+ parent = node.each_ancestor(:block).first
70
+ return unless parent && (description = offense_example?(parent))
71
+
72
+ method_name = node.method_name
73
+ message = format(MSG, method_name: method_name)
74
+
75
+ regexp_group = self.class.const_get("#{method_name}_incorrect_descriptions".upcase)
76
+ check_description(description, regexp_group, message)
77
+ end
78
+
79
+ private
80
+
81
+ def check_description(description, regexps, message)
82
+ return unless regexps.any? { |regexp| regexp.match?(description.value) }
83
+
84
+ add_offense(description, message: message)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end