diff --git a/changelog/fix_recover_ruby_23_code_analysis.md b/changelog/fix_recover_ruby_23_code_analysis.md new file mode 100644 index 00000000000..76e66a4afc9 --- /dev/null +++ b/changelog/fix_recover_ruby_23_code_analysis.md @@ -0,0 +1 @@ +* [#10640](https://github.com/rubocop/rubocop/pull/10640): Recover Ruby 2.3 code analysis using `TargetRubyVersion: 2.3`. ([@koic][]) diff --git a/lib/rubocop/cop/lint/unified_integer.rb b/lib/rubocop/cop/lint/unified_integer.rb index a7c46babe37..0b0b1232594 100644 --- a/lib/rubocop/cop/lint/unified_integer.rb +++ b/lib/rubocop/cop/lint/unified_integer.rb @@ -33,6 +33,8 @@ def on_const(node) return unless klass add_offense(node, message: format(MSG, klass: klass)) do |corrector| + next if target_ruby_version <= 2.3 + corrector.replace(node.loc.name, 'Integer') end end diff --git a/lib/rubocop/cop/style/hash_transform_values.rb b/lib/rubocop/cop/style/hash_transform_values.rb index 3d135e09cd7..bb60aede2c2 100644 --- a/lib/rubocop/cop/style/hash_transform_values.rb +++ b/lib/rubocop/cop/style/hash_transform_values.rb @@ -26,6 +26,9 @@ module Style class HashTransformValues < Base include HashTransformMethod extend AutoCorrector + extend TargetRubyVersion + + minimum_target_ruby_version 2.4 # @!method on_bad_each_with_object(node) def_node_matcher :on_bad_each_with_object, <<~PATTERN diff --git a/lib/rubocop/cop/style/unpack_first.rb b/lib/rubocop/cop/style/unpack_first.rb index 6abc7e4b6d9..45badcdd1ec 100644 --- a/lib/rubocop/cop/style/unpack_first.rb +++ b/lib/rubocop/cop/style/unpack_first.rb @@ -19,6 +19,9 @@ module Style # class UnpackFirst < Base extend AutoCorrector + extend TargetRubyVersion + + minimum_target_ruby_version 2.4 MSG = 'Use `%s.unpack1(%s)` instead of '\ '`%s.unpack(%s)%s`.' diff --git a/lib/rubocop/rspec/shared_contexts.rb b/lib/rubocop/rspec/shared_contexts.rb index d72630ddf1d..39a4093a3ba 100644 --- a/lib/rubocop/rspec/shared_contexts.rb +++ b/lib/rubocop/rspec/shared_contexts.rb @@ -116,6 +116,10 @@ def source_range(range, buffer: source_buffer) end end +RSpec.shared_context 'ruby 2.3', :ruby23 do + let(:ruby_version) { 2.3 } +end + RSpec.shared_context 'ruby 2.4', :ruby24 do let(:ruby_version) { 2.4 } end diff --git a/lib/rubocop/target_ruby.rb b/lib/rubocop/target_ruby.rb index 5569a05cc47..64cf4e88fb4 100644 --- a/lib/rubocop/target_ruby.rb +++ b/lib/rubocop/target_ruby.rb @@ -4,7 +4,7 @@ module RuboCop # The kind of Ruby that code inspected by RuboCop is written in. # @api private class TargetRuby - KNOWN_RUBIES = [2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze + KNOWN_RUBIES = [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze DEFAULT_VERSION = 2.6 OBSOLETE_RUBIES = { diff --git a/rubocop.gemspec b/rubocop.gemspec index 3a28d5a2800..a7c08c3c25d 100644 --- a/rubocop.gemspec +++ b/rubocop.gemspec @@ -36,7 +36,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0') s.add_runtime_dependency('regexp_parser', '>= 1.8', '< 3.0') s.add_runtime_dependency('rexml', '>= 3.2.5', '< 4.0') - s.add_runtime_dependency('rubocop-ast', '>= 1.17.0', '< 2.0') + s.add_runtime_dependency('rubocop-ast', '>= 1.18.0', '< 2.0') s.add_runtime_dependency('ruby-progressbar', '~> 1.7') s.add_runtime_dependency('unicode-display_width', '>= 1.4.0', '< 3.0') diff --git a/spec/rubocop/cli_spec.rb b/spec/rubocop/cli_spec.rb index ebeffb1d243..50c8770331d 100644 --- a/spec/rubocop/cli_spec.rb +++ b/spec/rubocop/cli_spec.rb @@ -1724,7 +1724,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85} 'Error: RuboCop found unknown Ruby version 4.0 in `TargetRubyVersion`' ) expect($stderr.string.strip).to match( - /Supported versions: 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2/ + /Supported versions: 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2/ ) end end @@ -1746,7 +1746,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85} /2\.0-compatible analysis was dropped after version 0\.50/ ) - expect($stderr.string.strip).to match(/Supported versions: 2.4/) + expect($stderr.string.strip).to match(/Supported versions: 2.3/) end end end diff --git a/spec/rubocop/config_loader_spec.rb b/spec/rubocop/config_loader_spec.rb index aeafcc13b28..7b696d632b9 100644 --- a/spec/rubocop/config_loader_spec.rb +++ b/spec/rubocop/config_loader_spec.rb @@ -1188,7 +1188,7 @@ class Loop < Base end context 'when the specified version is obsolete' do - let(:inherited_version) { '2.3' } + let(:inherited_version) { '2.2' } context 'and it is not overridden' do before do @@ -1199,7 +1199,7 @@ class Loop < Base it 'raises a validation error' do expect { configuration_from_file }.to raise_error(RuboCop::ValidationError) do |error| - expect(error.message).to start_with('RuboCop found unsupported Ruby version 2.3') + expect(error.message).to start_with('RuboCop found unsupported Ruby version 2.2') end end end diff --git a/spec/rubocop/cop/lint/unified_integer_spec.rb b/spec/rubocop/cop/lint/unified_integer_spec.rb index ad07d445778..353f1c4aa3e 100644 --- a/spec/rubocop/cop/lint/unified_integer_spec.rb +++ b/spec/rubocop/cop/lint/unified_integer_spec.rb @@ -2,36 +2,72 @@ RSpec.describe RuboCop::Cop::Lint::UnifiedInteger, :config do shared_examples 'registers an offense' do |klass| - context "when #{klass}" do - context 'without any decorations' do - it 'registers an offense and autocorrects' do - expect_offense(<<~RUBY, klass: klass) - 1.is_a?(%{klass}) - ^{klass} Use `Integer` instead of `#{klass}`. - RUBY - - expect_correction(<<~RUBY) - 1.is_a?(Integer) - RUBY + context 'target ruby version < 2.4', :ruby23 do + context "when #{klass}" do + context 'without any decorations' do + it 'registers an offense and autocorrects' do + expect_offense(<<~RUBY, klass: klass) + 1.is_a?(%{klass}) + ^{klass} Use `Integer` instead of `#{klass}`. + RUBY + + expect_no_corrections + end end - end - context 'when explicitly specified as toplevel constant' do - it 'registers an offense' do - expect_offense(<<~RUBY, klass: klass) - 1.is_a?(::%{klass}) - ^^^{klass} Use `Integer` instead of `#{klass}`. - RUBY + context 'when explicitly specified as toplevel constant' do + let(:source) { "1.is_a?(::#{klass})" } + + it 'registers an offense' do + expect_offense(<<~RUBY, klass: klass) + 1.is_a?(::%{klass}) + ^^^{klass} Use `Integer` instead of `#{klass}`. + RUBY - expect_correction(<<~RUBY) - 1.is_a?(::Integer) - RUBY + expect_no_corrections + end + end + + context 'with MyNamespace' do + it 'does not register an offense' do + expect_no_offenses("1.is_a?(MyNamespace::#{klass})") + end end end + end + + context 'target ruby version >= 2.4', :ruby24 do + context "when #{klass}" do + context 'without any decorations' do + it 'registers an offense' do + expect_offense(<<~RUBY, klass: klass) + 1.is_a?(#{klass}) + ^{klass} Use `Integer` instead of `#{klass}`. + RUBY + + expect_correction(<<~RUBY) + 1.is_a?(Integer) + RUBY + end + end + + context 'when explicitly specified as toplevel constant' do + it 'registers an offense' do + expect_offense(<<~RUBY, klass: klass) + 1.is_a?(::#{klass}) + ^^^{klass} Use `Integer` instead of `#{klass}`. + RUBY + + expect_correction(<<~RUBY) + 1.is_a?(::Integer) + RUBY + end + end - context 'with MyNamespace' do - it 'does not register an offense' do - expect_no_offenses("1.is_a?(MyNamespace::#{klass})") + context 'with MyNamespace' do + it 'does not register an offense' do + expect_no_offenses("1.is_a?(MyNamespace::#{klass})") + end end end end diff --git a/spec/rubocop/cop/style/hash_transform_values_spec.rb b/spec/rubocop/cop/style/hash_transform_values_spec.rb index cb366e7987d..48c5ed0e05b 100644 --- a/spec/rubocop/cop/style/hash_transform_values_spec.rb +++ b/spec/rubocop/cop/style/hash_transform_values_spec.rb @@ -1,221 +1,223 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Style::HashTransformValues, :config do - context 'with inline block' do - it 'flags each_with_object when transform_values could be used' do - expect_offense(<<~RUBY) - x.each_with_object({}) {|(k, v), h| h[k] = foo(v)} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. - RUBY + context 'when using Ruby 2.4 or newer', :ruby24 do + context 'with inline block' do + it 'flags each_with_object when transform_values could be used' do + expect_offense(<<~RUBY) + x.each_with_object({}) {|(k, v), h| h[k] = foo(v)} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. + RUBY + + expect_correction(<<~RUBY) + x.transform_values {|v| foo(v)} + RUBY + end + end - expect_correction(<<~RUBY) - x.transform_values {|v| foo(v)} - RUBY + context 'with multiline block' do + it 'flags each_with_object when transform_values could be used' do + expect_offense(<<~RUBY) + some_hash.each_with_object({}) do |(key, val), memo| + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. + memo[key] = val * val + end + RUBY + + expect_correction(<<~RUBY) + some_hash.transform_values do |val| + val * val + end + RUBY + end end - end - context 'with multiline block' do - it 'flags each_with_object when transform_values could be used' do - expect_offense(<<~RUBY) - some_hash.each_with_object({}) do |(key, val), memo| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. - memo[key] = val * val - end - RUBY + context 'with safe navigation operator' do + it 'flags each_with_object when transform_values could be used' do + expect_offense(<<~RUBY) + x&.each_with_object({}) {|(k, v), h| h[k] = foo(v)} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. + RUBY - expect_correction(<<~RUBY) - some_hash.transform_values do |val| - val * val - end - RUBY + expect_correction(<<~RUBY) + x&.transform_values {|v| foo(v)} + RUBY + end end - end - context 'with safe navigation operator' do - it 'flags each_with_object when transform_values could be used' do - expect_offense(<<~RUBY) - x&.each_with_object({}) {|(k, v), h| h[k] = foo(v)} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `each_with_object`. - RUBY - - expect_correction(<<~RUBY) - x&.transform_values {|v| foo(v)} + it 'does not flag each_with_object when both key & value are transformed' do + expect_no_offenses(<<~RUBY) + x.each_with_object({}) {|(k, v), h| h[k.to_sym] = foo(v)} RUBY end - end - - it 'does not flag each_with_object when both key & value are transformed' do - expect_no_offenses(<<~RUBY) - x.each_with_object({}) {|(k, v), h| h[k.to_sym] = foo(v)} - RUBY - end - it 'does not flag each_with_object when value transformation uses key' do - expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[k] = k.to_s}') - end + it 'does not flag each_with_object when value transformation uses key' do + expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[k] = k.to_s}') + end - it 'does not flag each_with_object when no transformation occurs' do - expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[k] = v}') - end + it 'does not flag each_with_object when no transformation occurs' do + expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[k] = v}') + end - it 'does not flag each_with_object when its argument is not modified' do - expect_no_offenses(<<~RUBY) - x.each_with_object({}) {|(k, v), h| other_h[k] = v * v} - RUBY - end + it 'does not flag each_with_object when its argument is not modified' do + expect_no_offenses(<<~RUBY) + x.each_with_object({}) {|(k, v), h| other_h[k] = v * v} + RUBY + end - it 'does not flag `each_with_object` when its argument is used in the value' do - expect_no_offenses(<<~RUBY) - x.each_with_object({}) { |(k, v), h| h[k] = h.count } - RUBY - end + it 'does not flag `each_with_object` when its argument is used in the value' do + expect_no_offenses(<<~RUBY) + x.each_with_object({}) { |(k, v), h| h[k] = h.count } + RUBY + end - it 'does not flag each_with_object when receiver is array literal' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each_with_object({}) {|(k, v), h| h[k] = foo(v)} - RUBY - end + it 'does not flag each_with_object when receiver is array literal' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each_with_object({}) {|(k, v), h| h[k] = foo(v)} + RUBY + end - it 'does not flag `each_with_object` when its receiver is `each_with_index`' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each_with_index.each_with_object({}) { |(k, v), h| h[k] = foo(v) } - RUBY - end + it 'does not flag `each_with_object` when its receiver is `each_with_index`' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each_with_index.each_with_object({}) { |(k, v), h| h[k] = foo(v) } + RUBY + end - it 'does not flag `each_with_object` when its receiver is `with_index`' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each.with_index.each_with_object({}) { |(k, v), h| h[k] = foo(v) } - RUBY - end + it 'does not flag `each_with_object` when its receiver is `with_index`' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each.with_index.each_with_object({}) { |(k, v), h| h[k] = foo(v) } + RUBY + end - it 'does not flag `each_with_object` when its receiver is `zip`' do - expect_no_offenses(<<~RUBY) - %i[a b c].zip([1, 2, 3]).each_with_object({}) { |(k, v), h| h[k] = foo(v) } - RUBY - end + it 'does not flag `each_with_object` when its receiver is `zip`' do + expect_no_offenses(<<~RUBY) + %i[a b c].zip([1, 2, 3]).each_with_object({}) { |(k, v), h| h[k] = foo(v) } + RUBY + end - it 'flags _.map {...}.to_h when transform_values could be used' do - expect_offense(<<~RUBY) - x.map {|k, v| [k, foo(v)]}.to_h - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. - RUBY + it 'flags _.map {...}.to_h when transform_values could be used' do + expect_offense(<<~RUBY) + x.map {|k, v| [k, foo(v)]}.to_h + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. + RUBY - expect_correction(<<~RUBY) - x.transform_values {|v| foo(v)} - RUBY - end + expect_correction(<<~RUBY) + x.transform_values {|v| foo(v)} + RUBY + end - it 'flags _.map {...}.to_h when transform_values could be used when line break before `to_h`' do - expect_offense(<<~RUBY) - x.map {|k, v| [k, foo(v)]}. - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. - to_h - RUBY + it 'flags _.map {...}.to_h when transform_values could be used when line break before `to_h`' do + expect_offense(<<~RUBY) + x.map {|k, v| [k, foo(v)]}. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. + to_h + RUBY - expect_correction(<<~RUBY) - x.transform_values {|v| foo(v)} - RUBY - end + expect_correction(<<~RUBY) + x.transform_values {|v| foo(v)} + RUBY + end - it 'flags _.map {...}.to_h when transform_values could be used when wrapped in another block' do - expect_offense(<<~RUBY) - wrapping do - x.map do |k, v| - ^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. - [k, v.to_s] - end.to_h - end - RUBY + it 'flags _.map {...}.to_h when transform_values could be used when wrapped in another block' do + expect_offense(<<~RUBY) + wrapping do + x.map do |k, v| + ^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. + [k, v.to_s] + end.to_h + end + RUBY - expect_correction(<<~RUBY) - wrapping do - x.transform_values do |v| - v.to_s + expect_correction(<<~RUBY) + wrapping do + x.transform_values do |v| + v.to_s + end end - end - RUBY - end + RUBY + end - it 'does not flag _.map{...}.to_h when both key & value are transformed' do - expect_no_offenses('x.map {|k, v| [k.to_sym, foo(v)]}.to_h') - end + it 'does not flag _.map{...}.to_h when both key & value are transformed' do + expect_no_offenses('x.map {|k, v| [k.to_sym, foo(v)]}.to_h') + end - it 'flags Hash[_.map{...}] when transform_values could be used' do - expect_offense(<<~RUBY) - Hash[x.map {|k, v| [k, foo(v)]}] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `Hash[_.map {...}]`. - RUBY + it 'flags Hash[_.map{...}] when transform_values could be used' do + expect_offense(<<~RUBY) + Hash[x.map {|k, v| [k, foo(v)]}] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `Hash[_.map {...}]`. + RUBY - expect_correction(<<~RUBY) - x.transform_values {|v| foo(v)} - RUBY - end + expect_correction(<<~RUBY) + x.transform_values {|v| foo(v)} + RUBY + end - it 'does not flag Hash[_.map{...}] when both key & value are transformed' do - expect_no_offenses('Hash[x.map {|k, v| [k.to_sym, foo(v)]}]') - end + it 'does not flag Hash[_.map{...}] when both key & value are transformed' do + expect_no_offenses('Hash[x.map {|k, v| [k.to_sym, foo(v)]}]') + end - it 'does not flag value transformation in the absence of to_h' do - expect_no_offenses('x.map {|k, v| [k, foo(v)]}') - end + it 'does not flag value transformation in the absence of to_h' do + expect_no_offenses('x.map {|k, v| [k, foo(v)]}') + end - it 'does not flag value transformation when receiver is array literal' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].map {|k, v| [k, foo(v)]}.to_h - RUBY - end + it 'does not flag value transformation when receiver is array literal' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].map {|k, v| [k, foo(v)]}.to_h + RUBY + end - it 'does not flag `_.map{...}.to_h` when its receiver is `each_with_index`' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each_with_index.map { |k, v| [k, foo(v)] }.to_h - RUBY - end + it 'does not flag `_.map{...}.to_h` when its receiver is `each_with_index`' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each_with_index.map { |k, v| [k, foo(v)] }.to_h + RUBY + end - it 'does not flag `_.map{...}.to_h` when its receiver is `with_index`' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each.with_index.map { |k, v| [k, foo(v)] }.to_h - RUBY - end + it 'does not flag `_.map{...}.to_h` when its receiver is `with_index`' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each.with_index.map { |k, v| [k, foo(v)] }.to_h + RUBY + end - it 'does not flag `_.map{...}.to_h` when its receiver is `zip`' do - expect_no_offenses(<<~RUBY) - %i[a b c].zip([1, 2, 3]).map { |k, v| [k, foo(v)] }.to_h - RUBY - end + it 'does not flag `_.map{...}.to_h` when its receiver is `zip`' do + expect_no_offenses(<<~RUBY) + %i[a b c].zip([1, 2, 3]).map { |k, v| [k, foo(v)] }.to_h + RUBY + end - it 'correctly autocorrects _.map{...}.to_h with block' do - expect_offense(<<~RUBY) - {a: 1, b: 2}.map {|k, v| [k, foo(v)]}.to_h {|k, v| [v, k]} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. - RUBY + it 'correctly autocorrects _.map{...}.to_h with block' do + expect_offense(<<~RUBY) + {a: 1, b: 2}.map {|k, v| [k, foo(v)]}.to_h {|k, v| [v, k]} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_values` over `map {...}.to_h`. + RUBY - expect_correction(<<~RUBY) - {a: 1, b: 2}.transform_values {|v| foo(v)}.to_h {|k, v| [v, k]} - RUBY - end + expect_correction(<<~RUBY) + {a: 1, b: 2}.transform_values {|v| foo(v)}.to_h {|k, v| [v, k]} + RUBY + end - it 'does not flag `Hash[_.map{...}]` when its receiver is an array literal' do - expect_no_offenses(<<~RUBY) - Hash[[1, 2, 3].map { |k, v| [k, foo(v)] }] - RUBY - end + it 'does not flag `Hash[_.map{...}]` when its receiver is an array literal' do + expect_no_offenses(<<~RUBY) + Hash[[1, 2, 3].map { |k, v| [k, foo(v)] }] + RUBY + end - it 'does not flag `Hash[_.map{...}]` when its receiver is `each_with_index`' do - expect_no_offenses(<<~RUBY) - Hash[[1, 2, 3].each_with_index.map { |k, v| [k, foo(v)] }] - RUBY - end + it 'does not flag `Hash[_.map{...}]` when its receiver is `each_with_index`' do + expect_no_offenses(<<~RUBY) + Hash[[1, 2, 3].each_with_index.map { |k, v| [k, foo(v)] }] + RUBY + end - it 'does not flag `Hash[_.map{...}]` when its receiver is `with_index`' do - expect_no_offenses(<<~RUBY) - Hash[[1, 2, 3].each.with_index.map { |k, v| [k, foo(v)] }] - RUBY - end + it 'does not flag `Hash[_.map{...}]` when its receiver is `with_index`' do + expect_no_offenses(<<~RUBY) + Hash[[1, 2, 3].each.with_index.map { |k, v| [k, foo(v)] }] + RUBY + end - it 'does not flag `Hash[_.map{...}]` when its receiver is `zip`' do - expect_no_offenses(<<~RUBY) - Hash[%i[a b c].zip([1, 2, 3]).map { |k, v| [k, foo(v)] }] - RUBY + it 'does not flag `Hash[_.map{...}]` when its receiver is `zip`' do + expect_no_offenses(<<~RUBY) + Hash[%i[a b c].zip([1, 2, 3]).map { |k, v| [k, foo(v)] }] + RUBY + end end context 'when using Ruby 2.6 or newer', :ruby26 do @@ -283,6 +285,12 @@ end end + context 'below Ruby 2.4', :ruby23 do + it 'does not flag even if transform_values could be used' do + expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[k] = foo(v)}') + end + end + context 'below Ruby 2.6', :ruby25 do it 'does not flag _.to_h{...}' do expect_no_offenses(<<~RUBY) diff --git a/spec/rubocop/cop/style/unpack_first_spec.rb b/spec/rubocop/cop/style/unpack_first_spec.rb index faa549243a3..e1fe3818b9a 100644 --- a/spec/rubocop/cop/style/unpack_first_spec.rb +++ b/spec/rubocop/cop/style/unpack_first_spec.rb @@ -1,74 +1,76 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Style::UnpackFirst, :config do - context 'registers offense' do - it 'when using `#unpack` with `#first`' do - expect_offense(<<~RUBY) - x.unpack('h*').first - ^^^^^^^^^^^^^^^^^^^^ Use `x.unpack1('h*')` instead of `x.unpack('h*').first`. - RUBY + context 'ruby version >= 2.4', :ruby24 do + context 'registers offense' do + it 'when using `#unpack` with `#first`' do + expect_offense(<<~RUBY) + x.unpack('h*').first + ^^^^^^^^^^^^^^^^^^^^ Use `x.unpack1('h*')` instead of `x.unpack('h*').first`. + RUBY - expect_correction(<<~RUBY) - x.unpack1('h*') - RUBY - end + expect_correction(<<~RUBY) + x.unpack1('h*') + RUBY + end - it 'when using `#unpack` with square brackets' do - expect_offense(<<~RUBY) - ''.unpack(y)[0] - ^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y)[0]`. - RUBY + it 'when using `#unpack` with square brackets' do + expect_offense(<<~RUBY) + ''.unpack(y)[0] + ^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y)[0]`. + RUBY - expect_correction(<<~RUBY) - ''.unpack1(y) - RUBY - end + expect_correction(<<~RUBY) + ''.unpack1(y) + RUBY + end - it 'when using `#unpack` with dot and square brackets' do - expect_offense(<<~RUBY) - ''.unpack(y).[](0) - ^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).[](0)`. - RUBY + it 'when using `#unpack` with dot and square brackets' do + expect_offense(<<~RUBY) + ''.unpack(y).[](0) + ^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).[](0)`. + RUBY - expect_correction(<<~RUBY) - ''.unpack1(y) - RUBY - end + expect_correction(<<~RUBY) + ''.unpack1(y) + RUBY + end - it 'when using `#unpack` with `#slice`' do - expect_offense(<<~RUBY) - ''.unpack(y).slice(0) - ^^^^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).slice(0)`. - RUBY + it 'when using `#unpack` with `#slice`' do + expect_offense(<<~RUBY) + ''.unpack(y).slice(0) + ^^^^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).slice(0)`. + RUBY - expect_correction(<<~RUBY) - ''.unpack1(y) - RUBY - end + expect_correction(<<~RUBY) + ''.unpack1(y) + RUBY + end - it 'when using `#unpack` with `#at`' do - expect_offense(<<~RUBY) - ''.unpack(y).at(0) - ^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).at(0)`. - RUBY + it 'when using `#unpack` with `#at`' do + expect_offense(<<~RUBY) + ''.unpack(y).at(0) + ^^^^^^^^^^^^^^^^^^ Use `''.unpack1(y)` instead of `''.unpack(y).at(0)`. + RUBY - expect_correction(<<~RUBY) - ''.unpack1(y) - RUBY + expect_correction(<<~RUBY) + ''.unpack1(y) + RUBY + end end - end - context 'does not register offense' do - it 'when using `#unpack1`' do - expect_no_offenses(<<~RUBY) - x.unpack1(y) - RUBY - end + context 'does not register offense' do + it 'when using `#unpack1`' do + expect_no_offenses(<<~RUBY) + x.unpack1(y) + RUBY + end - it 'when using `#unpack` accessing second element' do - expect_no_offenses(<<~RUBY) - ''.unpack('h*')[1] - RUBY + it 'when using `#unpack` accessing second element' do + expect_no_offenses(<<~RUBY) + ''.unpack('h*')[1] + RUBY + end end end end