rubocop 1.9.1 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86b427813730f667d5978bd4b4ca7e8f6766adf4ddf713e413cf07a0345b84b2
4
- data.tar.gz: ede1028f4ebe7b6b1cd59de4d604e655c7115d928d38393ebd7febdbbff5b3e7
3
+ metadata.gz: d690ba94b53010f458962d3c50bae5ec6198e0b54565422b1bce58351429618a
4
+ data.tar.gz: 4b0a3f5d69b88b1db292620328a02c26f8315b37fc49b066e4aa24c317c22f86
5
5
  SHA512:
6
- metadata.gz: b5e3ca723e7530916204e9bfce59bec1452232765a0903093ba2b4783fc35f109e655251c2fce8e3b08dbebcf4a4e67a4301b00c8113d45f5f0bb2a63cc4be7f
7
- data.tar.gz: d91068c77da3ea787a5c36c287f1913bc94c23d98fc315604883cb21742f4c1031014e10c9470c67dca2fa3dfdc41eb848134f0a9565ff5a82e65aed5d6d2cf3
6
+ metadata.gz: 3655b57caafb4704d05658ef53f39e09f30e0f32d2def6908cfc6ecefcf7a0b67aeeafe862bc4ad76f96fb2c6b17b00a60997ad4af31fc0727e16c20ce1141da
7
+ data.tar.gz: 69f5289513c39feb34bf4df834e45b3288b76eda570d860ab0aab3a4742283cbaa5f9bebae9663fc6e7f3d00ae18bd8638bdc4d40b4c13516966fb349496aec4
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.9', require: false
54
+ gem 'rubocop', '~> 1.10', 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
@@ -203,6 +203,13 @@ Bundler/OrderedGems:
203
203
 
204
204
  #################### Gemspec ###############################
205
205
 
206
+ Gemspec/DateAssignment:
207
+ Description: 'Checks that `date =` is not used in gemspec file, it is set automatically when the gem is packaged.'
208
+ Enabled: pending
209
+ VersionAdded: '1.10'
210
+ Include:
211
+ - '**/*.gemspec'
212
+
206
213
  Gemspec/DuplicatedAssignment:
207
214
  Description: 'An attribute assignment method calls should be listed only once in a gemspec.'
208
215
  Enabled: true
@@ -1446,23 +1453,31 @@ Lint/Debugger:
1446
1453
  Description: 'Check for debugger calls.'
1447
1454
  Enabled: true
1448
1455
  VersionAdded: '0.14'
1449
- VersionChanged: '0.49'
1450
- DebuggerReceivers:
1451
- - binding
1452
- - Kernel
1453
- - Pry
1456
+ VersionChanged: '1.10'
1457
+ DebuggerReceivers: [] # deprecated
1454
1458
  DebuggerMethods:
1455
- - debugger
1456
- - byebug
1457
- - remote_byebug
1458
- - pry
1459
- - remote_pry
1460
- - pry_remote
1461
- - console
1462
- - rescue
1463
- - save_and_open_page
1464
- - save_and_open_screenshot
1465
- - irb
1459
+ # Groups are available so that a specific group can be disabled in
1460
+ # a user's configuration, but are otherwise not significant.
1461
+ Kernel:
1462
+ - binding.irb
1463
+ Byebug:
1464
+ - byebug
1465
+ - remote_byebug
1466
+ - Kernel.byebug
1467
+ - Kernel.remote_byebug
1468
+ Capybara:
1469
+ - save_and_open_page
1470
+ - save_and_open_screenshot
1471
+ Pry:
1472
+ - binding.pry
1473
+ - binding.remote_pry
1474
+ - binding.pry_remote
1475
+ - Pry.rescue
1476
+ Rails:
1477
+ - debugger
1478
+ - Kernel.debugger
1479
+ WebConsole:
1480
+ - binding.console
1466
1481
 
1467
1482
  Lint/DeprecatedClassMethods:
1468
1483
  Description: 'Check for deprecated class method calls.'
@@ -3087,6 +3102,8 @@ Style/ConstantVisibility:
3087
3102
  visibility declarations.
3088
3103
  Enabled: false
3089
3104
  VersionAdded: '0.66'
3105
+ VersionChanged: '1.10'
3106
+ IgnoreModules: false
3090
3107
 
3091
3108
  # Checks that you have put a copyright in a comment before any code.
3092
3109
  #
@@ -3425,6 +3442,11 @@ Style/HashAsLastArrayItem:
3425
3442
  - braces
3426
3443
  - no_braces
3427
3444
 
