rubocop 0.84.0 → 0.85.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +33 -15
  4. data/lib/rubocop.rb +6 -0
  5. data/lib/rubocop/cli.rb +2 -2
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  7. data/lib/rubocop/comment_config.rb +1 -1
  8. data/lib/rubocop/config.rb +3 -1
  9. data/lib/rubocop/config_loader.rb +1 -1
  10. data/lib/rubocop/config_loader_resolver.rb +18 -2
  11. data/lib/rubocop/config_store.rb +12 -2
  12. data/lib/rubocop/cop/bundler/gem_comment.rb +70 -1
  13. data/lib/rubocop/cop/commissioner.rb +0 -21
  14. data/lib/rubocop/cop/cop.rb +14 -6
  15. data/lib/rubocop/cop/corrector.rb +3 -1
  16. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +1 -1
  17. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +3 -1
  18. data/lib/rubocop/cop/layout/case_indentation.rb +3 -3
  19. data/lib/rubocop/cop/layout/class_structure.rb +19 -16
  20. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -2
  21. data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +1 -1
  24. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -6
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  27. data/lib/rubocop/cop/layout/heredoc_indentation.rb +19 -102
  28. data/lib/rubocop/cop/layout/line_length.rb +17 -17
  29. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -1
  30. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  31. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +3 -1
  32. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +3 -1
  33. data/lib/rubocop/cop/lint/ambiguous_operator.rb +2 -1
  34. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +8 -4
  35. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  36. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -1
  37. data/lib/rubocop/cop/lint/loop.rb +1 -1
  38. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +62 -0
  39. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  40. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +7 -7
  41. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -1
  42. data/lib/rubocop/cop/lint/redundant_require_statement.rb +3 -3
  43. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  44. data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -2
  45. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  46. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +1 -1
  47. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  48. data/lib/rubocop/cop/migration/department_name.rb +9 -5
  49. data/lib/rubocop/cop/mixin/array_min_size.rb +3 -1
  50. data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -1
  51. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  52. data/lib/rubocop/cop/mixin/ignored_pattern.rb +1 -1
  53. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  54. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +3 -1
  55. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +16 -0
  56. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -1
  57. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +1 -1
  58. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +11 -1
  59. data/lib/rubocop/cop/naming/file_name.rb +26 -11
  60. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  61. data/lib/rubocop/cop/registry.rb +3 -1
  62. data/lib/rubocop/cop/style/array_join.rb +1 -1
  63. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
  64. data/lib/rubocop/cop/style/copyright.rb +2 -2
  65. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  66. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  67. data/lib/rubocop/cop/style/format_string_token.rb +2 -3
  68. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -2
  69. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
  70. data/lib/rubocop/cop/style/hash_syntax.rb +5 -3
  71. data/lib/rubocop/cop/style/inline_comment.rb +1 -1
  72. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  73. data/lib/rubocop/cop/style/negated_if.rb +3 -3
  74. data/lib/rubocop/cop/style/negated_unless.rb +3 -3
  75. data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
  76. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  77. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +89 -0
  78. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +130 -0
  79. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  80. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +3 -3
  81. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +3 -3
  82. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +13 -13
  83. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +3 -3
  84. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  85. data/lib/rubocop/cop/style/unless_else.rb +1 -1
  86. data/lib/rubocop/cop/style/when_then.rb +1 -1
  87. data/lib/rubocop/cop/team.rb +61 -25
  88. data/lib/rubocop/cop/util.rb +1 -1
  89. data/lib/rubocop/cop/variable_force/branch.rb +3 -1
  90. data/lib/rubocop/formatter/junit_formatter.rb +14 -4
  91. data/lib/rubocop/magic_comment.rb +1 -1
  92. data/lib/rubocop/options.rb +17 -3
  93. data/lib/rubocop/result_cache.rb +4 -4
  94. data/lib/rubocop/rspec/cop_helper.rb +2 -23
  95. data/lib/rubocop/rspec/expect_offense.rb +42 -6
  96. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  97. data/lib/rubocop/runner.rb +14 -10
  98. data/lib/rubocop/target_finder.rb +3 -1
  99. data/lib/rubocop/target_ruby.rb +4 -1
  100. data/lib/rubocop/version.rb +1 -1
  101. metadata +21 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92b169f3f7a5c04a2ce3b9b674328a49e078a8f19b5560e5135eee1ddb4f0428
