rubocop 1.6.1 → 1.7.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 +48 -6
- data/lib/rubocop.rb +4 -0
- data/lib/rubocop/config.rb +8 -5
- data/lib/rubocop/config_loader.rb +10 -6
- data/lib/rubocop/config_loader_resolver.rb +21 -4
- data/lib/rubocop/config_obsoletion.rb +5 -3
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +64 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
- data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
- data/lib/rubocop/cop/registry.rb +10 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
- data/lib/rubocop/cop/style/collection_methods.rb +14 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/hash_except.rb +95 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
- data/lib/rubocop/cop/style/single_line_methods.rb +4 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
- data/lib/rubocop/cop/util.rb +3 -1
- data/lib/rubocop/options.rb +9 -9
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/expect_offense.rb +34 -22
- data/lib/rubocop/runner.rb +16 -1
- data/lib/rubocop/target_finder.rb +4 -2
- data/lib/rubocop/util.rb +16 -0
- data/lib/rubocop/version.rb +8 -2
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe0d2cef28b14b92436ce28d483594398761fe11474f23e2577630e4c74d877d
|
4
|
+
data.tar.gz: 4c06f9d71ffc6b08ad14e9fbb574bcca19cfccc231c36aee75f23c7753643893
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a395e4004802da434ac704d5aec675b16637d464edc7d9305ec03c739a8d85f57f59d19f31187e93c7f37e9bcd7df6ec0b92df951de8e4508b169637cc7fb190
|
7
|
+
data.tar.gz: bac84ae15f62dafabde785bb46bf9e67d4554979fc09a431ee949b61ae03edac8897a6a914f153667eb6abdf803e73efe0a117c691d36d3ff73599ca3b41a13c
|
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.
|
54
|
+
gem 'rubocop', '~> 1.7', require: false
|
55
55
|
```
|
56
56
|
|
57
57
|
See [versioning](https://docs.rubocop.org/rubocop/1.0/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -473,7 +473,7 @@ Layout/EmptyLineBetweenDefs:
|
|
473
473
|
StyleGuide: '#empty-lines-between-methods'
|
474
474
|
Enabled: true
|
475
475
|
VersionAdded: '0.49'
|
476
|
-
VersionChanged: '1.
|
476
|
+
VersionChanged: '1.7'
|
477
477
|
EmptyLineBetweenMethodDefs: true
|
478
478
|
EmptyLineBetweenClassDefs: true
|
479
479
|
EmptyLineBetweenModuleDefs: true
|
@@ -1192,6 +1192,13 @@ Layout/SpaceBeforeBlockBraces:
|
|
1192
1192
|
- no_space
|
1193
1193
|
VersionChanged: '0.52'
|
1194
1194
|
|
1195
|
+
Layout/SpaceBeforeBrackets:
|
1196
|
+
Description: 'Checks for receiver with a space before the opening brackets.'
|
1197
|
+
StyleGuide: '#space-in-brackets-access'
|
1198
|
+
Enabled: pending
|
1199
|
+
VersionAdded: '1.7'
|
1200
|
+
Safe: false
|
1201
|
+
|
1195
1202
|
Layout/SpaceBeforeComma:
|
1196
1203
|
Description: 'No spaces before commas.'
|
1197
1204
|
Enabled: true
|
@@ -1354,6 +1361,11 @@ Layout/TrailingWhitespace:
|
|
1354
1361
|
#################### Lint ##################################
|
1355
1362
|
### Warnings
|
1356
1363
|
|
1364
|
+
Lint/AmbiguousAssignment:
|
1365
|
+
Description: 'Checks for mistyped shorthand assignments.'
|
1366
|
+
Enabled: pending
|
1367
|
+
VersionAdded: '1.7'
|
1368
|
+
|
1357
1369
|
Lint/AmbiguousBlockAssociation:
|
1358
1370
|
Description: >-
|
1359
1371
|
Checks for ambiguous block association with method when param passed without
|
@@ -1396,6 +1408,7 @@ Lint/BinaryOperatorWithIdenticalOperands:
|
|
1396
1408
|
Enabled: true
|
1397
1409
|
Safe: false
|
1398
1410
|
VersionAdded: '0.89'
|
1411
|
+
VersionChanged: '1.7'
|
1399
1412
|
|
1400
1413
|
Lint/BooleanSymbol:
|
1401
1414
|
Description: 'Check for `:true` and `:false` symbols.'
|
@@ -1472,6 +1485,9 @@ Lint/DuplicateBranch:
|
|
1472
1485
|
Description: Checks that there are no repeated bodies within `if/unless`, `case-when` and `rescue` constructs.
|
1473
1486
|
Enabled: pending
|
1474
1487
|
VersionAdded: '1.3'
|
1488
|
+
VersionChanged: '1.7'
|
1489
|
+
IgnoreLiteralBranches: false
|
1490
|
+
IgnoreConstantBranches: false
|
1475
1491
|
|
1476
1492
|
Lint/DuplicateCaseCondition:
|
1477
1493
|
Description: 'Do not repeat values in case conditionals.'
|
@@ -1842,6 +1858,8 @@ Lint/RedundantSplatExpansion:
|
|
1842
1858
|
Description: 'Checks for splat unnecessarily being called on literals.'
|
1843
1859
|
Enabled: true
|
1844
1860
|
VersionAdded: '0.76'
|
1861
|
+
VersionChanged: '1.7'
|
1862
|
+
AllowPercentLiteralArrayArgument: true
|
1845
1863
|
|
1846
1864
|
Lint/RedundantStringCoercion:
|
1847
1865
|
Description: 'Checks for Object#to_s usage in string interpolation.'
|
@@ -2045,6 +2063,11 @@ Lint/UnreachableLoop:
|
|
2045
2063
|
Description: 'This cop checks for loops that will have at most one iteration.'
|
2046
2064
|
Enabled: true
|
2047
2065
|
VersionAdded: '0.89'
|
2066
|
+
VersionChanged: '1.7'
|
2067
|
+
IgnoredPatterns:
|
2068
|
+
# RSpec uses `times` in its message expectations
|
2069
|
+
# eg. `exactly(2).times`
|
2070
|
+
- !ruby/regexp /(exactly|at_least|at_most)\(\d+\)\.times/
|
2048
2071
|
|
2049
2072
|
Lint/UnusedBlockArgument:
|
2050
2073
|
Description: 'Checks for unused block arguments.'
|
@@ -2895,7 +2918,7 @@ Style/CollectionMethods:
|
|
2895
2918
|
StyleGuide: '#map-find-select-reduce-include-size'
|
2896
2919
|
Enabled: false
|
2897
2920
|
VersionAdded: '0.9'
|
2898
|
-
VersionChanged: '
|
2921
|
+
VersionChanged: '1.7'
|
2899
2922
|
Safe: false
|
2900
2923
|
# Mapping from undesired method to desired method
|
2901
2924
|
# e.g. to use `detect` over `find`:
|
@@ -2910,6 +2933,11 @@ Style/CollectionMethods:
|
|
2910
2933
|
detect: 'find'
|
2911
2934
|
find_all: 'select'
|
2912
2935
|
member?: 'include?'
|
2936
|
+
# Methods in this array accept a final symbol as an implicit block
|
2937
|
+
# eg. `inject(:+)`
|
2938
|
+
MethodsAcceptingSymbol:
|
2939
|
+
- inject
|
2940
|
+
- reduce
|
2913
2941
|
|
2914
2942
|
Style/ColonMethodCall:
|
2915
2943
|
Description: 'Do not use :: for method call.'
|
@@ -2969,6 +2997,7 @@ Style/CommentedKeyword:
|
|
2969
2997
|
Description: 'Do not place comments on the same line as certain keywords.'
|
2970
2998
|
Enabled: true
|
2971
2999
|
VersionAdded: '0.51'
|
3000
|
+
VersionChanged: '1.7'
|
2972
3001
|
|
2973
3002
|
Style/ConditionalAssignment:
|
2974
3003
|
Description: >-
|
@@ -3328,6 +3357,13 @@ Style/HashEachMethods:
|
|
3328
3357
|
VersionAdded: '0.80'
|
3329
3358
|
Safe: false
|
3330
3359
|
|
3360
|
+
Style/HashExcept:
|
3361
|
+
Description: >-
|
3362
|
+
Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
|
3363
|
+
that can be replaced with `Hash#except` method.
|
3364
|
+
Enabled: pending
|
3365
|
+
VersionAdded: '1.7'
|
3366
|
+
|
3331
3367
|
Style/HashLikeCase:
|
3332
3368
|
Description: >-
|
3333
3369
|
Checks for places where `case-when` represents a simple 1:1
|
@@ -3482,6 +3518,7 @@ Style/KeywordParametersOrder:
|
|
3482
3518
|
StyleGuide: '#keyword-parameters-order'
|
3483
3519
|
Enabled: true
|
3484
3520
|
VersionAdded: '0.90'
|
3521
|
+
VersionChanged: '1.7'
|
3485
3522
|
|
3486
3523
|
Style/Lambda:
|
3487
3524
|
Description: 'Use the new lambda literal syntax for single-line blocks.'
|
@@ -3520,7 +3557,7 @@ Style/MethodCallWithArgsParentheses:
|
|
3520
3557
|
StyleGuide: '#method-invocation-parens'
|
3521
3558
|
Enabled: false
|
3522
3559
|
VersionAdded: '0.47'
|
3523
|
-
VersionChanged: '
|
3560
|
+
VersionChanged: '1.7'
|
3524
3561
|
IgnoreMacros: true
|
3525
3562
|
IgnoredMethods: []
|
3526
3563
|
IgnoredPatterns: []
|
@@ -3554,7 +3591,7 @@ Style/MethodDefParentheses:
|
|
3554
3591
|
StyleGuide: '#method-parens'
|
3555
3592
|
Enabled: true
|
3556
3593
|
VersionAdded: '0.16'
|
3557
|
-
VersionChanged: '
|
3594
|
+
VersionChanged: '1.7'
|
3558
3595
|
EnforcedStyle: require_parentheses
|
3559
3596
|
SupportedStyles:
|
3560
3597
|
- require_parentheses
|
@@ -3660,6 +3697,7 @@ Style/MultilineMethodSignature:
|
|
3660
3697
|
Description: 'Avoid multi-line method signatures.'
|
3661
3698
|
Enabled: false
|
3662
3699
|
VersionAdded: '0.59'
|
3700
|
+
VersionChanged: '1.7'
|
3663
3701
|
|
3664
3702
|
Style/MultilineTernaryOperator:
|
3665
3703
|
Description: >-
|
@@ -4026,12 +4064,16 @@ Style/RedundantArgument:
|
|
4026
4064
|
Enabled: pending
|
4027
4065
|
Safe: false
|
4028
4066
|
VersionAdded: '1.4'
|
4029
|
-
VersionChanged: '1.
|
4067
|
+
VersionChanged: '1.7'
|
4030
4068
|
Methods:
|
4031
4069
|
# Array#join
|
4032
4070
|
join: ''
|
4033
4071
|
# String#split
|
4034
4072
|
split: ' '
|
4073
|
+
# String#chomp
|
4074
|
+
chomp: "\n"
|
4075
|
+
# String#chomp!
|
4076
|
+
chomp!: "\n"
|
4035
4077
|
|
4036
4078
|
Style/RedundantAssignment:
|
4037
4079
|
Description: 'Checks for redundant assignment before returning.'
|
@@ -4288,7 +4330,7 @@ Style/SingleLineMethods:
|
|
4288
4330
|
StyleGuide: '#no-single-line-methods'
|
4289
4331
|
Enabled: true
|
4290
4332
|
VersionAdded: '0.9'
|
4291
|
-
VersionChanged: '
|
4333
|
+
VersionChanged: '1.7'
|
4292
4334
|
AllowIfMethodIsEmpty: true
|
4293
4335
|
|
4294
4336
|
Style/SlicingWithRange:
|
data/lib/rubocop.rb
CHANGED
@@ -28,6 +28,7 @@ require_relative 'rubocop/name_similarity'
|
|
28
28
|
require_relative 'rubocop/string_interpreter'
|
29
29
|
require_relative 'rubocop/error'
|
30
30
|
require_relative 'rubocop/warning'
|
31
|
+
require_relative 'rubocop/util'
|
31
32
|
|
32
33
|
require_relative 'rubocop/cop/util'
|
33
34
|
require_relative 'rubocop/cop/offense'
|
@@ -230,6 +231,7 @@ require_relative 'rubocop/cop/layout/space_around_keyword'
|
|
230
231
|
require_relative 'rubocop/cop/layout/space_around_method_call_operator'
|
231
232
|
require_relative 'rubocop/cop/layout/space_around_operators'
|
232
233
|
require_relative 'rubocop/cop/layout/space_before_block_braces'
|
234
|
+
require_relative 'rubocop/cop/layout/space_before_brackets'
|
233
235
|
require_relative 'rubocop/cop/layout/space_before_comma'
|
234
236
|
require_relative 'rubocop/cop/layout/space_before_comment'
|
235
237
|
require_relative 'rubocop/cop/layout/space_before_first_arg'
|
@@ -247,6 +249,7 @@ require_relative 'rubocop/cop/layout/space_inside_string_interpolation'
|
|
247
249
|
require_relative 'rubocop/cop/layout/trailing_empty_lines'
|
248
250
|
require_relative 'rubocop/cop/layout/trailing_whitespace'
|
249
251
|
|
252
|
+
require_relative 'rubocop/cop/lint/ambiguous_assignment'
|
250
253
|
require_relative 'rubocop/cop/lint/ambiguous_block_association'
|
251
254
|
require_relative 'rubocop/cop/lint/ambiguous_operator'
|
252
255
|
require_relative 'rubocop/cop/lint/ambiguous_regexp_literal'
|
@@ -460,6 +463,7 @@ require_relative 'rubocop/cop/style/global_vars'
|
|
460
463
|
require_relative 'rubocop/cop/style/guard_clause'
|
461
464
|
require_relative 'rubocop/cop/style/hash_as_last_array_item'
|
462
465
|
require_relative 'rubocop/cop/style/hash_each_methods'
|
466
|
+
require_relative 'rubocop/cop/style/hash_except'
|
463
467
|
require_relative 'rubocop/cop/style/hash_like_case'
|
464
468
|
require_relative 'rubocop/cop/style/hash_syntax'
|
465
469
|
require_relative 'rubocop/cop/style/hash_transform_keys'
|
data/lib/rubocop/config.rb
CHANGED
@@ -50,8 +50,8 @@ module RuboCop
|
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
53
|
-
def_delegators :@hash, :[], :[]=, :delete, :each, :key?, :keys, :each_key,
|
54
|
-
:fetch, :map, :merge, :to_h, :to_hash, :transform_values
|
53
|
+
def_delegators :@hash, :[], :[]=, :delete, :dig, :each, :key?, :keys, :each_key,
|
54
|
+
:fetch, :map, :merge, :replace, :to_h, :to_hash, :transform_values
|
55
55
|
def_delegators :@validator, :validate, :target_ruby_version
|
56
56
|
|
57
57
|
def to_s
|
@@ -281,6 +281,9 @@ module RuboCop
|
|
281
281
|
end
|
282
282
|
|
283
283
|
def enable_cop?(qualified_cop_name, cop_options)
|
284
|
+
# If the cop is explicitly enabled, the other checks can be skipped.
|
285
|
+
return true if cop_options['Enabled'] == true
|
286
|
+
|
284
287
|
department = department_of(qualified_cop_name)
|
285
288
|
cop_enabled = cop_options.fetch('Enabled') do
|
286
289
|
!for_all_cops['DisabledByDefault']
|
@@ -292,10 +295,10 @@ module RuboCop
|
|
292
295
|
end
|
293
296
|
|
294
297
|
def department_of(qualified_cop_name)
|
295
|
-
cop_department,
|
296
|
-
return nil if
|
298
|
+
*cop_department, _ = qualified_cop_name.split('/')
|
299
|
+
return nil if cop_department.empty?
|
297
300
|
|
298
|
-
self[cop_department]
|
301
|
+
self[cop_department.join('/')]
|
299
302
|
end
|
300
303
|
end
|
301
304
|
end
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
|
32
32
|
def clear_options
|
33
33
|
@debug = nil
|
34
|
+
@loaded_features = []
|
34
35
|
FileFinder.root_level = nil
|
35
36
|
end
|
36
37
|
|
@@ -177,12 +178,9 @@ module RuboCop
|
|
177
178
|
@loaded_features.flatten.compact
|
178
179
|
end
|
179
180
|
|
180
|
-
private
|
181
|
-
|
182
|
-
|
183
|
-
File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
|
184
|
-
end
|
185
|
-
|
181
|
+
# @api private
|
182
|
+
# Used to add features that were required inside a config or from
|
183
|
+
# the CLI using `--require`.
|
186
184
|
def add_loaded_features(loaded_features)
|
187
185
|
if instance_variable_defined?(:@loaded_features)
|
188
186
|
instance_variable_get(:@loaded_features) << loaded_features
|
@@ -191,6 +189,12 @@ module RuboCop
|
|
191
189
|
end
|
192
190
|
end
|
193
191
|
|
192
|
+
private
|
193
|
+
|
194
|
+
def file_path(file)
|
195
|
+
File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
|
196
|
+
end
|
197
|
+
|
194
198
|
def find_project_dotfile(target_dir)
|
195
199
|
find_file_upwards(DOTFILE, target_dir, project_root)
|
196
200
|
end
|
@@ -20,12 +20,13 @@ module RuboCop
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
# rubocop:disable Metrics/MethodLength
|
24
|
-
def resolve_inheritance(path, hash, file, debug)
|
23
|
+
def resolve_inheritance(path, hash, file, debug) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
25
24
|
inherited_files = Array(hash['inherit_from'])
|
26
25
|
base_configs(path, inherited_files, file)
|
27
26
|
.reverse.each_with_index do |base_config, index|
|
28
27
|
override_department_setting_for_cops(base_config, hash)
|
28
|
+
override_enabled_for_disabled_departments(base_config, hash)
|
29
|
+
|
29
30
|
base_config.each do |k, v|
|
30
31
|
next unless v.is_a?(Hash)
|
31
32
|
|
@@ -39,7 +40,6 @@ module RuboCop
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
# rubocop:enable Metrics/MethodLength
|
43
43
|
|
44
44
|
def resolve_inheritance_from_gems(hash)
|
45
45
|
gems = hash.delete('inherit_gem')
|
@@ -75,6 +75,7 @@ module RuboCop
|
|
75
75
|
end
|
76
76
|
|
77
77
|
config = handle_disabled_by_default(config, default_configuration) if disabled_by_default
|
78
|
+
override_enabled_for_disabled_departments(default_configuration, config)
|
78
79
|
|
79
80
|
opts = { inherit_mode: config['inherit_mode'] || {},
|
80
81
|
unset_nil: unset_nil }
|
@@ -122,10 +123,26 @@ module RuboCop
|
|
122
123
|
end
|
123
124
|
end
|
124
125
|
|
126
|
+
# If a cop was previously explicitly enabled, but then superseded by the
|
127
|
+
# department being disabled, disable it.
|
128
|
+
def override_enabled_for_disabled_departments(base_hash, derived_hash)
|
129
|
+
cops_to_disable = derived_hash.each_key.with_object([]) do |key, cops|
|
130
|
+
next unless disabled?(derived_hash, key)
|
131
|
+
|
132
|
+
cops.concat(base_hash.keys.grep(Regexp.new("^#{key}/")))
|
133
|
+
end
|
134
|
+
|
135
|
+
cops_to_disable.each do |cop_name|
|
136
|
+
next unless base_hash.dig(cop_name, 'Enabled') == true
|
137
|
+
|
138
|
+
derived_hash.replace(merge({ cop_name => { 'Enabled' => false } }, derived_hash))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
125
142
|
private
|
126
143
|
|
127
144
|
def disabled?(hash, department)
|
128
|
-
hash[department] && hash[department]['Enabled'] == false
|
145
|
+
hash[department].is_a?(Hash) && hash[department]['Enabled'] == false
|
129
146
|
end
|
130
147
|
|
131
148
|
def duplicate_setting?(base_hash, derived_hash, key, inherited_file)
|
@@ -63,9 +63,11 @@ module RuboCop
|
|
63
63
|
# Cop rules are keyed by the name of the original cop
|
64
64
|
def load_cop_rules(rules)
|
65
65
|
rules.flat_map do |rule_type, data|
|
66
|
-
data.map do |configuration|
|
67
|
-
|
68
|
-
|
66
|
+
data.map do |cop_name, configuration|
|
67
|
+
next unless configuration # allow configurations to be disabled with `CopName: ~`
|
68
|
+
|
69
|
+
COP_RULE_CLASSES[rule_type].new(@config, cop_name, configuration)
|
70
|
+
end.compact
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
@@ -36,12 +36,13 @@ module RuboCop
|
|
36
36
|
# spec.required_ruby_version = '>= 2.5'
|
37
37
|
# end
|
38
38
|
#
|
39
|
-
# #
|
39
|
+
# # accepted but not recommended
|
40
40
|
# Gem::Specification.new do |spec|
|
41
41
|
# spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0']
|
42
42
|
# end
|
43
43
|
#
|
44
|
-
# #
|
44
|
+
# # accepted but not recommended, since
|
45
|
+
# # Ruby does not really follow semantic versionning
|
45
46
|
# Gem::Specification.new do |spec|
|
46
47
|
# spec.required_ruby_version = '~> 2.5'
|
47
48
|
# end
|
@@ -6,4 +6,5 @@ require_relative 'internal_affairs/node_type_predicate'
|
|
6
6
|
require_relative 'internal_affairs/offense_location_keyword'
|
7
7
|
require_relative 'internal_affairs/redundant_message_argument'
|
8
8
|
require_relative 'internal_affairs/redundant_location_argument'
|
9
|
+
require_relative 'internal_affairs/style_detected_api_use'
|
9
10
|
require_relative 'internal_affairs/useless_message_assertion'
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Checks for correct use of the style_detected API provided by
|
7
|
+
# `ConfigurableEnforcedStyle`. If `correct_style_detected` is used
|
8
|
+
# then `opposite_style_detected`, `unexpected_style_detected`,
|
9
|
+
# `ambiguous_style_detected`, `conflicting_styles_detected`,
|
10
|
+
# `unrecognized_style_detected` or `no_acceptable_style!` should be
|
11
|
+
# used too, and vice versa. The `xxx_style_detected` methods
|
12
|
+
# should not be used as predicates either.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# def on_send(node)
|
18
|
+
# return add_offense(node) if opposite_style_detected
|
19
|
+
#
|
20
|
+
# correct_style_detected
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def on_send(node)
|
24
|
+
# if offense?
|
25
|
+
# add_offense(node)
|
26
|
+
# else
|
27
|
+
# correct_style_detected
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def on_send(node)
|
32
|
+
# return unless offense?
|
33
|
+
#
|
34
|
+
# add_offense(node)
|
35
|
+
# opposite_style_detected
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # good
|
39
|
+
# def on_send(node)
|
40
|
+
# if offense?
|
41
|
+
# add_offense(node)
|
42
|
+
# opposite_style_detected
|
43
|
+
# else
|
44
|
+
# correct_style_detected
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def on_send(node)
|
49
|
+
# add_offense(node) if offense?
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
class StyleDetectedApiUse < Base
|
53
|
+
include RangeHelp
|
54
|
+
|
55
|
+
MSG_FOR_POSITIVE_WITHOUT_NEGATIVE =
|
56
|
+
'`correct_style_detected` method called without ' \
|
57
|
+
'calling a negative `*_style_detected` method.'
|
58
|
+
MSG_FOR_NEGATIVE_WITHOUT_POSITIVE =
|
59
|
+
'negative `*_style_detected` methods called without ' \
|
60
|
+
'calling `correct_style_detected` method.'
|
61
|
+
MSG_FOR_CONDITIONAL_USE =
|
62
|
+
'`*_style_detected` method called in conditional.'
|
63
|
+
RESTRICT_ON_SEND = %i[
|
64
|
+
correct_style_detected opposite_style_detected
|
65
|
+
unexpected_style_detected ambiguous_style_detected
|
66
|
+
conflicting_styles_detected unrecognized_style_detected
|
67
|
+
no_acceptable_style! style_detected
|
68
|
+
].freeze
|
69
|
+
|
70
|
+
def_node_matcher :correct_style_detected_check, <<~PATTERN
|
71
|
+
(send nil? :correct_style_detected)
|
72
|
+
PATTERN
|
73
|
+
|
74
|
+
def_node_matcher :negative_style_detected_method_check, <<~PATTERN
|
75
|
+
(send nil? /(?:opposite|unexpected|ambiguous|unrecognized)_style_detected|conflicting_styles_detected/ ...)
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def_node_matcher :no_acceptable_style_check, <<~PATTERN
|
79
|
+
(send nil? :no_acceptable_style!)
|
80
|
+
PATTERN
|
81
|
+
|
82
|
+
def_node_matcher :style_detected_check, <<~PATTERN
|
83
|
+
(send nil? :style_detected ...)
|
84
|
+
PATTERN
|
85
|
+
|
86
|
+
def on_new_investigation
|
87
|
+
@correct_style_detected_called = false
|
88
|
+
@negative_style_detected_methods_called = false
|
89
|
+
@style_detected_called = false
|
90
|
+
end
|
91
|
+
|
92
|
+
def on_investigation_end
|
93
|
+
return if style_detected_called
|
94
|
+
return unless correct_style_detected_called ^ negative_style_detected_methods_called
|
95
|
+
|
96
|
+
add_global_offense(MSG_FOR_POSITIVE_WITHOUT_NEGATIVE) if positive_without_negative?
|
97
|
+
add_global_offense(MSG_FOR_NEGATIVE_WITHOUT_POSITIVE) if negative_without_positive?
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_send(node)
|
101
|
+
if correct_style_detected_check(node)
|
102
|
+
@correct_style_detected_called = true
|
103
|
+
elsif negative_style_detected_method_check(node) || no_acceptable_style_check(node)
|
104
|
+
@negative_style_detected_methods_called = true
|
105
|
+
elsif style_detected_check(node)
|
106
|
+
@style_detected_called = true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def on_if(node)
|
111
|
+
traverse_condition(node.condition) do |cond|
|
112
|
+
add_offense(cond, message: MSG_FOR_CONDITIONAL_USE) if style_detected_api_used?(cond)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
attr_reader :correct_style_detected_called,
|
119
|
+
:negative_style_detected_methods_called,
|
120
|
+
:style_detected_called
|
121
|
+
|
122
|
+
def positive_without_negative?
|
123
|
+
correct_style_detected_called && !negative_style_detected_methods_called
|
124
|
+
end
|
125
|
+
|
126
|
+
def negative_without_positive?
|
127
|
+
negative_style_detected_methods_called && !correct_style_detected_called
|
128
|
+
end
|
129
|
+
|
130
|
+
def style_detected_api_used?(node)
|
131
|
+
correct_style_detected_check(node) ||
|
132
|
+
negative_style_detected_method_check(node) ||
|
133
|
+
no_acceptable_style_check(node) ||
|
134
|
+
style_detected_check(node)
|
135
|
+
end
|
136
|
+
|
137
|
+
def traverse_condition(condition, &block)
|
138
|
+
yield condition if condition.send_type?
|
139
|
+
|
140
|
+
condition.each_child_node { |child| traverse_condition(child, &block) }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|