3445
+ Style/HashConversion:
3446
+ Description: 'Avoid Hash[] in favor of ary.to_h or literal hashes.'
3447
+ Enabled: pending
3448
+ VersionAdded: '1.10'
3449
+
3428
3450
  Style/HashEachMethods:
3429
3451
  Description: 'Use Hash#each_key and Hash#each_value.'
3430
3452
  StyleGuide: '#hash-each'
@@ -187,6 +187,10 @@ changed_parameters:
187
187
  parameters: ExcludedMethods
188
188
  alternative: IgnoredMethods
189
189
  severity: warning
190
+ - cops: Lint/Debugger
191
+ parameters: DebuggerReceivers
192
+ reason: "`DebuggerReceivers` is no longer necessary, method receivers should be specified in `DebuggerMethods` instead."
193
+ severity: warning
190
194
 
191
195
  # Enforced styles that have been removed or replaced
192
196
  changed_enforced_styles:
data/lib/rubocop.rb CHANGED
@@ -152,6 +152,7 @@ require_relative 'rubocop/cop/bundler/gem_comment'
152
152
  require_relative 'rubocop/cop/bundler/insecure_protocol_source'
153
153
  require_relative 'rubocop/cop/bundler/ordered_gems'
154
154
 
155
+ require_relative 'rubocop/cop/gemspec/date_assignment'
155
156
  require_relative 'rubocop/cop/gemspec/duplicated_assignment'
156
157
  require_relative 'rubocop/cop/gemspec/ordered_dependencies'
157
158
  require_relative 'rubocop/cop/gemspec/required_ruby_version'
@@ -472,6 +473,7 @@ require_relative 'rubocop/cop/style/global_std_stream'
472
473
  require_relative 'rubocop/cop/style/global_vars'
473
474
  require_relative 'rubocop/cop/style/guard_clause'
474
475
  require_relative 'rubocop/cop/style/hash_as_last_array_item'
476
+ require_relative 'rubocop/cop/style/hash_conversion'
475
477
  require_relative 'rubocop/cop/style/hash_each_methods'
476
478
  require_relative 'rubocop/cop/style/hash_except'
477
479
  require_relative 'rubocop/cop/style/hash_like_case'
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # This cop checks that `date =` is not used in gemspec file.
7
+ # It is set automatically when the gem is packaged.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Gem::Specification.new do |spec|
13
+ # s.name = 'your_cool_gem_name'
14
+ # spec.date = Time.now.strftime('%Y-%m-%d')
15
+ # end
16
+ #
17
+ # # good
18
+ # Gem::Specification.new do |spec|
19
+ # s.name = 'your_cool_gem_name'
20
+ # end
21
+ #
22
+ class DateAssignment < Base
23
+ include RangeHelp
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Do not use `date =` in gemspec, it is set automatically when the gem is packaged.'
27
+
28
+ def_node_matcher :gem_specification, <<~PATTERN
29
+ (block
30
+ (send
31
+ (const
32
+ (const {cbase nil?} :Gem) :Specification) :new)
33
+ ...)
34
+ PATTERN
35
+
36
+ def on_block(block_node)
37
+ return unless gem_specification(block_node)
38
+
39
+ block_parameter = block_node.arguments.first.source
40
+
41
+ date_assignment = block_node.descendants.detect do |node|
42
+ node.send_type? && node.receiver&.source == block_parameter && node.method?(:date=)
43
+ end
44
+
45
+ return unless date_assignment
46
+
47
+ add_offense(date_assignment) do |corrector|
48
+ range = range_by_whole_lines(date_assignment.source_range, include_final_newline: true)
49
+
50
+ corrector.remove(range)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -152,7 +152,7 @@ module RuboCop
152
152
  MSG = 'Indent the first argument one step more than %<base>s.'
153
153
 
154
154
  def on_send(node)
155
- return if enforce_first_argument_with_fixed_indentation?
155
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation?
156
156
  return if !node.arguments? || node.operator_method?
157
157
 
158
158
  indent = base_indentation(node) + configured_indentation_width
@@ -31,6 +31,32 @@ module RuboCop
31
31
  # foo = if expression
32
32
  # 'bar'
33
33
  # end
34
+ #
35
+ # @example SupportedTypes: ['block', 'case', 'class', 'if', 'kwbegin', 'module'] (default)
36
+ # # good
37
+ # foo =
38
+ # if expression
39
+ # 'bar'
40
+ # end
41
+ #
42
+ # # good
43
+ # foo =
44
+ # [1].map do |i|
45
+ # i + 1
46
+ # end
47
+ #
48
+ # @example SupportedTypes: ['block']
49
+ # # good
50
+ # foo = if expression
51
+ # 'bar'
52
+ # end
53
+ #
54
+ # # good
55
+ # foo =
56
+ # [1].map do |i|
57
+ # 'bar' * i
58
+ # end
59
+ #
34
60
  class MultilineAssignmentLayout < Base