4
- data.tar.gz: 6057deda8dd47bbf92038a03ce0bd4d35139c220f5fede6049f5e3da9fcc7ad0
3
+ metadata.gz: edfaa1a180e5c318e672651ae7e4c75625a41a4c247d3ce378f6e25e809a4277
4
+ data.tar.gz: 8ce15a32ddd8181b7b5117214d00a795f8824cbd13282120545fc7dd58548137
5
5
  SHA512:
6
- metadata.gz: 073154f4f62eed603c4b4d947b5dcdc308d1f0aebcffe11daad2b0d21820272f9d13d89e40403292a5497d6d9722e405f9f6cb16071c69214fc10a074eef5254
7
- data.tar.gz: 69c0e58d557d71c898cf6c43bed3fb6a5df83650e239e470bf0bb56cf4a2722895f2c8b9fb36775e752a2dafc80893f719166e204a4d5f136c82c0f6a03bc321
6
+ metadata.gz: 57f80040236ae265d1478fecbbe20ebfd27905d52cd2c06d83202d2a8d7fe426feb774d63788fd38942872a12c18c247896e89f21c7010259ab1902cb5034177
7
+ data.tar.gz: b86dcfcaa1839b9f3a7d532d87c1574e712df8018bfb3f85f06e4d2ecc1bb174018458fd2ee5f853def55f2312da8ab8b3037ea3be0defff4c16f4bbbeb6cf5d
data/README.md CHANGED
@@ -53,7 +53,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
53
53
  might want to use a conservative version lock in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 0.84.0', require: false
