rubocop 0.84.0 → 0.85.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -14
  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 +36 -21
  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 +20 -103
  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/format_parameter_mismatch.rb +33 -2
  38. data/lib/rubocop/cop/lint/loop.rb +1 -1
  39. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +69 -0
  40. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  41. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +7 -7
  42. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -1
  43. data/lib/rubocop/cop/lint/redundant_require_statement.rb +3 -3
  44. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  45. data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -2
  46. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  47. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +1 -1
  48. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  49. data/lib/rubocop/cop/migration/department_name.rb +9 -5
  50. data/lib/rubocop/cop/mixin/array_min_size.rb +3 -1
  51. data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -1
  52. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  53. data/lib/rubocop/cop/mixin/ignored_pattern.rb +1 -1
  54. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  55. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +3 -1
  56. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +16 -0
  57. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -1
  58. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +1 -1
  59. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +11 -1
  60. data/lib/rubocop/cop/naming/file_name.rb +26 -11
  61. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  62. data/lib/rubocop/cop/registry.rb +65 -8
  63. data/lib/rubocop/cop/style/array_join.rb +1 -1
  64. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
  65. data/lib/rubocop/cop/style/copyright.rb +2 -2
  66. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  67. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  68. data/lib/rubocop/cop/style/format_string_token.rb +2 -3
  69. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -2
  70. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
  71. data/lib/rubocop/cop/style/hash_syntax.rb +5 -3
  72. data/lib/rubocop/cop/style/inline_comment.rb +1 -1
  73. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  74. data/lib/rubocop/cop/style/negated_if.rb +3 -3
  75. data/lib/rubocop/cop/style/negated_unless.rb +3 -3
  76. data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
  77. data/lib/rubocop/cop/style/redundant_conditional.rb +4 -3
  78. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  79. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +89 -0
  80. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +130 -0
  81. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  82. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +3 -3
  83. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +3 -3
  84. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +13 -13
  85. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +3 -3
  86. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  87. data/lib/rubocop/cop/style/unless_else.rb +1 -1
  88. data/lib/rubocop/cop/style/when_then.rb +1 -1
  89. data/lib/rubocop/cop/team.rb +69 -25
  90. data/lib/rubocop/cop/util.rb +1 -1
  91. data/lib/rubocop/cop/utils/format_string.rb +18 -0
  92. data/lib/rubocop/cop/variable_force/branch.rb +3 -1
  93. data/lib/rubocop/formatter/junit_formatter.rb +14 -4
  94. data/lib/rubocop/magic_comment.rb +1 -1
  95. data/lib/rubocop/options.rb +17 -3
  96. data/lib/rubocop/result_cache.rb +4 -4
  97. data/lib/rubocop/rspec/cop_helper.rb +2 -23
  98. data/lib/rubocop/rspec/expect_offense.rb +45 -6
  99. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  100. data/lib/rubocop/runner.rb +14 -10
  101. data/lib/rubocop/target_finder.rb +3 -1
  102. data/lib/rubocop/target_ruby.rb +4 -1
  103. data/lib/rubocop/version.rb +1 -1
  104. metadata +23 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92b169f3f7a5c04a2ce3b9b674328a49e078a8f19b5560e5135eee1ddb4f0428
4
- data.tar.gz: 6057deda8dd47bbf92038a03ce0bd4d35139c220f5fede6049f5e3da9fcc7ad0
3
+ metadata.gz: 86b240fb0a653934db99c6ca12a1c53976c01f3d6de666842e9f7146f207f725
4
+ data.tar.gz: 606ea84dc8c148971ba8a2dc17ef2a03bbb48802e6053f5042d180e0f6c7c15f
5
5
  SHA512:
6
- metadata.gz: 073154f4f62eed603c4b4d947b5dcdc308d1f0aebcffe11daad2b0d21820272f9d13d89e40403292a5497d6d9722e405f9f6cb16071c69214fc10a074eef5254
7
- data.tar.gz: 69c0e58d557d71c898cf6c43bed3fb6a5df83650e239e470bf0bb56cf4a2722895f2c8b9fb36775e752a2dafc80893f719166e204a4d5f136c82c0f6a03bc321
6
+ metadata.gz: 4e6a817ec287b216c15e8820e29192fe1152fa77bb9b6fb9377f7a9b1bc22faef07e15c1f025691107914ae211f401549ef831c755fbf6b9c21bd04198388742
7
+ data.tar.gz: 2e3a6b4d35e5b24a9542ac5749247537ae2a47db242e86a189d3f719f7b1d35568eb22deaf491b2f5d1408de8415b2ee86fadfe8a56f229fbce89686744cc5e4
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/rubocop-hq/rubocop/master/logo/rubo-logo-horizontal.png" alt="RuboCop Logo"/>
3
+ </p>
4
+
5
+ ----------
1
6
  [![Gem Version](https://badge.fury.io/rb/rubocop.svg)](https://badge.fury.io/rb/rubocop)
2
7
  [![CircleCI Status](https://circleci.com/gh/rubocop-hq/rubocop/tree/master.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop/tree/master)
3
8
  [![Actions Status](https://github.com/rubocop-hq/rubocop/workflows/CI/badge.svg?branch=master)](https://github.com/rubocop-hq/rubocop/actions?query=workflow%3ACI)
@@ -11,26 +16,17 @@
11
16
  [![OpenCollective](https://opencollective.com/rubocop/sponsors/badge.svg)](#open-collective-sponsors)
12
17
  [![Tidelift](https://tidelift.com/badges/package/rubygems/rubocop)](https://tidelift.com/subscription/pkg/rubygems-rubocop?utm_source=rubygems-rubocop&utm_medium=referral&utm_campaign=readme)
13
18
 
14
- <p align="center">
15
- <img src="https://raw.githubusercontent.com/rubocop-hq/rubocop/master/logo/rubo-logo-horizontal.png" alt="RuboCop Logo"/>
16
- </p>
17
-
18
19
  > Role models are important. <br/>
19
20
  > -- Officer Alex J. Murphy / RoboCop
20
21
 
21
- **RuboCop** is a Ruby static code analyzer and code formatter. Out of
22
- the box it will enforce many of the guidelines outlined in the
23
- community [Ruby Style
24
- Guide](https://rubystyle.guide).
22
+ **RuboCop** is a Ruby static code analyzer (a.k.a. `linter`) and code formatter. Out of the box it
23
+ will enforce many of the guidelines outlined in the community [Ruby Style
24
+ Guide](https://rubystyle.guide). Apart from reporting the problems discovered in your code,
25
+ RuboCop can also automatically fix many of them you.
25
26
 
26
27
  RuboCop is extremely flexible and most aspects of its behavior can be tweaked via various
27
28
  [configuration options](https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml).
28
29
 
29
- Apart from reporting problems in your code, RuboCop can also
30
- automatically fix some of the problems for you.
31
-
32
- [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bbatsov/rubocop?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
33
-
34
30
  **Please consider [financially supporting its ongoing development](#funding).**
35
31
 
36
32
  ## Installation
@@ -53,7 +49,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
53
49
  might want to use a conservative version lock in your `Gemfile`:
54
50
 
55
51
  ```rb
56
- gem 'rubocop', '~> 0.84.0', require: false
52
+ gem 'rubocop', '~> 0.85.1', require: false
57
53
  ```
58
54
 
59
55
  ## 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