35
61
  include CheckAssignment
36
62
  include ConfigurableEnforcedStyle
@@ -47,7 +47,7 @@ module RuboCop
47
47
  end_pos = node.receiver.source_range.end_pos
48
48
 
49
49
  return if begin_pos - end_pos == 1 ||
50
- (range = range_between(end_pos, begin_pos - 1)).source == '['
50
+ (range = range_between(end_pos, begin_pos - 1)).source.start_with?('[')
51
51
 
52
52
  range
53
53
  end
@@ -3,8 +3,21 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks for calls to debugger or pry.
7
- # The cop can be configured to define which methods and receivers must be fixed.
6
+ # This cop checks for debug calls (such as `debugger` or `binding.pry`) that should
7
+ # not be kept for production code.
8
+ #
9
+ # The cop can be configured using `DebuggerMethods`. By default, a number of gems
10
+ # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `Pry`, `Rails`,
11
+ # and `WebConsole`). Additional methods can be added.
12
+ #
13
+ # Specific default groups can be disabled if necessary:
14
+ #
15
+ # [source,yaml]
16
+ # ----
17
+ # Lint/Debugger:
18
+ # WebConsole: ~
19
+ # ---
20
+ #
8
21
  #
9
22
  # @example
10
23
  #
@@ -33,14 +46,32 @@ module RuboCop
33
46
  # def some_method
34
47
  # do_something
35
48
  # end
49
+ #
50
+ # @example DebuggerMethods: [my_debugger]
51
+ #
52
+ # # bad (ok during development)
53
+ #
54
+ # def some_method
55
+ # my_debugger
56
+ # end
36
57
  class Debugger < Base
37
58
  MSG = 'Remove debugger entry point `%<source>s`.'
38
59
 
39
60
  RESTRICT_ON_SEND = [].freeze
40
61
 