56
+ gem 'rubocop', '~> 0.85.0', require: false
57
57
  ```
58
58
 
59
59
  ## Quickstart
@@ -153,12 +153,13 @@ Bundler/GemComment:
153
153
  Description: 'Add a comment describing each gem.'
154
154
  Enabled: false
155
155
  VersionAdded: '0.59'
156
- VersionChanged: '0.77'
156
+ VersionChanged: '0.85'
157
157
  Include:
158
158
  - '**/*.gemfile'
159
159
  - '**/Gemfile'
160
160
  - '**/gems.rb'
161
161
  IgnoredGems: []
162
+ OnlyFor: []
162
163
 
163
164
  Bundler/InsecureProtocolSource:
164
165
  Description: >-
@@ -790,13 +791,7 @@ Layout/HeredocIndentation:
790
791
  StyleGuide: '#squiggly-heredocs'
791
792
  Enabled: true
792
793
  VersionAdded: '0.49'
793
- VersionChanged: '0.77'
794
- EnforcedStyle: squiggly
795
- SupportedStyles:
796
- - squiggly
797
- - active_support
798
- - powerpack
799
- - unindent
794
+ VersionChanged: '0.85'
800
795
 
801
796
  Layout/IndentationConsistency:
802
797
  Description: 'Keep indentation straight.'
@@ -864,8 +859,8 @@ Layout/LeadingEmptyLines:
864
859
  VersionChanged: '0.77'
865
860
 
866
861
  Layout/LineLength:
867
- Description: 'Limit lines to 80 characters.'
868
- StyleGuide: '#80-character-limits'
862
+ Description: 'Checks that line length does not exceed the configured limit.'
863
+ StyleGuide: '#max-line-length'
869
864
  Enabled: true
870
865
  VersionAdded: '0.25'
871
866
  VersionChanged: '0.84'
@@ -1538,6 +1533,11 @@ Lint/MissingCopEnableDirective:
1538
1533
  # .inf for any size
1539
1534
  MaximumRangeSize: .inf
1540
1535
 
1536
+ Lint/MixedRegexpCaptureTypes:
1537
+ Description: 'Do not mix named captures and numbered captures in a Regexp literal.'
1538
+ Enabled: pending
1539
+ VersionAdded: '0.85'
1540
+
1541
1541
  Lint/MultipleComparison:
1542
1542
  Description: "Use `&&` operator to compare multiple values."
1543
1543
  Enabled: true
@@ -2011,6 +2011,11 @@ Naming/ClassAndModuleCamelCase:
2011
2011
  StyleGuide: '#camelcase-classes'
2012
2012
  Enabled: true
2013
2013
  VersionAdded: '0.50'
2014
+ VersionChanged: '0.85'
2015
+ # Allowed class/module names can be specified here.
2016
+ # These can be full or part of the name.
2017
+ AllowedNames:
2018
+ - module_parent
2014
2019
 
2015
2020
  Naming/ConstantName:
2016
2021
  Description: 'Constants should use SCREAMING_SNAKE_CASE.'
@@ -2031,6 +2036,10 @@ Naming/FileName:
2031
2036
  # It further expects it to be nested inside modules which match the names
2032
2037
  # of subdirectories in its path.
2033
2038
  ExpectMatchingDefinition: false
2039
+ # When `false`, changes the behavior of ExpectMatchingDefinition to match only
2040
+ # whether each source file's class or module name matches the file name --
2041
+ # not whether the nested module hierarchy matches the subdirectory path.
2042
+ CheckDefinitionPathHierarchy: true
2034
2043
  # If non-`nil`, expect all source file names to match the following regex.
2035
2044
  # Only the file name itself is matched, not the entire file path.
2036
2045
  # Use anchors as necessary if you want to match the entire name rather than
@@ -2222,7 +2231,7 @@ Security/JSONLoad:
2222
2231
  Description: >-
2223
2232
  Prefer usage of `JSON.parse` over `JSON.load` due to potential
2224
2233
  security issues. See reference for more information.
2225
- Reference: 'https://ruby-doc.org/stdlib-2.3.0/libdoc/json/rdoc/JSON.html#method-i-load'
2234
+ Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load'
2226
2235
  Enabled: true
2227
2236
  VersionAdded: '0.43'
2228
2237
  VersionChanged: '0.44'
@@ -2235,7 +2244,7 @@ Security/MarshalLoad:
2235
2244
  Description: >-
2236
2245
  Avoid using of `Marshal.load` or `Marshal.restore` due to potential
2237
2246
  security issues. See reference for more information.
2238
- Reference: 'https://ruby-doc.org/core-2.3.3/Marshal.html#module-Marshal-label-Security+considerations'
2247
+ Reference: 'https://ruby-doc.org/core-2.7.0/Marshal.html#module-Marshal-label-Security+considerations'
2239
2248
  Enabled: true
2240
2249
  VersionAdded: '0.47'
2241
2250
 
@@ -2249,7 +2258,7 @@ Security/YAMLLoad:
2249
2258
  Description: >-
2250
2259
  Prefer usage of `YAML.safe_load` over `YAML.load` due to potential
2251
2260
  security issues. See reference for more information.
2252
- Reference: 'https://ruby-doc.org/stdlib-2.3.3/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security'
2261
+ Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security'
2253
2262
  Enabled: true
2254
2263
  VersionAdded: '0.47'
2255
2264
  SafeAutoCorrect: false
@@ -2874,8 +2883,7 @@ Style/FrozenStringLiteralComment:
2874
2883
  SupportedStyles:
2875
2884
  # `always` will always add the frozen string literal comment to a file
2876
2885
  # regardless of the Ruby version or if `freeze` or `<<` are called on a
2877
- # string literal. If you run code against multiple versions of Ruby, it is
2878
- # possible that this will create errors in Ruby 2.3.0+.
2886
+ # string literal. It is possible that this will create errors.
2879
2887
  - always
2880
2888
  # `always_true` will add the frozen string literal comment to a file,
2881
2889
  # similarly to the `always` style, but will also change any disabled
@@ -3610,6 +3618,16 @@ Style/RedundantPercentQ:
3610
3618
  Enabled: true
3611
3619
  VersionAdded: '0.76'
3612
3620
 
3621
+ Style/RedundantRegexpCharacterClass:
3622
+ Description: 'Checks for unnecessary single-element Regexp character classes.'
3623
+ Enabled: pending
3624
+ VersionAdded: '0.85'
3625
+
3626
+ Style/RedundantRegexpEscape:
3627
+ Description: 'Checks for redundant escapes in Regexps.'
3628
+ Enabled: pending
3629
+ VersionAdded: '0.85'
3630
+
3613
3631
  Style/RedundantReturn:
3614
3632
  Description: "Don't use return where it's not required."
3615
3633
  StyleGuide: '#no-explicit-return'
@@ -4,6 +4,8 @@ require 'rainbow'
4
4
 
5
5
  require 'English'
6
6
  require 'set'
7
+ require 'forwardable'
8
+ require 'regexp_parser'
7
9
  require 'unicode/display_width/no_string_ext'
8
10
  require 'rubocop-ast'
9
11
  require_relative 'rubocop/ast_aliases'
@@ -96,6 +98,7 @@ require_relative 'rubocop/cop/mixin/percent_literal'
96
98
  require_relative 'rubocop/cop/mixin/preceding_following_alignment'
97
99
  require_relative 'rubocop/cop/mixin/preferred_delimiters'
98
100
  require_relative 'rubocop/cop/mixin/rational_literal'
101
+ require_relative 'rubocop/cop/mixin/regexp_literal_help'
99
102
  require_relative 'rubocop/cop/mixin/rescue_node'
100
103
  require_relative 'rubocop/cop/mixin/safe_assignment'
101
104
  require_relative 'rubocop/cop/mixin/space_after_punctuation'
@@ -266,6 +269,7 @@ require_relative 'rubocop/cop/lint/literal_as_condition'
266
269
  require_relative 'rubocop/cop/lint/literal_in_interpolation'
267
270
  require_relative 'rubocop/cop/lint/loop'
268
271
  require_relative 'rubocop/cop/lint/missing_cop_enable_directive'
272
+ require_relative 'rubocop/cop/lint/mixed_regexp_capture_types'
269
273
  require_relative 'rubocop/cop/lint/multiple_comparison'
270
274
  require_relative 'rubocop/cop/lint/nested_method_definition'
271
275
  require_relative 'rubocop/cop/lint/nested_percent_literal'
@@ -475,6 +479,8 @@ require_relative 'rubocop/cop/style/redundant_freeze'
475
479
  require_relative 'rubocop/cop/style/redundant_interpolation'
476
480
  require_relative 'rubocop/cop/style/redundant_parentheses'
477
481
  require_relative 'rubocop/cop/style/redundant_percent_q'
482
+ require_relative 'rubocop/cop/style/redundant_regexp_character_class'
483
+ require_relative 'rubocop/cop/style/redundant_regexp_escape'
478
484
  require_relative 'rubocop/cop/style/redundant_return'
479
485
  require_relative 'rubocop/cop/style/redundant_self'
480
486
  require_relative 'rubocop/cop/style/redundant_sort'
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  def validate_options_vs_config
77
77
  if @options[:parallel] &&
78
- !@config_store.for(Dir.pwd).for_all_cops['UseCache']
78
+ !@config_store.for_dir(Dir.pwd).for_all_cops['UseCache']
79
79
  raise OptionArgumentError, '-P/--parallel uses caching to speed up ' \
80
80
  'execution, so combining with AllCops: ' \
81
81
  'UseCache: false is not allowed.'
@@ -123,7 +123,7 @@ module RuboCop
123
123
  if @options[:auto_gen_config]
124
124
  formatter = 'autogenconf'
125
125
  else
126
- cfg = @config_store.for(Dir.pwd).for_all_cops
126
+ cfg = @config_store.for_dir(Dir.pwd).for_all_cops
127
127
  formatter = cfg['DefaultFormatter'] || 'progress'
128
128
  end
129
129
  [[formatter, @options[:output_path]]]
@@ -25,10 +25,10 @@ module RuboCop
25
25
  private
26
26
 
27
27
  def maybe_run_line_length_cop
28
- if !line_length_enabled?(@config_store.for(Dir.pwd))
28
+ if !line_length_enabled?(@config_store.for_dir(Dir.pwd))
29
29
  skip_line_length_cop(PHASE_1_DISABLED)
30
30
  elsif !same_max_line_length?(
31
- @config_store.for(Dir.pwd), ConfigLoader.default_configuration
31
+ @config_store.for_dir(Dir.pwd), ConfigLoader.default_configuration
32
32
  )
33
33
  skip_line_length_cop(PHASE_1_OVERRIDDEN)
34
34
  else
@@ -124,7 +124,7 @@ module RuboCop
124
124
  end
125
125
 
126
126
  def directive_on_comment_line?(comment)
127
- comment.text[1..-1].match(COMMENT_DIRECTIVE_REGEXP)
127
+ comment.text[1..-1].match?(COMMENT_DIRECTIVE_REGEXP)
128
128
  end
129
129
 
130
130
  def each_directive
@@ -86,7 +86,9 @@ module RuboCop
86
86
 
87
87
  excludes = for_all_cops['Exclude'] ||= []
88
88
  highest_config.for_all_cops['Exclude'].each do |path|
89
- path = File.join(File.dirname(highest_config.loaded_path), path) unless path.is_a?(Regexp) || absolute?(path)
89
+ unless path.is_a?(Regexp) || absolute?(path)
90
+ path = File.join(File.dirname(highest_config.loaded_path), path)
91
+ end
90
92
  excludes << path unless excludes.include?(path)
91
93
  end
92
94
  end
@@ -136,7 +136,7 @@ module RuboCop
136
136
  warn Rainbow(" - #{cop.name} (#{version})").yellow
137
137
  end
138
138
 
139
- warn Rainbow('For more information: https://docs.rubocop.org/en/latest/versioning/').yellow
139
+ warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
140
140
  end
141
141
 
142
142
  # Merges the given configuration with the default one. If
@@ -171,10 +171,20 @@ module RuboCop
171
171
 
172
172
  def inherited_file(path, inherit_from, file)
173
173
  if remote_file?(inherit_from)
174
+ # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`.
174
175
  RemoteConfig.new(inherit_from, File.dirname(path))
