rubocop 0.85.0 → 0.85.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edfaa1a180e5c318e672651ae7e4c75625a41a4c247d3ce378f6e25e809a4277
4
- data.tar.gz: 8ce15a32ddd8181b7b5117214d00a795f8824cbd13282120545fc7dd58548137
3
+ metadata.gz: 86b240fb0a653934db99c6ca12a1c53976c01f3d6de666842e9f7146f207f725
4
+ data.tar.gz: 606ea84dc8c148971ba8a2dc17ef2a03bbb48802e6053f5042d180e0f6c7c15f
5
5
  SHA512:
6
- metadata.gz: 57f80040236ae265d1478fecbbe20ebfd27905d52cd2c06d83202d2a8d7fe426feb774d63788fd38942872a12c18c247896e89f21c7010259ab1902cb5034177
7
- data.tar.gz: b86dcfcaa1839b9f3a7d532d87c1574e712df8018bfb3f85f06e4d2ecc1bb174018458fd2ee5f853def55f2312da8ab8b3037ea3be0defff4c16f4bbbeb6cf5d
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.85.0', require: false
52
+ gem 'rubocop', '~> 0.85.1', require: false
57
53
  ```
58
54
 
59
55
  ## Quickstart
@@ -23,7 +23,7 @@ module RuboCop
23
23
  # # Do custom processing
24
24
  # end
25
25
  # end
26
- class Cop
26
+ class Cop # rubocop:disable Metrics/ClassLength
27
27
  extend RuboCop::AST::Sexp
28
28
  extend NodePattern::Macros
29
29
  include RuboCop::AST::Sexp
@@ -44,22 +44,12 @@ module RuboCop
44
44
  attr_reader :config, :offenses, :corrections
45
45
  attr_accessor :processed_source # TODO: Bad design.
46
46
 
47
- @registry = Registry.new
48
-
49
- class << self
50
- attr_reader :registry
51
- end
52
-
53
- def self.all
54
- registry.without_department(:Test).cops
55
- end
56
-
57
- def self.qualified_cop_name(name, origin)
58
- registry.qualified_cop_name(name, origin)
47
+ def self.inherited(subclass)
48
+ Registry.global.enlist(subclass)
59
49
  end
60
50
 
61
- def self.inherited(subclass)
62
- registry.enlist(subclass)
51
+ def self.exclude_from_registry
52
+ Registry.global.dismiss(self)
63
53
  end
64
54
 
65
55
  def self.badge
@@ -246,6 +236,23 @@ module RuboCop
246
236
  nil
247
237
  end
248
238
 
239
+ ### Deprecated registry access
240
+
241
+ # @deprecated Use Registry.global
242
+ def self.registry
243
+ Registry.global
244
+ end
245
+
246
+ # @deprecated Use Registry.all
247
+ def self.all
248
+ Registry.all
249
+ end
250
+
251
+ # @deprecated Use Registry.qualified_cop_name
252
+ def self.qualified_cop_name(name, origin)
253
+ Registry.qualified_cop_name(name, origin)
254
+ end
255
+
249
256
  private
250
257
 
251
258
  def find_message(node, message)
@@ -147,7 +147,7 @@ module RuboCop
147
147
  def indent_level(str)
148
148
  indentations = str.lines
149
149
  .map { |line| line[/^\s*/] }
150
- .reject { |line| line == "\n" }
150
+ .reject { |line| line.end_with?("\n") }
151
151
  indentations.empty? ? 0 : indentations.min_by(&:size).size
152
152
  end
153
153
 
@@ -7,6 +7,10 @@ module RuboCop
7
7
  # expected fields for format/sprintf/#% and what is actually
8
8
  # passed as arguments.
9
9
  #
10
+ # In addition it checks whether different formats are used in the same
11
+ # format string. Do not mix numbered, unnumbered, and named formats in
12
+ # the same format string.
13
+ #
10
14
  # @example
11
15
  #
12
16
  # # bad
@@ -18,16 +22,37 @@ module RuboCop
18
22
  # # good
19
23
  #
20
24
  # format('A value: %s and another: %i', a_value, another)
25
+ #
26
+ # @example
27
+ #
28
+ # # bad
29
+ #
30
+ # format('Unnumbered format: %s and numbered: %2$s', a_value, another)
31
+ #
32
+ # @example
33
+ #
34
+ # # good
35
+ #
36
+ # format('Numbered format: %1$s and numbered %2$s', a_value, another)
21
37
  class FormatParameterMismatch < Cop
22
38
  # http://rubular.com/r/CvpbxkcTzy
23
39
  MSG = "Number of arguments (%<arg_num>i) to `%<method>s` doesn't " \
24
40
  'match the number of fields (%<field_num>i).'
41
+ MSG_INVALID = 'Format string is invalid because formatting sequence types ' \
42
+ '(numbered, named or unnumbered) are mixed.'
25
43
 
26
44
  KERNEL = 'Kernel'
27
45
  SHOVEL = '<<'
28
46
  STRING_TYPES = %i[str dstr].freeze
29
47
 
30
48
  def on_send(node)
49
+ return unless format_string?(node)
50
+
51
+ if invalid_format_string?(node)
52
+ add_offense(node, location: :selector, message: MSG_INVALID)
53
+ return
54
+ end
55
+
31
56
  return unless offending_node?(node)
32
57
 
33
58
  add_offense(node, location: :selector)
@@ -35,9 +60,15 @@ module RuboCop
35
60
 
36
61
  private
37
62
 
63
+ def format_string?(node)
64
+ called_on_string?(node) && method_with_format_args?(node)
65
+ end
66
+
67
+ def invalid_format_string?(node)
68
+ !RuboCop::Cop::Utils::FormatString.new(node.source).valid?
69
+ end
70
+
38
71
  def offending_node?(node)
39
- return false unless called_on_string?(node)
40
- return false unless method_with_format_args?(node)
41
72
  return false if splat_args?(node)
42
73
 
43
74
  num_of_format_args, num_of_expected_fields = count_matches(node)
@@ -27,7 +27,14 @@ module RuboCop
27
27
  def on_regexp(node)
28
28
  return if contain_non_literal?(node)
29
29
 
30
- tree = Regexp::Parser.parse(node.content)
30
+ begin
31
+ tree = Regexp::Parser.parse(node.content)
32
+ # Returns if a regular expression that cannot be processed by regexp_parser gem.
33
+ # https://github.com/rubocop-hq/rubocop/issues/8083
34
+ rescue Regexp::Scanner::ScannerError
35
+ return
36
+ end
37
+
31
38
  return unless named_capture?(tree)
32
39
  return unless numbered_capture?(tree)
33
40
 
@@ -78,7 +78,7 @@ module RuboCop
78
78
 
79
79
  def comment_between_rescue_and_end?(node)
80
80
  end_line = nil
81
- node.each_ancestor(:kwbegin, :def) do |ancestor|
81
+ node.each_ancestor(:kwbegin, :def, :defs, :block) do |ancestor|
82
82
  end_line = ancestor.loc.end.line
83
83
  break
84
84
  end
@@ -22,34 +22,42 @@ module RuboCop
22
22
 
23
23
  # Registry that tracks all cops by their badge and department.
24
24
  class Registry
25
+ include Enumerable
26
+
27
+ attr_reader :options
28
+
25
29
  def initialize(cops = [], options = {})
26
30
  @registry = {}
27
31
  @departments = {}
28
32
  @cops_by_cop_name = Hash.new { |hash, key| hash[key] = [] }
29
33
 
30
- cops.each { |cop| enlist(cop) }
34
+ @enrollment_queue = cops
31
35
  @options = options
32
36
  end
33
37
 
34
38
  def enlist(cop)
35
- @registry[cop.badge] = cop
36
- @departments[cop.department] ||= []
37
- @departments[cop.department] << cop
38
- @cops_by_cop_name[cop.cop_name] << cop
39
+ @enrollment_queue << cop
40
+ end
41
+
42
+ def dismiss(cop)
43
+ raise "Cop #{cop} could not be dismissed" unless @enrollment_queue.delete(cop)
39
44
  end
40
45
 
41
46
  # @return [Array<Symbol>] list of departments for current cops.
42
47
  def departments
48
+ clear_enrollment_queue
43
49
  @departments.keys
44
50
  end
45
51
 
46
52
  # @return [Registry] Cops for that specific department.
47
53
  def with_department(department)
54
+ clear_enrollment_queue
48
55
  with(@departments.fetch(department, []))
49
56
  end
50
57
 
51
58
  # @return [Registry] Cops not for a specific department.
52
59
  def without_department(department)
60
+ clear_enrollment_queue
53
61
  without_department = @departments.dup
54
62
  without_department.delete(department)
55
63
 
@@ -119,6 +127,7 @@ module RuboCop
119
127
  end
120
128
 
121
129
  def unqualified_cop_names
130
+ clear_enrollment_queue
122
131
  @unqualified_cop_names ||=
123
132
  Set.new(@cops_by_cop_name.keys.map { |qn| File.basename(qn) }) <<
124
133
  'RedundantCopDisableDirective'
@@ -126,18 +135,21 @@ module RuboCop
126
135
 
127
136
  # @return [Hash{String => Array<Class>}]
128
137
  def to_h
138
+ clear_enrollment_queue
129
139
  @cops_by_cop_name
130
140
  end
131
141
 
132
142
  def cops
143
+ clear_enrollment_queue
133
144
  @registry.values
134
145
  end
135
146
 
136
147
  def length
148
+ clear_enrollment_queue
137
149
  @registry.size
138
150
  end
139
151
 
140
- def enabled(config, only, only_safe = false)
152
+ def enabled(config, only = [], only_safe = false)
141
153
  select do |cop|
142
154
  only.include?(cop.cop_name) || enabled?(cop, config, only_safe)
143
155
  end
@@ -172,6 +184,7 @@ module RuboCop
172
184
  end
173
185
 
174
186
  def sort!
187
+ clear_enrollment_queue
175
188
  @registry = Hash[@registry.sort_by { |badge, _| badge.cop_name }]
176
189
 
177
190
  self
@@ -188,16 +201,57 @@ module RuboCop
188
201
  # @param [String] cop_name
189
202
  # @return [Class, nil]
190
203
  def find_by_cop_name(cop_name)
191
- @cops_by_cop_name[cop_name].first
204
+ to_h[cop_name].first
205
+ end
206
+
207
+ @global = new
208
+
209
+ class << self
210
+ attr_reader :global
211
+ end
212
+
213
+ def self.all
214
+ global.without_department(:Test).cops
215
+ end
216
+
217
+ def self.qualified_cop_name(name, origin)
218
+ global.qualified_cop_name(name, origin)
219
+ end
220
+
221
+ # Changes momentarily the global registry
222
+ # Intended for testing purposes
223
+ def self.with_temporary_global(temp_global = global.dup)
224
+ previous = @global
225
+ @global = temp_global
226
+ yield
227
+ ensure
228
+ @global = previous
192
229
  end
193
230
 
194
231
  private
195
232
 
233
+ def initialize_copy(reg)
234
+ initialize(reg.cops, reg.options)
235
+ end
236
+
237
+ def clear_enrollment_queue
238
+ return if @enrollment_queue.empty?
239
+
240
+ @enrollment_queue.each do |cop|
241
+ @registry[cop.badge] = cop
242
+ @departments[cop.department] ||= []
243
+ @departments[cop.department] << cop
244
+ @cops_by_cop_name[cop.cop_name] << cop
245
+ end
246
+ @enrollment_queue = []
247
+ end
248
+
196
249
  def with(cops)
197
250
  self.class.new(cops)
198
251
  end
199
252
 
200
253
  def qualify_badge(badge)
254
+ clear_enrollment_queue
201
255
  @departments
202
256
  .map { |department, _| badge.with_department(department) }
203
257
  .select { |potential_badge| registered?(potential_badge) }
@@ -214,6 +268,7 @@ module RuboCop
214
268
  end
215
269
 
216
270
  def registered?(badge)
271
+ clear_enrollment_queue
217
272
  @registry.key?(badge)
218
273
  end
219
274
  end
@@ -27,7 +27,8 @@ module RuboCop
27
27
  class RedundantConditional < Cop
28
28
  include Alignment
29
29
 
30
- COMPARISON_OPERATORS = RuboCop::AST::Node::COMPARISON_OPERATORS
30
+ operators = RuboCop::AST::Node::COMPARISON_OPERATORS.to_a
31
+ COMPARISON_OPERATOR_MATCHER = "{:#{operators.join(' :')}}"
31
32
 
32
33
  MSG = 'This conditional expression can just be replaced ' \
33
34
  'by `%<msg>s`.'
@@ -54,11 +55,11 @@ module RuboCop
54
55
  end
55
56
 
56
57
  def_node_matcher :redundant_condition?, <<~RUBY
57
- (if (send _ {:#{COMPARISON_OPERATORS.join(' :')}} _) true false)
58
+ (if (send _ #{COMPARISON_OPERATOR_MATCHER} _) true false)
58
59
  RUBY
59
60
 
60
61
  def_node_matcher :redundant_condition_inverted?, <<~RUBY
61
- (if (send _ {:#{COMPARISON_OPERATORS.join(' :')}} _) false true)
62
+ (if (send _ #{COMPARISON_OPERATOR_MATCHER} _) false true)
62
63
  RUBY
63
64
 
64
65
  def offense?(node)
@@ -31,6 +31,14 @@ module RuboCop
31
31
  validate_config
32
32
  end
33
33
 
34
+ # @return [Team]
35
+ def self.new(cop_or_classes, config, options = {})
36
+ # Support v0 api:
37
+ return mobilize(cop_or_classes, config, options) if cop_or_classes.first.is_a?(Class)
38
+
39
+ super
40
+ end
41
+
34
42
  # @return [Team] with cops assembled from the given `cop_classes`
35
43
  def self.mobilize(cop_classes, config, options = nil)
36
44
  options ||= DEFAULT_OPTIONS
@@ -97,6 +97,10 @@ module RuboCop
97
97
  @format_sequences ||= parse
98
98
  end
99
99
 
100
+ def valid?
101
+ !mixed_formats?
102
+ end
103
+
100
104
  def named_interpolation?
101
105
  format_sequences.any?(&:name)
102
106
  end
@@ -114,6 +118,20 @@ module RuboCop
114
118
  )
115
119
  end
116
120
  end
121
+
122
+ def mixed_formats?
123
+ formats = format_sequences.map do |seq|
124
+ if seq.name
125
+ :named
126
+ elsif seq.max_digit_dollar_num
127
+ :numbered
128
+ else
129
+ :unnumbered
130
+ end
131
+ end
132
+
133
+ formats.uniq.size > 1
134
+ end
117
135
  end
118
136
  end
119
137
  end
@@ -115,7 +115,7 @@ module RuboCop
115
115
  expect(actual_annotations.to_s).to eq(expected_annotations.to_s)
116
116
  end
117
117
 
118
- def expect_correction(correction, loop: false)
118
+ def expect_correction(correction, loop: true)
119
119
  raise '`expect_correction` must follow `expect_offense`' unless @processed_source
120
120
 
121
121
  iteration = 0
@@ -128,6 +128,7 @@ module RuboCop
128
128
 
129
129
  break corrected_source unless loop
130
130
  break corrected_source if cop.corrections.empty?
131
+ break corrected_source if corrected_source == @processed_source.buffer.source
131
132
 
132
133
  if iteration > RuboCop::Runner::MAX_ITERATIONS
133
134
  raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [])
@@ -135,6 +136,8 @@ module RuboCop
135
136
 
136
137
  # Prepare for next loop
137
138
  cop.instance_variable_set(:@corrections, [])
139
+ # Cache invalidation. This is bad!
140
+ cop.instance_variable_set(:@token_table, nil)
138
141
  @processed_source = parse_source(corrected_source,
139
142
  @processed_source.path)
140
143
  _investigate(cop, @processed_source)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.85.0'
6
+ STRING = '0.85.1'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.85.0
4
+ version: 0.85.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-06-01 00:00:00.000000000 Z
13
+ date: 2020-06-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -157,8 +157,8 @@ dependencies:
157
157
  - !ruby/object:Gem::Version
158
158
  version: '3.0'
159
159
  description: |2
160
- Automatic Ruby code style checking tool.
161
- Aims to enforce the community-driven Ruby Style Guide.
160
+ RuboCop is a Ruby code style checking and code formatting tool.
161
+ It aims to enforce the community-driven Ruby Style Guide.
162
162
  email: rubocop@googlegroups.com
163
163
  executables:
164
164
  - rubocop