rubocop 0.38.0 → 0.39.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/config/default.yml +13 -0
- data/config/enabled.yml +15 -3
- data/lib/rubocop.rb +2 -0
- data/lib/rubocop/ast_node/builder.rb +6 -0
- data/lib/rubocop/cli.rb +2 -2
- data/lib/rubocop/config.rb +13 -13
- data/lib/rubocop/config_loader.rb +5 -28
- data/lib/rubocop/config_loader_resolver.rb +42 -0
- data/lib/rubocop/cop/cop.rb +4 -5
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +9 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -4
- data/lib/rubocop/cop/performance/case_when_splat.rb +1 -1
- data/lib/rubocop/cop/performance/count.rb +20 -0
- data/lib/rubocop/cop/performance/detect.rb +12 -0
- data/lib/rubocop/cop/performance/redundant_merge.rb +10 -1
- data/lib/rubocop/cop/performance/times_map.rb +14 -0
- data/lib/rubocop/cop/style/case_indentation.rb +14 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +221 -20
- data/lib/rubocop/cop/style/file_name.rb +31 -17
- data/lib/rubocop/cop/style/if_unless_modifier.rb +8 -0
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +45 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -2
- data/lib/rubocop/cop/style/next.rb +6 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +37 -8
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -0
- data/lib/rubocop/cop/style/redundant_self.rb +1 -1
- data/lib/rubocop/cop/style/space_around_keyword.rb +10 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +23 -14
- data/lib/rubocop/cop/style/zero_length_predicate.rb +25 -0
- data/lib/rubocop/formatter/html_formatter.rb +3 -3
- data/lib/rubocop/result_cache.rb +2 -2
- data/lib/rubocop/runner.rb +3 -3
- data/lib/rubocop/target_finder.rb +2 -6
- data/lib/rubocop/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfcbbab3c5c192b9ec4f2af0d65ef6af2218196a
|
4
|
+
data.tar.gz: 13951f737deacbbca91730cafca92ed861e5b4b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 938228431a9934dc8916618e35256c75bf5a95ad3387933019599ecc242a3281ce2a234f3a174793634b44bcf5043b924ee18f1949f3abfd97e67c8db1aea088
|
7
|
+
data.tar.gz: 20459e73a5a9fbe29eeac14413a6f2e54253692d474e01cde4ec1155dfff8010a1202297b1d35a4d422cddc27d7d15a2f633725d1ebe6e63ffff41bf672f8114
|
data/README.md
CHANGED
@@ -115,7 +115,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
|
|
115
115
|
might want to use a conservative version locking in your `Gemfile`:
|
116
116
|
|
117
117
|
```rb
|
118
|
-
gem 'rubocop', '~> 0.
|
118
|
+
gem 'rubocop', '~> 0.39.0', require: false
|
119
119
|
```
|
120
120
|
|
121
121
|
## Basic Usage
|
@@ -289,7 +289,14 @@ Metrics/LineLength:
|
|
289
289
|
### Inheritance
|
290
290
|
|
291
291
|
RuboCop supports inheriting configuration from one or more supplemental
|
292
|
-
configuration files at runtime.
|
292
|
+
configuration files at runtime. Settings in the file that inherits
|
293
|
+
override settings in the file that's inherited from. Configuration
|
294
|
+
parameter that are hashes, for example `PreferredMethods` in
|
295
|
+
`Style/CollectionMethods` are merged with the same parameter in the base
|
296
|
+
configuration, while other parameter, such as `AllCops` / `Include`, are
|
297
|
+
simply replaced by the local setting. If arrays were merged, there would
|
298
|
+
be no way to remove elements through overriding them in local
|
299
|
+
configuration.
|
293
300
|
|
294
301
|
#### Inheriting from another configuration file in the project
|
295
302
|
|
@@ -1017,7 +1024,8 @@ require:
|
|
1017
1024
|
|
1018
1025
|
Note: The paths are directly passed to `Kernel.require`. If your
|
1019
1026
|
extension file is not in `$LOAD_PATH`, you need to specify the path as
|
1020
|
-
relative path prefixed with `./` explicitly, or absolute path.
|
1027
|
+
relative path prefixed with `./` explicitly, or absolute path. Paths
|
1028
|
+
starting with a `.` are resolved relative to `.rubocop.yml`.
|
1021
1029
|
|
1022
1030
|
### Custom Cops
|
1023
1031
|
|
data/config/default.yml
CHANGED
@@ -344,6 +344,19 @@ Style/CommentAnnotation:
|
|
344
344
|
- HACK
|
345
345
|
- REVIEW
|
346
346
|
|
347
|
+
Style/ConditionalAssignment:
|
348
|
+
EnforcedStyle: assign_to_condition
|
349
|
+
SupportedStyles:
|
350
|
+
- assign_to_condition
|
351
|
+
- assign_inside_condition
|
352
|
+
# When configured to `assign_to_condition`, `SingleLineConditionsOnly`
|
353
|
+
# will only register an offense when all branches of a condition are
|
354
|
+
# a single line.
|
355
|
+
# When configured to `assign_inside_condition`, `SingleLineConditionsOnly`
|
356
|
+
# will only register an offense for assignment to a condition that has
|
357
|
+
# at least one multiline branch.
|
358
|
+
SingleLineConditionsOnly: true
|
359
|
+
|
347
360
|
# Checks that you have put a copyright in a comment before any code.
|
348
361
|
#
|
349
362
|
# You can override the default Notice in your .rubocop.yml file.
|
data/config/enabled.yml
CHANGED
@@ -159,9 +159,6 @@ Style/ConditionalAssignment:
|
|
159
159
|
assignment to a variable and variable comparison instead
|
160
160
|
of assigning that variable inside of each branch.
|
161
161
|
Enabled: true
|
162
|
-
SingleLineConditionsOnly: true
|
163
|
-
# Whether the cop should register offenses for conditionals whose branches
|
164
|
-
# contain more than one statement a piece
|
165
162
|
|
166
163
|
Style/ConstantName:
|
167
164
|
Description: 'Constants should use SCREAMING_SNAKE_CASE.'
|
@@ -324,6 +321,11 @@ Style/IfUnlessModifier:
|
|
324
321
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier'
|
325
322
|
Enabled: true
|
326
323
|
|
324
|
+
Style/IfUnlessModifierOfIfUnless:
|
325
|
+
Description: >-
|
326
|
+
Avoid modifier if/unless usage on conditionals.
|
327
|
+
Enabled: true
|
328
|
+
|
327
329
|
Style/IfWithSemicolon:
|
328
330
|
Description: 'Do not use if x; .... Use the ternary operator instead.'
|
329
331
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs'
|
@@ -1173,6 +1175,11 @@ Performance/Count:
|
|
1173
1175
|
Use `count` instead of `select...size`, `reject...size`,
|
1174
1176
|
`select...count`, `reject...count`, `select...length`,
|
1175
1177
|
and `reject...length`.
|
1178
|
+
# This cop has known compatibility issues with `ActiveRecord` and other
|
1179
|
+
# frameworks. ActiveRecord's `count` ignores the block that is passed to it.
|
1180
|
+
# For more information, see the documentation in the cop itself.
|
1181
|
+
# If you understand the known risk, you can disable `SafeMode`.
|
1182
|
+
SafeMode: true
|
1176
1183
|
Enabled: true
|
1177
1184
|
|
1178
1185
|
Performance/Detect:
|
@@ -1180,6 +1187,11 @@ Performance/Detect:
|
|
1180
1187
|
Use `detect` instead of `select.first`, `find_all.first`,
|
1181
1188
|
`select.last`, and `find_all.last`.
|
1182
1189
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
|
1190
|
+
# This cop has known compatibility issues with `ActiveRecord` and other
|
1191
|
+
# frameworks. `ActiveRecord` does not implement a `detect` method and `find`
|
1192
|
+
# has its own meaning. Correcting `ActiveRecord` methods with this cop
|
1193
|
+
# should be considered unsafe.
|
1194
|
+
SafeMode: true
|
1183
1195
|
Enabled: true
|
1184
1196
|
|
1185
1197
|
Performance/DoubleStartEndWith:
|
data/lib/rubocop.rb
CHANGED
@@ -238,6 +238,7 @@ require 'rubocop/cop/style/hash_syntax'
|
|
238
238
|
require 'rubocop/cop/style/identical_conditional_branches'
|
239
239
|
require 'rubocop/cop/style/if_inside_else'
|
240
240
|
require 'rubocop/cop/style/if_unless_modifier'
|
241
|
+
require 'rubocop/cop/style/if_unless_modifier_of_if_unless'
|
241
242
|
require 'rubocop/cop/style/if_with_semicolon'
|
242
243
|
require 'rubocop/cop/style/indent_array'
|
243
244
|
require 'rubocop/cop/style/indent_assignment'
|
@@ -387,6 +388,7 @@ require 'rubocop/formatter/formatter_set'
|
|
387
388
|
|
388
389
|
require 'rubocop/cached_data'
|
389
390
|
require 'rubocop/config'
|
391
|
+
require 'rubocop/config_loader_resolver'
|
390
392
|
require 'rubocop/config_loader'
|
391
393
|
require 'rubocop/config_store'
|
392
394
|
require 'rubocop/target_finder'
|
@@ -20,6 +20,12 @@ module RuboCop
|
|
20
20
|
def n(type, children, source_map)
|
21
21
|
Node.new(type, children, location: source_map)
|
22
22
|
end
|
23
|
+
|
24
|
+
# TODO: Figure out what to do about literal encoding handling...
|
25
|
+
# More details here https://github.com/whitequark/parser/issues/283
|
26
|
+
def string_value(token)
|
27
|
+
value(token)
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
25
31
|
end
|
data/lib/rubocop/cli.rb
CHANGED
@@ -85,8 +85,8 @@ module RuboCop
|
|
85
85
|
# This must be done after the options have already been processed,
|
86
86
|
# because they can affect how ConfigStore behaves
|
87
87
|
@options[:formatters] ||= begin
|
88
|
-
cfg = @config_store.for(Dir.pwd)
|
89
|
-
formatter =
|
88
|
+
cfg = @config_store.for(Dir.pwd).for_all_cops
|
89
|
+
formatter = cfg['DefaultFormatter'] || 'progress'
|
90
90
|
[[formatter, @options[:output_path]]]
|
91
91
|
end
|
92
92
|
|
data/lib/rubocop/config.rb
CHANGED
@@ -66,12 +66,10 @@ module RuboCop
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def add_excludes_from_higher_level(highest_config)
|
69
|
-
return unless highest_config['
|
70
|
-
highest_config['AllCops']['Exclude']
|
69
|
+
return unless highest_config.for_all_cops['Exclude']
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
highest_config['AllCops']['Exclude'].each do |path|
|
71
|
+
excludes = for_all_cops['Exclude'] ||= []
|
72
|
+
highest_config.for_all_cops['Exclude'].each do |path|
|
75
73
|
unless path.is_a?(Regexp) || absolute?(path)
|
76
74
|
path = File.join(File.dirname(highest_config.loaded_path), path)
|
77
75
|
end
|
@@ -80,14 +78,12 @@ module RuboCop
|
|
80
78
|
end
|
81
79
|
|
82
80
|
def deprecation_check
|
83
|
-
return unless (all_cops = self['AllCops'])
|
84
|
-
|
85
81
|
%w(Exclude Include).each do |key|
|
86
82
|
plural = "#{key}s"
|
87
|
-
next unless
|
83
|
+
next unless for_all_cops[plural]
|
88
84
|
|
89
|
-
|
90
|
-
|
85
|
+
for_all_cops[key] = for_all_cops[plural] # Stay backwards compatible.
|
86
|
+
for_all_cops.delete(plural)
|
91
87
|
yield "AllCops/#{plural} was renamed to AllCops/#{key}"
|
92
88
|
end
|
93
89
|
end
|
@@ -96,6 +92,10 @@ module RuboCop
|
|
96
92
|
@for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop]
|
97
93
|
end
|
98
94
|
|
95
|
+
def for_all_cops
|
96
|
+
@for_all_cops ||= self['AllCops'] || {}
|
97
|
+
end
|
98
|
+
|
99
99
|
def cop_enabled?(cop)
|
100
100
|
department = cop.cop_type.to_s.capitalize!
|
101
101
|
|
@@ -167,11 +167,11 @@ module RuboCop
|
|
167
167
|
end
|
168
168
|
|
169
169
|
def patterns_to_include
|
170
|
-
@patterns_to_include ||=
|
170
|
+
@patterns_to_include ||= for_all_cops['Include']
|
171
171
|
end
|
172
172
|
|
173
173
|
def patterns_to_exclude
|
174
|
-
@patterns_to_exclude ||=
|
174
|
+
@patterns_to_exclude ||= for_all_cops['Exclude']
|
175
175
|
end
|
176
176
|
|
177
177
|
def path_relative_to_config(path)
|
@@ -272,7 +272,7 @@ module RuboCop
|
|
272
272
|
end
|
273
273
|
|
274
274
|
def check_target_ruby
|
275
|
-
target =
|
275
|
+
target = for_all_cops['TargetRubyVersion']
|
276
276
|
return unless target
|
277
277
|
|
278
278
|
unless KNOWN_RUBIES.include?(target)
|
@@ -17,6 +17,8 @@ module RuboCop
|
|
17
17
|
AUTO_GENERATED_FILE = '.rubocop_todo.yml'.freeze
|
18
18
|
|
19
19
|
class << self
|
20
|
+
include ConfigLoaderResolver
|
21
|
+
|
20
22
|
attr_accessor :debug, :auto_gen_config
|
21
23
|
attr_writer :root_level # The upwards search is stopped at this level.
|
22
24
|
attr_writer :default_configuration
|
@@ -34,11 +36,7 @@ module RuboCop
|
|
34
36
|
|
35
37
|
resolve_inheritance_from_gems(hash, hash.delete('inherit_gem'))
|
36
38
|
resolve_inheritance(path, hash)
|
37
|
-
|
38
|
-
config_dir = File.dirname(path)
|
39
|
-
Array(hash.delete('require')).each do |r|
|
40
|
-
require(File.join(config_dir, r))
|
41
|
-
end
|
39
|
+
resolve_requires(path, hash)
|
42
40
|
|
43
41
|
hash.delete('inherit_from')
|
44
42
|
config = Config.new(hash, path)
|
@@ -119,7 +117,7 @@ module RuboCop
|
|
119
117
|
# that only cops from user configuration are enabled.
|
120
118
|
def merge_with_default(config, config_file)
|
121
119
|
configs =
|
122
|
-
if config.
|
120
|
+
if config.for_all_cops['DisabledByDefault']
|
123
121
|
disabled_default = transform(default_configuration) do |params|
|
124
122
|
params.merge('Enabled' => false) # Overwrite with false.
|
125
123
|
end
|
@@ -161,7 +159,7 @@ module RuboCop
|
|
161
159
|
|
162
160
|
def yaml_safe_load(yaml_code)
|
163
161
|
if YAML.respond_to?(:safe_load) # Ruby 2.1+
|
164
|
-
if defined?(SafeYAML)
|
162
|
+
if defined?(SafeYAML) && SafeYAML.respond_to?(:load)
|
165
163
|
SafeYAML.load(yaml_code, nil, whitelisted_tags: %w(!ruby/regexp))
|
166
164
|
else
|
167
165
|
YAML.safe_load(yaml_code, [Regexp])
|
@@ -171,27 +169,6 @@ module RuboCop
|
|
171
169
|
end
|
172
170
|
end
|
173
171
|
|
174
|
-
def resolve_inheritance(path, hash)
|
175
|
-
base_configs(path, hash['inherit_from']).reverse_each do |base_config|
|
176
|
-
base_config.each do |k, v|
|
177
|
-
hash[k] = hash.key?(k) ? merge(v, hash[k]) : v if v.is_a?(Hash)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def resolve_inheritance_from_gems(hash, gems)
|
183
|
-
(gems || {}).each_pair do |gem_name, config_path|
|
184
|
-
if gem_name == 'rubocop'
|
185
|
-
raise ArgumentError,
|
186
|
-
"can't inherit configuration from the rubocop gem"
|
187
|
-
end
|
188
|
-
|
189
|
-
hash['inherit_from'] = Array(hash['inherit_from'])
|
190
|
-
# Put gem configuration first so local configuration overrides it.
|
191
|
-
hash['inherit_from'].unshift gem_config_path(gem_name, config_path)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
172
|
def gem_config_path(gem_name, relative_config_path)
|
196
173
|
spec = Gem::Specification.find_by_name(gem_name)
|
197
174
|
return File.join(spec.gem_dir, relative_config_path)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module RuboCop
|
8
|
+
# A mixin to break up ConfigLoader
|
9
|
+
module ConfigLoaderResolver
|
10
|
+
def resolve_requires(path, hash)
|
11
|
+
config_dir = File.dirname(path)
|
12
|
+
Array(hash.delete('require')).each do |r|
|
13
|
+
if r.start_with?('.')
|
14
|
+
require(File.join(config_dir, r))
|
15
|
+
else
|
16
|
+
require(r)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def resolve_inheritance(path, hash)
|
22
|
+
base_configs(path, hash['inherit_from']).reverse_each do |base_config|
|
23
|
+
base_config.each do |k, v|
|
24
|
+
hash[k] = hash.key?(k) ? merge(v, hash[k]) : v if v.is_a?(Hash)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolve_inheritance_from_gems(hash, gems)
|
30
|
+
(gems || {}).each_pair do |gem_name, config_path|
|
31
|
+
if gem_name == 'rubocop'
|
32
|
+
raise ArgumentError,
|
33
|
+
"can't inherit configuration from the rubocop gem"
|
34
|
+
end
|
35
|
+
|
36
|
+
hash['inherit_from'] = Array(hash['inherit_from'])
|
37
|
+
# Put gem configuration first so local configuration overrides it.
|
38
|
+
hash['inherit_from'].unshift gem_config_path(gem_name, config_path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/rubocop/cop/cop.rb
CHANGED
@@ -138,18 +138,17 @@ module RuboCop
|
|
138
138
|
|
139
139
|
def display_cop_names?
|
140
140
|
debug? || @options[:display_cop_names] ||
|
141
|
-
config['
|
141
|
+
@config.for_all_cops['DisplayCopNames']
|
142
142
|
end
|
143
143
|
|
144
144
|
def display_style_guide?
|
145
145
|
(style_guide_url || reference_url) &&
|
146
146
|
(@options[:display_style_guide] ||
|
147
|
-
config['
|
147
|
+
config.for_all_cops['DisplayStyleGuide'])
|
148
148
|
end
|
149
149
|
|
150
150
|
def extra_details?
|
151
|
-
@options[:extra_details] ||
|
152
|
-
config['AllCops'] && config['AllCops']['ExtraDetails']
|
151
|
+
@options[:extra_details] || config.for_all_cops['ExtraDetails']
|
153
152
|
end
|
154
153
|
|
155
154
|
def message(_node = nil)
|
@@ -194,7 +193,7 @@ module RuboCop
|
|
194
193
|
end
|
195
194
|
|
196
195
|
def target_ruby_version
|
197
|
-
@config['
|
196
|
+
@config.for_all_cops['TargetRubyVersion']
|
198
197
|
end
|
199
198
|
|
200
199
|
def parse(source, path = nil)
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
traverse_node(condition, ASGN_TYPES) do |asgn_node|
|
35
35
|
if asgn_node.type == :send
|
36
36
|
_receiver, method_name, *_args = *asgn_node
|
37
|
-
next :skip_children if method_name
|
37
|
+
next :skip_children if method_name !~ /=\z/
|
38
38
|
end
|
39
39
|
|
40
40
|
# skip safe assignment nodes if safe assignment is allowed
|
@@ -11,14 +11,14 @@ module RuboCop
|
|
11
11
|
# "result is #{10}"
|
12
12
|
class LiteralInInterpolation < Cop
|
13
13
|
MSG = 'Literal interpolation detected.'.freeze
|
14
|
+
COMPOSITE = [:array, :hash, :pair, :irange, :erange].freeze
|
14
15
|
|
15
16
|
def on_dstr(node)
|
16
17
|
node.children.select { |n| n.type == :begin }.each do |begin_node|
|
17
18
|
final_node = begin_node.children.last
|
18
19
|
next unless final_node
|
19
20
|
next if special_keyword?(final_node)
|
20
|
-
next
|
21
|
-
next unless final_node.literal?
|
21
|
+
next unless prints_as_self?(final_node)
|
22
22
|
|
23
23
|
add_offense(final_node, :expression)
|
24
24
|
end
|
@@ -58,6 +58,13 @@ module RuboCop
|
|
58
58
|
node.loc.begin.end_pos,
|
59
59
|
end_pos).source
|
60
60
|
end
|
61
|
+
|
62
|
+
# Does node print its own source when converted to a string?
|
63
|
+
def prints_as_self?(node)
|
64
|
+
node.basic_literal? ||
|
65
|
+
(COMPOSITE.include?(node.type) &&
|
66
|
+
node.children.all? { |child| prints_as_self?(child) })
|
67
|
+
end
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
@@ -20,14 +20,15 @@ module RuboCop
|
|
20
20
|
return false if body_has_comment?(body)
|
21
21
|
return false if end_keyword_has_comment?(node)
|
22
22
|
|
23
|
+
length_in_modifier_form(node, cond, body_length) <= max_line_length
|
24
|
+
end
|
25
|
+
|
26
|
+
def length_in_modifier_form(node, cond, body_length)
|
23
27
|
indentation = node.loc.keyword.column
|
24
28
|
kw_length = node.loc.keyword.size
|
25
29
|
cond_length = cond.source_range.size
|
26
30
|
space = 1
|
27
|
-
|
28
|
-
cond_length
|
29
|
-
|
30
|
-
total <= max_line_length
|
31
|
+
indentation + body_length + space + kw_length + space + cond_length
|
31
32
|
end
|
32
33
|
|
33
34
|
def max_line_length
|
@@ -101,7 +101,7 @@ module RuboCop
|
|
101
101
|
def splat_offenses(when_conditions)
|
102
102
|
found_non_splat = false
|
103
103
|
when_conditions.reverse.each_with_object([]) do |condition, result|
|
104
|
-
found_non_splat ||=
|
104
|
+
found_non_splat ||= error_condition?(condition)
|
105
105
|
|
106
106
|
next unless condition.splat_type?
|
107
107
|
result << condition if found_non_splat
|
@@ -25,6 +25,19 @@ module RuboCop
|
|
25
25
|
# [1, 2, 3].count { |e| e < 2 && e.even? }
|
26
26
|
# Model.select('field AS field_one').count
|
27
27
|
# Model.select(:value).count
|
28
|
+
#
|
29
|
+
# `ActiveRecord` compatibility:
|
30
|
+
# `ActiveRecord` will ignore the block that is passed to `count`.
|
31
|
+
# Other methods, such as `select`, will convert the association to an
|
32
|
+
# array and then run the block on the array. A simple work around to
|
33
|
+
# make `count` work with a block is to call `to_a.count {...}`.
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# Model.where(id: [1, 2, 3].select { |m| m.method == true }.size
|
37
|
+
#
|
38
|
+
# becomes:
|
39
|
+
#
|
40
|
+
# Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }
|
28
41
|
class Count < Cop
|
29
42
|
MSG = 'Use `count` instead of `%s...%s`.'.freeze
|
30
43
|
|
@@ -32,6 +45,7 @@ module RuboCop
|
|
32
45
|
COUNTERS = [:count, :length, :size].freeze
|
33
46
|
|
34
47
|
def on_send(node)
|
48
|
+
return unless should_run?
|
35
49
|
selector, selector_loc, params, counter = parse(node)
|
36
50
|
return unless COUNTERS.include?(counter)
|
37
51
|
return unless SELECTORS.include?(selector)
|
@@ -62,6 +76,12 @@ module RuboCop
|
|
62
76
|
|
63
77
|
private
|
64
78
|
|
79
|
+
def should_run?
|
80
|
+
!(cop_config['SafeMode'.freeze] ||
|
81
|
+
config['Rails'.freeze] &&
|
82
|
+
config['Rails'.freeze]['Enabled'.freeze])
|
83
|
+
end
|
84
|
+
|
65
85
|
def parse(node)
|
66
86
|
left, counter = *node
|
67
87
|
expression, selector, params = *left
|