176
+ elsif Pathname.new(inherit_from).absolute?
177
+ # An absolute path to a config, e.g. `inherit_from: /Users/me/rubocop.yml`.
178
+ # The path may come from `inherit_gem` option, where a gem name is expanded
179
+ # to an absolute path to that gem.
180
+ print 'Inheriting ' if ConfigLoader.debug?
181
+ inherit_from
175
182
  elsif file.is_a?(RemoteConfig)
183
+ # A path relative to a URL, e.g. `inherit_from: configs/default.yml`
184
+ # in a config included with `inherit_from: http://example.com/rubocop.yml`
176
185
  file.inherit_from_remote(inherit_from, path)
177
186
  else
187
+ # A local relative path, e.g. `inherit_from: default.yml`
178
188
  print 'Inheriting ' if ConfigLoader.debug?
179
189
  File.expand_path(inherit_from, File.dirname(path))
180
190
  end
@@ -208,8 +218,14 @@ module RuboCop
208
218
  end
209
219
 
210
220
  def gem_config_path(gem_name, relative_config_path)
211
- spec = Gem::Specification.find_by_name(gem_name)
212
- File.join(spec.gem_dir, relative_config_path)
221
+ if defined?(Bundler)
222
+ gem = Bundler.load.specs[gem_name].first
223
+ gem_path = gem.full_gem_path if gem
224
+ end
225
+
226
+ gem_path ||= Gem::Specification.find_by_name(gem_name).gem_dir
227
+
228
+ File.join(gem_path, relative_config_path)
213
229
  rescue Gem::LoadError => e