62
+ def_node_matcher :kernel?, <<~PATTERN
63
+ (const {nil? cbase} :Kernel)
64
+ PATTERN
65
+
66
+ def_node_matcher :valid_receiver?, <<~PATTERN
67
+ {
68
+ (const {nil? cbase} %1)
69
+ (send {nil? #kernel?} %1)
70
+ }
71
+ PATTERN
72
+
41
73
  def on_send(node)
42
- return unless debugger_method?(node.method_name)
43
- return if !node.receiver.nil? && !debugger_receiver?(node)
74
+ return unless debugger_method?(node)
44
75
 
45
76
  add_offense(node)
46
77
  end
@@ -51,19 +82,32 @@ module RuboCop
51
82
  format(MSG, source: node.source)
52
83
  end
53
84
 
54
- def debugger_method?(name)
55
- cop_config.fetch('DebuggerMethods', []).include?(name.to_s)
85
+ def debugger_methods
86
+ @debugger_methods ||= begin
87
+ config = cop_config.fetch('DebuggerMethods', [])
88
+ values = config.is_a?(Array) ? config : config.values.flatten
89
+ values.map do |v|
90
+ next unless v
91
+
92
+ *receiver, method_name = v.split('.')
93
+ {
94
+ receiver: receiver.empty? ? nil : receiver.join.to_sym,
95
+ method_name: method_name.to_sym
96
+ }
97
+ end.compact
98
+ end
56
99
  end
57
100
 
58
- def debugger_receiver?(node)
59
- receiver = case node.receiver
60
- when RuboCop::AST::SendNode
61
- node.receiver.method_name
62
- when RuboCop::AST::ConstNode
63
- node.receiver.const_name
64
- end
101
+ def debugger_method?(send_node)
102
+ debugger_methods.any? do |method|
103
+ next unless method[:method_name] == send_node.method_name
65
104
 
66
- cop_config.fetch('DebuggerReceivers', []).include?(receiver.to_s)
105
+ if method[:receiver].nil?
106
+ send_node.receiver.nil?
107
+ else
108
+ valid_receiver?(send_node.receiver, method[:receiver])
109
+ end
110
+ end
67
111
  end
68
112
  end
69
113
  end
@@ -44,6 +44,8 @@ module RuboCop
44
44
  MSG = 'Use `%<constant>s.%<method>s(%<replacement_args>s)`' \
45
45
  ' instead of `%<original>s`.'
46
46
 
47
+ NO_ARG_ALGORITHM = %w[BF DES IDEA RC4].freeze
48
+
47
49
  def_node_matcher :algorithm_const, <<~PATTERN
48
50
  (send
49
51
  $(const
@@ -104,7 +106,7 @@ module RuboCop
104
106
  def algorithm_name(node)
105
107
  name = node.loc.name.source
106
108
 
107
- if openssl_class(node) == 'OpenSSL::Cipher'
109
+ if openssl_class(node) == 'OpenSSL::Cipher' && !NO_ARG_ALGORITHM.include?(name)
108
110
  name.scan(/.{3}/).join('-')
109
111
  else
110
112
  name
@@ -124,16 +126,23 @@ module RuboCop
124
126
  algorithm_name = algorithm_name(algorithm_constant)
125
127
 
126
128
  if openssl_class(algorithm_constant) == 'OpenSSL::Cipher'
127
- build_cipher_arguments(node, algorithm_name)
129
+ build_cipher_arguments(node, algorithm_name, node.arguments.empty?)
128
130
  else
129
131
  (["'#{algorithm_name}'"] + node.arguments.map(&:source)).join(', ')
130
132
  end
131
133
  end
132
134
 
133
- def build_cipher_arguments(node, algorithm_name)
135
+ def build_cipher_arguments(node, algorithm_name, no_arguments)
134
136
  algorithm_parts = algorithm_name.downcase.split('-')
135
137
  size_and_mode = sanitize_arguments(node.arguments).map(&:downcase)
136
- "'#{(algorithm_parts + size_and_mode + ['cbc']).take(3).join('-')}'"
138
+
139
+ if NO_ARG_ALGORITHM.include?(algorithm_parts.first.upcase) && no_arguments
140
+ "'#{algorithm_parts.first}'"
141
+ else
142
+ mode = 'cbc' unless size_and_mode == ['cbc']
143
+
144
+ "'#{(algorithm_parts + size_and_mode + [mode]).compact.take(3).join('-')}'"
145
+ end
137
146
  end
138
147
  end
139
148
  end
@@ -21,11 +21,11 @@ module RuboCop
21
21
  #
22
22
  class DuplicateRequire < Base
23
23
  MSG = 'Duplicate `%<method>s` detected.'
24
- REQUIRE_METHODS = %i[require require_relative].freeze
24
+ REQUIRE_METHODS = Set.new(%i[require require_relative]).freeze
25
25
  RESTRICT_ON_SEND = REQUIRE_METHODS
26
26
 
27
27
  def_node_matcher :require_call?, <<~PATTERN
28
- (send {nil? (const _ :Kernel)} {:#{REQUIRE_METHODS.join(' :')}} _)
28
+ (send {nil? (const _ :Kernel)} %REQUIRE_METHODS _)
29
29
  PATTERN
30
30
 
31
31
  def on_new_investigation
@@ -47,7 +47,7 @@ module RuboCop
47
47
  MSG = 'Odd `else` layout detected. Did you mean to use `elsif`?'
48
48
 
49
49
  def on_if(node)
50
- return if node.ternary? || node.elsif?
50
+ return if node.ternary?
51
51
 
52
52
  check(node)
53
53
  end
@@ -11,14 +11,10 @@ module RuboCop
11
11
  # @example
12
12
  #
13
13
  # # bad
14
- #
15
14
  # x < y < z
16
15
  # 10 <= x <= 20
17
16
  #
18
- # @example
19
- #
20
17
  # # good
21
- #
22
18
  # x < y && y < z
23
19
  # 10 <= x && x <= 20
24
20
  class MultipleComparison < Base
@@ -26,6 +22,7 @@ module RuboCop
26
22
 
27
23
  MSG = 'Use the `&&` operator to compare multiple values.'
28
24
  COMPARISON_METHODS = %i[< > <= >=].freeze
25
+ SET_OPERATION_OPERATORS = %i[& | ^].freeze
29
26
  RESTRICT_ON_SEND = COMPARISON_METHODS
30
27
 
31
28
  def_node_matcher :multiple_compare?, <<~PATTERN
@@ -34,6 +31,9 @@ module RuboCop
34
31
 
35
32
  def on_send(node)
36
33
  return unless (center = multiple_compare?(node))
34
+ # It allows multiple comparison using `&`, `|`, and `^` set operation operators.
35
+ # e.g. `x >= y & y < z`
36
+ return if center.send_type? && SET_OPERATION_OPERATORS.include?(center.method_name)
37
37
 
38
38
  add_offense(node) do |corrector|
39
39
  new_center = "#{center.source} && #{center.source}"
@@ -140,13 +140,15 @@ module RuboCop
140
140
  def replacement_range_and_content(node)
141
141
  variable, = *node
142
142
  loc = node.loc
143
+ expression = loc.expression
143
144
 
144
145
  if array_new?(variable)
145
- [node.parent.loc.expression, variable.source]
146
+ expression = node.parent.loc.expression if node.parent.array_type?
147
+ [expression, variable.source]
146
148
  elsif !variable.array_type?
147
- [loc.expression, "[#{variable.source}]"]
149
+ [expression, "[#{variable.source}]"]
148
150
  elsif redundant_brackets?(node)
149
- [loc.expression, remove_brackets(variable)]
151
+ [expression, remove_brackets(variable)]
150
152
  else
151
153
  [loc.operator, '']
152
154
  end
@@ -35,10 +35,10 @@ module RuboCop
35
35
  ensure_valid_preferred_delimiters
36
36
 
37
37
  if preferred_delimiters_config.key?('default')
38
- Hash[PERCENT_LITERAL_TYPES.map do |type|
38
+ PERCENT_LITERAL_TYPES.map do |type|
39
39
  [type, preferred_delimiters_config[type] ||
40
40
  preferred_delimiters_config['default']]
41
- end]
41
+ end.to_h
42
42
  else
43
43
  preferred_delimiters_config
44
44
  end
@@ -185,7 +185,7 @@ module RuboCop
185
185
 
186
186
  def sort!
187
187
  clear_enrollment_queue
188
- @registry = Hash[@registry.sort_by { |badge, _| badge.cop_name }]
188
+ @registry = @registry.sort_by { |badge, _| badge.cop_name }.to_h
189
189
 
190
190
  self
191
191
  end
@@ -26,6 +26,24 @@ module RuboCop
26
26
  # public_constant :BAZ
27
27
  # end
28
28
  #
29
+ # @example IgnoreModules: false (default)
30
+ # # bad
31
+ # class Foo
32
+ # MyClass = Struct.new()
33
+ # end
34
+ #
35
+ # # good
36
+ # class Foo
37
+ # MyClass = Struct.new()
38
+ # public_constant :MyClass
39
+ # end
40
+ #
41
+ # @example IgnoreModules: true
42
+ # # good
43
+ # class Foo
44
+ # MyClass = Struct.new()
45
+ # end
46
+ #
29
47
  class ConstantVisibility < Base
30
48
  MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
31
49
  'either `#public_constant` or `#private_constant`.'
@@ -33,6 +51,7 @@ module RuboCop
33
51
  def on_casgn(node)
34
52
  return unless class_or_module_scope?(node)
35
53
  return if visibility_declaration?(node)
54
+ return if ignore_modules? && module?(node)
36
55
 
37
56
  message = message(node)
38
57
  add_offense(node, message: message)
@@ -40,6 +59,14 @@ module RuboCop
40
59
 
41
60
  private
42
61
 
62
+ def ignore_modules?
63
+ cop_config.fetch('IgnoreModules', false)
64
+ end
65
+
66
+ def module?(node)
67
+ node.children.last.class_constructor?
68
+ end
69
+
43
70
  def message(node)
44
71
  _namespace, constant_name, _value = *node
45
72
 
@@ -5,8 +5,8 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for uses of double negation (`!!`) to convert something to a boolean value.
7
7
  #
8
- # When using `EnforcedStyle: allowed_in_returns`, allow double nagation in contexts
9
- # that use boolean as a return value. When using `EnforcedStyle: forbidden`, double nagation
8
+ # When using `EnforcedStyle: allowed_in_returns`, allow double negation in contexts
9
+ # that use boolean as a return value. When using `EnforcedStyle: forbidden`, double negation
10
10
  # should be forbidden always.
11
11
  #
12
12
  # @example
@@ -12,6 +12,11 @@ module RuboCop
12
12
  # The cop also checks that the line number given relative to `__LINE__` is
13
13
  # correct.
14
14
  #
15
+ # This cop will autocorrect incorrect or missing filename and line number
16
+ # values. However, if `eval` is called without a binding argument, the cop
17
+ # will not attempt to automatically add a binding, or add filename and
18
+ # line values.
19
+ #
15
20
  # @example
16
21
  # # bad
17
22
  # eval <<-RUBY
@@ -36,7 +41,21 @@ module RuboCop
36
41
  # def do_something
37
42
  # end
38
43
  # RUBY
44
+ #
45
+ # This cop works only when a string literal is given as a code string.
46
+ # No offence is reported if a string variable is given as below:
47
+ #
48
+ # @example
49
+ # # not checked
50
+ # code = <<-RUBY
51
+ # def do_something
52
+ # end
53
+ # RUBY
54
+ # eval code
55
+ #
39
56
  class EvalWithLocation < Base
57
+ extend AutoCorrector
58
+
40
59
  MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
41
60
  MSG_EVAL = 'Pass a binding, `__FILE__` and `__LINE__` to `eval`.'
42
61
  MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
@@ -66,21 +85,28 @@ module RuboCop
66
85
  code = node.arguments.first
67
86
  return unless code && (code.str_type? || code.dstr_type?)
68
87
 
88
+ check_location(node, code)
89
+ end
90
+
91
+ private
92
+
93
+ def check_location(node, code)
69
94
  file, line = file_and_line(node)
70
95
 
71
96
  if line
72
97
  check_file(node, file)
73
98
  check_line(node, code)
99
+ elsif file
100
+ check_file(node, file)
101
+ add_offense_for_missing_line(node, code)
74
102
  else
75
- register_offense(node)
103
+ add_offense_for_missing_location(node, code)
76
104
  end
77
105
  end
78
106
 
79
- private
80
-
81
- def register_offense(node)
107
+ def register_offense(node, &block)
82
108
  msg = node.method?(:eval) ? MSG_EVAL : format(MSG, method_name: node.method_name)
83
- add_offense(node, message: msg)
109
+ add_offense(node, message: msg, &block)
84
110
  end
85
111
 
86
112
  def special_file_keyword?(node)
@@ -98,6 +124,10 @@ module RuboCop
98
124
  [node.arguments[base], node.arguments[base + 1]]
99
125
  end
100
126
 
127
+ def with_binding?(node)
128
+ node.method?(:eval) ? node.arguments.size >= 2 : true
129
+ end
130
+
101
131
  # FIXME: It's a Style/ConditionalAssignment's false positive.
102
132
  # rubocop:disable Style/ConditionalAssignment
103
133
  def with_lineno?(node)
@@ -109,18 +139,16 @@ module RuboCop
109
139
  end
110
140
  # rubocop:enable Style/ConditionalAssignment
111
141
 
112
- def message_incorrect_line(method_name, actual, sign, line_diff)
113
- expected =
114
- if line_diff.zero?
115
- '__LINE__'
116
- else
117
- "__LINE__ #{sign} #{line_diff}"
118
- end
142
+ def add_offense_for_incorrect_line(method_name, line_node, sign, line_diff)
143
+ expected = expected_line(sign, line_diff)
144
+ message = format(MSG_INCORRECT_LINE,
145
+ method_name: method_name,
146
+ actual: line_node.source,
147
+ expected: expected)
119
148
 
120
- format(MSG_INCORRECT_LINE,
121
- method_name: method_name,
122
- actual: actual.source,
123
- expected: expected)
149
+ add_offense(line_node.loc.expression, message: message) do |corrector|
150
+ corrector.replace(line_node, expected)
151
+ end
124
152
  end
125
153
 
126
154
  def check_file(node, file_node)
@@ -131,13 +159,14 @@ module RuboCop
131
159
  expected: '__FILE__',
132
160
  actual: file_node.source)
133
161
 
134
- add_offense(file_node, message: message)
162
+ add_offense(file_node, message: message) do |corrector|
163
+ corrector.replace(file_node, '__FILE__')
164
+ end
135
165
  end
136
166
 
137
167
  def check_line(node, code)
138
168
  line_node = node.arguments.last
139
- lineno_range = line_node.loc.expression
140
- line_diff = string_first_line(code) - lineno_range.first_line
169
+ line_diff = line_difference(line_node, code)
141
170
  if line_diff.zero?
142
171
  add_offense_for_same_line(node, line_node)
143
172
  else
@@ -145,6 +174,10 @@ module RuboCop
145
174
  end
146
175
  end
147
176
 
177
+ def line_difference(line_node, code)
178
+ string_first_line(code) - line_node.loc.expression.first_line
179
+ end
180
+
148
181
  def string_first_line(str_node)
149
182
  if str_node.heredoc?
150
183
  str_node.loc.heredoc_body.first_line
@@ -156,20 +189,47 @@ module RuboCop
156
189
  def add_offense_for_same_line(node, line_node)
157
190
  return if special_line_keyword?(line_node)
158
191
 
159
- add_offense(
160
- line_node.loc.expression,
161
- message: message_incorrect_line(node.method_name, line_node, nil, 0)
162
- )
192
+ add_offense_for_incorrect_line(node.method_name, line_node, nil, 0)
163
193
  end
164
194
 
165
195
  def add_offense_for_different_line(node, line_node, line_diff)
166
196
  sign = line_diff.positive? ? :+ : :-
167
197
  return if line_with_offset?(line_node, sign, line_diff.abs)
168
198
 
169
- add_offense(
170
- line_node.loc.expression,
171
- message: message_incorrect_line(node.method_name, line_node, sign, line_diff.abs)
172
- )
199
+ add_offense_for_incorrect_line(node.method_name, line_node, sign, line_diff.abs)
200
+ end
201
+
202
+ def expected_line(sign, line_diff)
203
+ if line_diff.zero?
204
+ '__LINE__'
205
+ else
206
+ "__LINE__ #{sign} #{line_diff.abs}"
207
+ end
208
+ end
209
+
210
+ def add_offense_for_missing_line(node, code)
211
+ register_offense(node) do |corrector|
212
+ line_str = missing_line(node, code)
213
+ corrector.insert_after(node.loc.expression.end, ", #{line_str}")
214
+ end
215
+ end
216
+
217
+ def add_offense_for_missing_location(node, code)
218
+ if node.method?(:eval) && !with_binding?(node)
219
+ register_offense(node)
220
+ return
221
+ end
222
+
223
+ register_offense(node) do |corrector|
224
+ line_str = missing_line(node, code)
225
+ corrector.insert_after(node.loc.expression.end, ", __FILE__, #{line_str}")
226
+ end
227
+ end
228
+
229
+ def missing_line(node, code)
230
+ line_diff = line_difference(node.arguments.last, code)
231
+ sign = line_diff.positive? ? :+ : :-
232
+ expected_line(sign, line_diff)
173
233
  end
174
234
  end
175
235
  end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  replacement = ' &block'
98
98
  replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
99
99
  corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
100
- elsif node.call_type?
100
+ elsif node.call_type? || node.zsuper_type?
101
101
  corrector.insert_after(node, '(&block)')
102
102
  else
103
103
  corrector.insert_after(node.loc.name, '(&block)')
@@ -5,13 +5,12 @@ module RuboCop
5
5
  module Style
6
6
  # This cop enforces consistency when using exponential notation
7
7
  # for numbers in the code (eg 1.2e4). Different styles are supported:
8
- # * `scientific` which enforces a mantissa between 1 (inclusive)
9
- # and 10 (exclusive).
10
- # * `engineering` which enforces the exponent to be a multiple of 3
11
- # and the mantissa to be between 0.1 (inclusive)
12
- # and 10 (exclusive).
13
- # * `integral` which enforces the mantissa to always be a whole number
14
- # without trailing zeroes.
8
+ #
9
+ # * `scientific` which enforces a mantissa between 1 (inclusive) and 10 (exclusive).
10
+ # * `engineering` which enforces the exponent to be a multiple of 3 and the mantissa
11
+ # to be between 0.1 (inclusive) and 10 (exclusive).
12
+ # * `integral` which enforces the mantissa to always be a whole number without
13
+ # trailing zeroes.
15
14
  #
16
15
  # @example EnforcedStyle: scientific (default)
17
16
  # # Enforces a mantissa between 1 (inclusive) and 10 (exclusive).
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks the usage of pre-2.1 `Hash[args]` method of converting enumerables and
7
+ # sequences of values to hashes.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Hash[ary]
12
+ #
13
+ # # good
14
+ # ary.to_h
15
+ #
16
+ # # bad
17
+ # Hash[key1, value1, key2, value2]
18
+ #
19
+ # # good
20
+ # {key1 => value1, key2 => value2}
21
+ class HashConversion < Base
22
+ extend AutoCorrector
23
+
24
+ MSG_TO_H = 'Prefer ary.to_h to Hash[ary].'
25
+ MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...].'
26
+ MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...].'
27
+ MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array].'
28
+ RESTRICT_ON_SEND = %i[[]].freeze
29
+
30
+ def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
31
+
32
+ def on_send(node)
33
+ return unless hash_from_array?(node)
34
+
35
+ # There are several cases:
36
+ # If there is one argument:
37
+ # Hash[ary] => ary.to_h
38
+ # Hash[*ary] => don't suggest corrections
39
+ # If there is 0 or 2+ arguments:
40
+ # Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
41
+ # ...but don't suggest correction if there is odd number of them (it is a bug)
42
+ node.arguments.count == 1 ? single_argument(node) : multi_argument(node)
43
+ end
44
+
45
+ private
46
+
47
+ def single_argument(node)
48
+ first_argument = node.first_argument
49
+ if first_argument.hash_type?
50
+ add_offense(node, message: MSG_LITERAL_HASH_ARG) do |corrector|
51
+ corrector.replace(node, "{#{first_argument.source}}")
52
+ end
53
+ elsif first_argument.splat_type?
54
+ add_offense(node, message: MSG_SPLAT)
55
+ else
56
+ add_offense(node, message: MSG_TO_H) do |corrector|
57
+ corrector.replace(node, "#{first_argument.source}.to_h")
58
+ end
59
+ end
60
+ end
61
+
62
+ def multi_argument(node)
63
+ if node.arguments.count.odd?
64
+ add_offense(node, message: MSG_LITERAL_MULTI_ARG)
65
+ else
66
+ add_offense(node, message: MSG_LITERAL_MULTI_ARG) do |corrector|
67
+ corrector.replace(node, args_to_hash(node.arguments))
68
+ end
69
+ end
70
+ end
71
+
72
+ def args_to_hash(args)
73
+ content = args.each_slice(2)
74
+ .map { |arg1, arg2| "#{arg1.source} => #{arg2.source}" }
75
+ .join(', ')
76
+ "{#{content}}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -81,13 +81,13 @@ module RuboCop
81
81
  }
82
82
 
83
83
  PERL_VARS =
84
- Hash[ENGLISH_VARS.flat_map { |k, vs| vs.map { |v| [v, [k]] } }]
84
+ ENGLISH_VARS.flat_map { |k, vs| vs.map { |v| [v, [k]] } }.to_h
85
85
 
86
86
  ENGLISH_VARS.merge!(
87
- Hash[ENGLISH_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }]
87
+ ENGLISH_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }.to_h
88
88
  )