214
230
  raise Gem::LoadError,
215
231
  "Unable to find gem #{gem_name}; is the gem installed? #{e}"
@@ -29,14 +29,24 @@ module RuboCop
29
29
  @options_config = ConfigLoader.default_configuration
30
30
  end
31
31
 
32
- def for(file_or_dir)
33
- return @options_config if @options_config
32
+ def for_file(file)
33
+ for_dir(File.dirname(file))
34
+ end
34
35
 
36
+ # If type (file/dir) is known beforehand,
37
+ # prefer using #for_file or #for_dir for improved performance
38
+ def for(file_or_dir)
35
39
  dir = if File.directory?(file_or_dir)
36
40
  file_or_dir
37
41
  else
38
42
  File.dirname(file_or_dir)
39
43
  end
44
+ for_dir(dir)
45
+ end
46
+
47
+ def for_dir(dir)
48
+ return @options_config if @options_config
49
+
40
50
  @path_cache[dir] ||= ConfigLoader.configuration_file_for(dir)
41
51
  path = @path_cache[dir]
42
52
  @object_cache[path] ||= begin
@@ -5,7 +5,25 @@ module RuboCop
5
5
  module Bundler
6
6
  # Add a comment describing each gem in your Gemfile.
7
7
  #
8
- # @example
8
+ # Optionally, the "OnlyFor" configuration
9
+ # can be used to only register offenses when the gems
10
+ # use certain options or have version specifiers.
11
+ # Add "version_specifiers" and/or the gem option names
12
+ # you want to check.
13
+ #
14
+ # A useful use-case is to enforce a comment when using
15
+ # options that change the source of a gem:
16
+ #
17
+ # - `bitbucket`
18
+ # - `gist`
19
+ # - `git`
20
+ # - `github`
21
+ # - `source`
22
+ #
23
+ # For a full list of options supported by bundler,
24
+ # you can check the https://bundler.io/man/gemfile.5.html[official documentation].
25
+ #
26
+ # @example OnlyFor: [] (default)
9
27
  # # bad
10
28
  #
11
29
  # gem 'foo'
@@ -15,10 +33,37 @@ module RuboCop
15
33
  # # Helpers for the foo things.
16
34
  # gem 'foo'
17
35
  #
36
+ # @example OnlyFor: ['version_specifiers']
37
+ # # bad
38
+ #
39
+ # gem 'foo', '< 2.1'
40
+ #
41
+ # # good
42
+ #
43
+ # # Version 2.1 introduces breaking change baz
44
+ # gem 'foo', '< 2.1'
45
+ #
46
+ # @example OnlyFor: ['version_specifiers', 'github']
47
+ # # bad
48
+ #
49
+ # gem 'foo', github: 'some_account/some_fork_of_foo'
50
+ #
51
+ # gem 'bar', '< 2.1'
52
+ #
53
+ # # good
54
+ #
55
+ # # Using this fork because baz
56
+ # gem 'foo', github: 'some_account/some_fork_of_foo'
57
+ #
58
+ # # Version 2.1 introduces breaking change baz
59
+ # gem 'bar', '< 2.1'
60
+ #
18
61
  class GemComment < Cop
19
62
  include DefNode
20
63
 
21
64
  MSG = 'Missing gem description comment.'
65
+ CHECKED_OPTIONS_CONFIG = 'OnlyFor'
66
+ VERSION_SPECIFIERS_OPTION = 'version_specifiers'
22
67
 
23
68
  def_node_matcher :gem_declaration?, '(send nil? :gem str ...)'
24
69
 
@@ -26,6 +71,7 @@ module RuboCop
26
71
  return unless gem_declaration?(node)
27
72
  return if ignored_gem?(node)
28
73
  return if commented?(node)
74
+ return if cop_config[CHECKED_OPTIONS_CONFIG].any? && !checked_options_present?(node)
29
75
 
30
76
  add_offense(node)
31
77
  end