89
89
  PERL_VARS.merge!(
90
- Hash[PERL_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }]
90
+ PERL_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }.to_h
91
91
  )
92
92
  ENGLISH_VARS.each_value(&:freeze).freeze
93
93
  PERL_VARS.each_value(&:freeze).freeze
@@ -63,7 +63,7 @@ module RuboCop
63
63
  # rubocop:enable Metrics/AbcSize
64
64
 
65
65
  def ordered_offense_counts(offense_counts)
66
- Hash[offense_counts.sort_by { |k, v| [-v, k] }]
66
+ offense_counts.sort_by { |k, v| [-v, k] }.to_h
67
67
  end
68
68
 
69
69
  def total_offense_count(offense_counts)
@@ -51,7 +51,7 @@ module RuboCop
51
51
  # rubocop:enable Metrics/AbcSize
52
52
 
53
53
  def ordered_offense_counts(offense_counts)
54
- Hash[offense_counts.sort_by { |k, v| [-v, k] }]
54
+ offense_counts.sort_by { |k, v| [-v, k] }.to_h
55
55
  end
56
56
 
57
57
  def total_offense_count(offense_counts)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.9.1'
6
+ STRING = '1.10.0'
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: 1.9.1
4
+ version: 1.10.0
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: 2021-02-01 00:00:00.000000000 Z
13
+ date: 2021-02-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -244,6 +244,7 @@ files:
244
244
  - lib/rubocop/cop/documentation.rb
245
245
  - lib/rubocop/cop/exclude_limit.rb
246
246
  - lib/rubocop/cop/force.rb
247
+ - lib/rubocop/cop/gemspec/date_assignment.rb
247
248
  - lib/rubocop/cop/gemspec/duplicated_assignment.rb
248
249
  - lib/rubocop/cop/gemspec/ordered_dependencies.rb
249
250
  - lib/rubocop/cop/gemspec/required_ruby_version.rb
@@ -655,6 +656,7 @@ files:
655
656
  - lib/rubocop/cop/style/global_vars.rb
656
657
  - lib/rubocop/cop/style/guard_clause.rb
657
658
  - lib/rubocop/cop/style/hash_as_last_array_item.rb
659
+ - lib/rubocop/cop/style/hash_conversion.rb
658
660
  - lib/rubocop/cop/style/hash_each_methods.rb
659
661
  - lib/rubocop/cop/style/hash_except.rb
660
662
  - lib/rubocop/cop/style/hash_like_case.rb
@@ -866,7 +868,7 @@ metadata:
866
868
  homepage_uri: https://rubocop.org/
867
869
  changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
868
870
  source_code_uri: https://github.com/rubocop-hq/rubocop/
869
- documentation_uri: https://docs.rubocop.org/rubocop/1.9/
871
+ documentation_uri: https://docs.rubocop.org/rubocop/1.10/
870
872
  bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
871
873
  post_install_message:
872
874
  rdoc_options: []