@@ -58,6 +104,29 @@ module RuboCop
58
104
  ignored_gems = Array(cop_config['IgnoredGems'])
59
105
  ignored_gems.include?(node.first_argument.value)
60
106
  end
107
+
108
+ def checked_options_present?(node)
109
+ (cop_config[CHECKED_OPTIONS_CONFIG].include?(VERSION_SPECIFIERS_OPTION) &&
110
+ version_specified_gem?(node)) ||
111
+ contains_checked_options?(node)
112
+ end
113
+
114
+ # Besides the gem name, all other *positional* arguments to `gem` are version specifiers,
115
+ # as long as it has one we know there's at least one version specifier.
116
+ def version_specified_gem?(node)
117
+ # arguments[0] is the gem name
118
+ node.arguments[1]&.str_type?
119
+ end
120
+
121
+ def contains_checked_options?(node)
122
+ (Array(cop_config[CHECKED_OPTIONS_CONFIG]) & gem_options(node).map(&:to_s)).any?
123
+ end
124
+
125
+ def gem_options(node)
126
+ return [] unless node.arguments.last&.type == :hash
127
+
128
+ node.arguments.last.keys.map(&:value)
129
+ end
61
130
  end
62
131
  end
63
132
  end
@@ -36,7 +36,6 @@ module RuboCop
36
36
 
37
37
  def investigate(processed_source)
38
38
  reset_errors
39
- remove_irrelevant_cops(processed_source.file_path)
40
39
  reset_callbacks
41
40
  prepare(processed_source)
42
41
  invoke_custom_processing(@cops, processed_source)
@@ -63,26 +62,6 @@ module RuboCop
63
62
  @errors = []
64
63
  end
65
64
 
66
- def remove_irrelevant_cops(filename)
67
- @cops.reject! do |cop|
68
- cop.excluded_file?(filename) ||
69
- !support_target_ruby_version?(cop) ||
70
- !support_target_rails_version?(cop)
71
- end
72
- end
73
-
74
- def support_target_ruby_version?(cop)
75
- return true unless cop.class.respond_to?(:support_target_ruby_version?)
76
-
77
- cop.class.support_target_ruby_version?(cop.target_ruby_version)
78
- end
79
-
80
- def support_target_rails_version?(cop)
81
- return true unless cop.class.respond_to?(:support_target_rails_version?)
82
-
83
- cop.class.support_target_rails_version?(cop.target_rails_version)
84
- end
85
-
86
65
  def reset_callbacks
87
66
  @callbacks.clear
88
67
  end
@@ -146,17 +146,24 @@ module RuboCop
146
146
  @offenses.any? { |o| o.location == location }
147
147
  end
148
148
 
149
- def correct(node)
149
+ def correct(node) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength
150
150
  reason = reason_to_not_correct(node)
151
151
  return reason if reason
152
152
 
153
153
  @corrected_nodes[node] = true
154
+
154
155
  if support_autocorrect?
155
156
  correction = autocorrect(node)
156
- return :uncorrected unless correction
157
157
 
158
- @corrections << Correction.new(correction, node, self)
159
- :corrected
158
+ if correction
159
+ @corrections << Correction.new(correction, node, self)
160
+ :corrected
161
+ elsif disable_uncorrectable?
162
+ disable_uncorrectable(node)
163
+ :corrected_with_todo
164
+ else
165
+ :uncorrected
166
+ end
160
167
  elsif disable_uncorrectable?
161
168
  disable_uncorrectable(node)
162
169
  :corrected_with_todo
@@ -211,8 +218,9 @@ module RuboCop
211
218
  alias name cop_name
212
219
 
213
220
  def relevant_file?(file)
214
- file_name_matches_any?(file, 'Include', true) &&
215
- !file_name_matches_any?(file, 'Exclude', false)
221
+ file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
222
+ file_name_matches_any?(file, 'Include', true) &&
223
+ !file_name_matches_any?(file, 'Exclude', false)
216
224
  end
217
225
 
218
226
  def excluded_file?(file)