diff --git a/.circleci/config.yml b/.circleci/config.yml index e460801f474..0df65b72ec5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,29 +46,6 @@ rubocop_steps: &rubocop_steps jobs: - # Ruby 2.4 - ruby-2.4-spec: - docker: - - image: circleci/ruby:2.4 - environment: - <<: *common_env - steps: - *spec_steps - ruby-2.4-ascii_spec: - docker: - - image: circleci/ruby:2.4 - environment: - <<: *common_env - steps: - *ascii_spec_steps - ruby-2.4-rubocop: - docker: - - image: circleci/ruby:2.4 - environment: - <<: *common_env - steps: - *rubocop_steps - # Ruby 2.5 ruby-2.5-spec: docker: @@ -242,7 +219,7 @@ jobs: - run: name: Upload coverage results to Code Climate command: | - ./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json --parts 6 --output tmp/codeclimate.total.json + ./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json --parts 5 --output tmp/codeclimate.total.json ./tmp/cc-test-reporter upload-coverage --input tmp/codeclimate.total.json # Miscellaneous tasks @@ -264,11 +241,6 @@ workflows: jobs: - documentation-checks - cc-setup - - ruby-2.4-spec: - requires: - - cc-setup - - ruby-2.4-ascii_spec - - ruby-2.4-rubocop - ruby-2.5-spec: requires: - cc-setup @@ -302,7 +274,6 @@ workflows: - cc-upload-coverage: requires: - - ruby-2.4-spec - ruby-2.5-spec - ruby-2.6-spec - ruby-2.7-spec diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 61482a6b3e1..e1430f0fa06 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -21,7 +21,7 @@ jobs: matrix: # [ ubuntu, macos, windows ] os: [ windows ] - ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0', 'head' ] + ruby: [ '2.5', '2.6', '2.7', '3.0', 'head' ] include: - { os: windows, ruby: mingw } exclude: diff --git a/.mergify.yml b/.mergify.yml index a799092094b..7f991cc6839 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -8,7 +8,6 @@ pull_request_rules: - label=auto-merge - "#review-requested=0" - "#changes-requested-reviews-by=0" - - "status-success=windows 2.4" - "status-success=windows 2.5" - "status-success=windows 2.6" - "status-success=windows 2.7" @@ -20,9 +19,6 @@ pull_request_rules: - "status-success=ci/circleci: jruby-9.2-ascii_spec" - "status-success=ci/circleci: jruby-9.2-rubocop" - "status-success=ci/circleci: jruby-9.2-spec" - - "status-success=ci/circleci: ruby-2.4-ascii_spec" - - "status-success=ci/circleci: ruby-2.4-rubocop" - - "status-success=ci/circleci: ruby-2.4-spec" - "status-success=ci/circleci: ruby-2.5-ascii_spec" - "status-success=ci/circleci: ruby-2.5-rubocop" - "status-success=ci/circleci: ruby-2.5-spec" diff --git a/.rubocop.yml b/.rubocop.yml index 5501680d59c..ca8e688a3a8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -14,7 +14,7 @@ AllCops: - 'tmp/**/*' - '.git/**/*' - 'bin/*' - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 SuggestExtensions: false Naming/PredicateName: diff --git a/Gemfile b/Gemfile index f799e60d714..bc7f839245d 100644 --- a/Gemfile +++ b/Gemfile @@ -5,13 +5,7 @@ source 'https://rubygems.org' gemspec gem 'bump', require: false -# memory_profiler 1.0.0 requires Ruby 2.5.0 or higher. -# Please remove this branch when dropping support for Ruby 2.4. -if RUBY_VERSION >= '2.5.0' - gem 'memory_profiler', platform: :mri -else - gem 'memory_profiler', '<= 1.0.0', platform: :mri -end +gem 'memory_profiler', platform: :mri gem 'rake', '~> 13.0' gem 'rspec', '~> 3.7' gem 'rubocop-performance', '~> 1.10.0' diff --git a/README.md b/README.md index e3f43bb7f21..972463ff112 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ You can read a lot more about RuboCop in its [official docs](https://docs.ruboco RuboCop officially supports the following Ruby implementations: -* MRI 2.4+ +* MRI 2.5+ * JRuby 9.2+ See the [compatibility documentation](https://docs.rubocop.org/rubocop/compatibility.html) for further details. diff --git a/Rakefile b/Rakefile index 0116e7bdf45..9cfe953688d 100644 --- a/Rakefile +++ b/Rakefile @@ -103,32 +103,30 @@ task documentation_syntax_check: :yard_for_generate_documentation do end examples.each do |example| - begin - buffer = Parser::Source::Buffer.new('', 1) - buffer.source = example.text - - # Ruby 2.6 or higher does not support a syntax used in - # `Lint/UselessElseWithoutRescue` cop's example. - parser = if cop == RuboCop::Cop::Lint::UselessElseWithoutRescue - Parser::Ruby25.new(RuboCop::AST::Builder.new) - # Ruby 2.7 raises a syntax error in - # `Lint/CircularArgumentReference` cop's example. - elsif cop == RuboCop::Cop::Lint::CircularArgumentReference - Parser::Ruby26.new(RuboCop::AST::Builder.new) - # Ruby 3.0 raises a syntax error in - # `Lint/NumberedParameterAssignment` cop's example. - elsif cop == RuboCop::Cop::Lint::NumberedParameterAssignment - Parser::Ruby27.new(RuboCop::AST::Builder.new) - else - Parser::Ruby30.new(RuboCop::AST::Builder.new) - end - parser.diagnostics.all_errors_are_fatal = true - parser.parse(buffer) - rescue Parser::SyntaxError => e - path = example.object.file - puts "#{path}: Syntax Error in an example. #{e}" - ok = false - end + buffer = Parser::Source::Buffer.new('', 1) + buffer.source = example.text + + # Ruby 2.6 or higher does not support a syntax used in + # `Lint/UselessElseWithoutRescue` cop's example. + parser = if cop == RuboCop::Cop::Lint::UselessElseWithoutRescue + Parser::Ruby25.new(RuboCop::AST::Builder.new) + # Ruby 2.7 raises a syntax error in + # `Lint/CircularArgumentReference` cop's example. + elsif cop == RuboCop::Cop::Lint::CircularArgumentReference + Parser::Ruby26.new(RuboCop::AST::Builder.new) + # Ruby 3.0 raises a syntax error in + # `Lint/NumberedParameterAssignment` cop's example. + elsif cop == RuboCop::Cop::Lint::NumberedParameterAssignment + Parser::Ruby27.new(RuboCop::AST::Builder.new) + else + Parser::Ruby30.new(RuboCop::AST::Builder.new) + end + parser.diagnostics.all_errors_are_fatal = true + parser.parse(buffer) + rescue Parser::SyntaxError => e + path = example.object.file + puts "#{path}: Syntax Error in an example. #{e}" + ok = false end end abort unless ok diff --git a/changelog/change_drop_ruby_24.md b/changelog/change_drop_ruby_24.md new file mode 100644 index 00000000000..9a0e723a8bf --- /dev/null +++ b/changelog/change_drop_ruby_24.md @@ -0,0 +1 @@ +* [#9647](https://github.com/rubocop/rubocop/pull/9647): Drop support for Ruby 2.4. ([@koic][]) diff --git a/docs/modules/ROOT/pages/compatibility.adoc b/docs/modules/ROOT/pages/compatibility.adoc index e5a1f2de3ca..30af1bb067b 100644 --- a/docs/modules/ROOT/pages/compatibility.adoc +++ b/docs/modules/ROOT/pages/compatibility.adoc @@ -1,10 +1,10 @@ = Compatibility -RuboCop targets Ruby 2.4+.footnote:[As defined by its reference implementation MRI.] +RuboCop targets Ruby 2.5+.footnote:[As defined by its reference implementation MRI.] RuboCop officially supports MRI (a.k.a. CRuby) and JRuby. -- MRI 2.4+ +- MRI 2.5+ - JRuby 9.2+ The oldest supported JRuby version is derived from the oldest compatible MRI version. @@ -14,7 +14,7 @@ NOTE: RuboCop might be working with other Ruby implementations as well, but it's == Support Matrix RuboCop generally aims to follow MRI's own support policy - meaning RuboCop would support all officially supported MRI releases.footnote:[Typically the last 3 releases.] To give people extra time for a smooth transition, we've customarily provided support for about one year after EOL of MRI version. -This means that if Ruby 2.4 reaches its EOL in Spring 2020, it would be supported by RuboCop (at least) until Spring 2021.footnote:[At the core team's discretion this policy might be waived aside for MRI releases causing significant maintenance overhead.] +This means that if Ruby 2.5 reaches its EOL in Spring 2021, it would be supported by RuboCop (at least) until Spring 2022.footnote:[At the core team's discretion this policy might be waived aside for MRI releases causing significant maintenance overhead.] The following table is the support matrix. @@ -26,7 +26,7 @@ The following table is the support matrix. | 2.1 | 0.57 | 2.2 | 0.68 | 2.3 | 0.81 -| 2.4 | - +| 2.4 | 1.12 | 2.5 | - | 2.6 | - | 2.7 | - diff --git a/docs/modules/ROOT/pages/formatters.adoc b/docs/modules/ROOT/pages/formatters.adoc index a9f4149fb32..cbb24417f69 100644 --- a/docs/modules/ROOT/pages/formatters.adoc +++ b/docs/modules/ROOT/pages/formatters.adoc @@ -205,11 +205,11 @@ The JSON structure is like the following example: ---- { "metadata": { - "rubocop_version": "0.50.0", + "rubocop_version": "1.12.0", "ruby_engine": "ruby", - "ruby_version": "2.4.2", - "ruby_patchlevel": "198", - "ruby_platform": "x86_64-darwin12.3.0" + "ruby_version": "3.0.0", + "ruby_patchlevel": "0", + "ruby_platform": "x86_64-darwin19" }, "files": [{ "path": "lib/foo.rb", diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 493ced4490f..180d4ef66c6 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -18,7 +18,6 @@ require_relative 'rubocop/ext/regexp_parser' require_relative 'rubocop/core_ext/string' -require_relative 'rubocop/core_ext/hash' require_relative 'rubocop/ext/processed_source' require_relative 'rubocop/path_util' diff --git a/lib/rubocop/comment_config.rb b/lib/rubocop/comment_config.rb index c29e62914af..93d0e7ff7d3 100644 --- a/lib/rubocop/comment_config.rb +++ b/lib/rubocop/comment_config.rb @@ -32,9 +32,7 @@ def extra_enabled_comments end def comment_only_line?(line_number) - non_comment_token_line_numbers.none? do |non_comment_line_number| - non_comment_line_number == line_number - end + non_comment_token_line_numbers.none?(line_number) end private diff --git a/lib/rubocop/cop/generator/require_file_injector.rb b/lib/rubocop/cop/generator/require_file_injector.rb index a871659c159..022b9950558 100644 --- a/lib/rubocop/cop/generator/require_file_injector.rb +++ b/lib/rubocop/cop/generator/require_file_injector.rb @@ -29,9 +29,7 @@ def inject attr_reader :require_entries, :root_file_path, :source_path, :output def require_exists? - require_entries.any? do |entry| - entry == injectable_require_directive - end + require_entries.any?(injectable_require_directive) end def updated_directives diff --git a/lib/rubocop/cop/lint/shadowed_exception.rb b/lib/rubocop/cop/lint/shadowed_exception.rb index 1bb0444635b..00cdebd457b 100644 --- a/lib/rubocop/cop/lint/shadowed_exception.rb +++ b/lib/rubocop/cop/lint/shadowed_exception.rb @@ -111,6 +111,9 @@ def evaluate_exceptions(group) if rescued_exceptions.any? rescued_exceptions.each_with_object([]) do |exception, converted| + # FIXME: Workaround `rubocop:disable` comment for JRuby. + # https://github.com/jruby/jruby/issues/6642 + # rubocop:disable Style/RedundantBegin begin RuboCop::Util.silence_warnings do # Avoid printing deprecation warnings about constants @@ -119,6 +122,7 @@ def evaluate_exceptions(group) rescue NameError converted << nil end + # rubocop:enable Style/RedundantBegin end else # treat an empty `rescue` as `rescue StandardError` diff --git a/lib/rubocop/cop/lint/symbol_conversion.rb b/lib/rubocop/cop/lint/symbol_conversion.rb index 3faf652c9ea..9513bc686b7 100644 --- a/lib/rubocop/cop/lint/symbol_conversion.rb +++ b/lib/rubocop/cop/lint/symbol_conversion.rb @@ -152,7 +152,7 @@ def correct_hash_key(node) # will be ignored. return unless node.value.to_s.match?(/\A[a-z0-9_]/i) - correction = node.value.inspect.gsub(/\A:/, '') + correction = node.value.inspect.delete_prefix(':') return if properly_quoted?(node.source, correction) register_offense( diff --git a/lib/rubocop/cop/mixin/method_preference.rb b/lib/rubocop/cop/mixin/method_preference.rb index d4068b72e1a..f81f7d97220 100644 --- a/lib/rubocop/cop/mixin/method_preference.rb +++ b/lib/rubocop/cop/mixin/method_preference.rb @@ -18,8 +18,7 @@ def preferred_methods default = default_cop_config['PreferredMethods'] merged = cop_config['PreferredMethods'] overrides = merged.values - default.values - merged.reject { |key, _| overrides.include?(key) } - .map { |k, v| [k.to_sym, v] }.to_h + merged.reject { |key, _| overrides.include?(key) }.transform_keys(&:to_sym) end end diff --git a/lib/rubocop/cop/naming/memoized_instance_variable_name.rb b/lib/rubocop/cop/naming/memoized_instance_variable_name.rb index f4f66397cac..d8f8427c37f 100644 --- a/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +++ b/lib/rubocop/cop/naming/memoized_instance_variable_name.rb @@ -260,7 +260,7 @@ def suggested_var(method_name) end def variable_name_candidates(method_name) - no_underscore = method_name.sub(/\A_/, '') + no_underscore = method_name.delete_prefix('_') with_underscore = "_#{method_name}" case style when :required diff --git a/lib/rubocop/cop/style/hash_syntax.rb b/lib/rubocop/cop/style/hash_syntax.rb index cf644d094d3..6b332816f56 100644 --- a/lib/rubocop/cop/style/hash_syntax.rb +++ b/lib/rubocop/cop/style/hash_syntax.rb @@ -137,7 +137,7 @@ def word_symbol_pair?(pair) end def acceptable_19_syntax_symbol?(sym_name) - sym_name.sub!(/\A:/, '') + sym_name.delete_prefix!(':') if cop_config['PreferHashRocketsForNonAlnumEndingSymbols'] && # Prefer { :production? => false } over { production?: false } and diff --git a/lib/rubocop/cop/style/multiple_comparison.rb b/lib/rubocop/cop/style/multiple_comparison.rb index 329033bae7a..827ae1033b3 100644 --- a/lib/rubocop/cop/style/multiple_comparison.rb +++ b/lib/rubocop/cop/style/multiple_comparison.rb @@ -142,7 +142,7 @@ def root_of_or_node(or_node) def switch_comparison?(node) return true if @last_comparison.nil? - @last_comparison.descendants.none? { |descendant| descendant == node } + @last_comparison.descendants.none?(node) end def reset_comparison diff --git a/lib/rubocop/cop/style/nested_ternary_operator.rb b/lib/rubocop/cop/style/nested_ternary_operator.rb index 6ebcb462f00..603d9516699 100644 --- a/lib/rubocop/cop/style/nested_ternary_operator.rb +++ b/lib/rubocop/cop/style/nested_ternary_operator.rb @@ -51,7 +51,7 @@ def if_node(node) def remove_parentheses(source) return source unless source.start_with?('(') - source.gsub(/\A\(/, '').gsub(/\)\z/, '') + source.delete_prefix('(').delete_suffix(')') end end end diff --git a/lib/rubocop/cop/style/parallel_assignment.rb b/lib/rubocop/cop/style/parallel_assignment.rb index 005f74b62bb..bb6d1b31f34 100644 --- a/lib/rubocop/cop/style/parallel_assignment.rb +++ b/lib/rubocop/cop/style/parallel_assignment.rb @@ -164,9 +164,12 @@ def dependency?(lhs, rhs) # Does `rhs` access the same value which is assigned by `lhs`? def accesses?(rhs, lhs) if lhs.method?(:[]=) + # FIXME: Workaround `rubocop:disable` comment for JRuby. + # rubocop:disable Performance/RedundantEqualityComparisonBlock matching_calls(rhs, lhs.receiver, :[]).any? do |args| args == lhs.arguments end + # rubocop:enable Performance/RedundantEqualityComparisonBlock else access_method = lhs.method_name.to_s.chop.to_sym matching_calls(rhs, lhs.receiver, access_method).any? diff --git a/lib/rubocop/cop/style/redundant_begin.rb b/lib/rubocop/cop/style/redundant_begin.rb index 1af81634648..fabb01744a8 100644 --- a/lib/rubocop/cop/style/redundant_begin.rb +++ b/lib/rubocop/cop/style/redundant_begin.rb @@ -36,7 +36,6 @@ module Style # do_something # # # bad - # # When using Ruby 2.5 or later. # do_something do # begin # something @@ -76,8 +75,6 @@ def on_def(node) alias on_defs on_def def on_block(node) - return if target_ruby_version < 2.5 - return if node.send_node.lambda_literal? return if node.braces? return unless node.body&.kwbegin_type? diff --git a/lib/rubocop/cop/style/redundant_file_extension_in_require.rb b/lib/rubocop/cop/style/redundant_file_extension_in_require.rb index 5cf4c37f1a5..1875cc30262 100644 --- a/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +++ b/lib/rubocop/cop/style/redundant_file_extension_in_require.rb @@ -40,7 +40,7 @@ def on_send(node) return unless name_node.value.end_with?('.rb') add_offense(name_node) do |corrector| - correction = name_node.value.sub(/\.rb\z/, '') + correction = name_node.value.delete_suffix('.rb') corrector.replace(name_node, "'#{correction}'") end diff --git a/lib/rubocop/cop/style/redundant_return.rb b/lib/rubocop/cop/style/redundant_return.rb index 979da17271b..8b7624f237c 100644 --- a/lib/rubocop/cop/style/redundant_return.rb +++ b/lib/rubocop/cop/style/redundant_return.rb @@ -73,7 +73,7 @@ def correct_with_arguments(return_node, corrector) end if return_node.splat_argument? first_argument = return_node.first_argument - corrector.replace(first_argument, first_argument.source.gsub(/\A\*/, '')) + corrector.replace(first_argument, first_argument.source.delete_prefix('*')) end keyword = range_with_surrounding_space(range: return_node.loc.keyword, diff --git a/lib/rubocop/cop/style/unless_logical_operators.rb b/lib/rubocop/cop/style/unless_logical_operators.rb index 70e86a805fe..9f4958deeea 100644 --- a/lib/rubocop/cop/style/unless_logical_operators.rb +++ b/lib/rubocop/cop/style/unless_logical_operators.rb @@ -90,14 +90,14 @@ def mixed_precedence_and?(node) and_sources = node.condition.each_descendant(:and).map(&:operator) and_sources << node.condition.operator if node.condition.and_type? - !(and_sources.all? { |s| s == '&&' } || and_sources.all? { |s| s == 'and' }) + !(and_sources.all?('&&') || and_sources.all?('and')) end def mixed_precedence_or?(node) or_sources = node.condition.each_descendant(:or).map(&:operator) or_sources << node.condition.operator if node.condition.or_type? - !(or_sources.all? { |s| s == '||' } || or_sources.all? { |s| s == 'or' }) + !(or_sources.all?('||') || or_sources.all?('or')) end end end diff --git a/lib/rubocop/core_ext/hash.rb b/lib/rubocop/core_ext/hash.rb deleted file mode 100644 index 2e1be74a75a..00000000000 --- a/lib/rubocop/core_ext/hash.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -# Extensions to the core Hash class -class Hash - unless method_defined?(:slice) - # Adds `Hash#slice` for Ruby 2.4. - # Returns a hash containing a subset of keys. If a given key is not - # in the hash, it will not be returned. - # - # @return [Hash] hash containing only the keys given. - # - # @example - # { one: 1, two: 2 }.slice(:two, :three) #=> { two: 2 } - def slice(*keys) - h = {} - keys.each { |k| h[k] = self[k] if key?(k) } - h - end - end -end diff --git a/lib/rubocop/remote_config.rb b/lib/rubocop/remote_config.rb index 585eebf7b41..2c2f2d23714 100644 --- a/lib/rubocop/remote_config.rb +++ b/lib/rubocop/remote_config.rb @@ -46,11 +46,9 @@ def request(uri = @uri, limit = 10, &block) http.use_ssl = uri.instance_of?(URI::HTTPS) generate_request(uri) do |request| - begin - handle_response(http.request(request), limit, &block) - rescue SocketError => e - handle_response(e, limit, &block) - end + handle_response(http.request(request), limit, &block) + rescue SocketError => e + handle_response(e, limit, &block) end end diff --git a/lib/rubocop/rspec/cop_helper.rb b/lib/rubocop/rspec/cop_helper.rb index b2d3d6f12a2..011b040bb5c 100644 --- a/lib/rubocop/rspec/cop_helper.rb +++ b/lib/rubocop/rspec/cop_helper.rb @@ -6,7 +6,7 @@ module CopHelper extend RSpec::SharedContext - let(:ruby_version) { 2.4 } + let(:ruby_version) { 2.5 } let(:rails_version) { false } def inspect_source(source, file = nil) diff --git a/lib/rubocop/rspec/shared_contexts.rb b/lib/rubocop/rspec/shared_contexts.rb index 1e250a01e8a..d64a6257744 100644 --- a/lib/rubocop/rspec/shared_contexts.rb +++ b/lib/rubocop/rspec/shared_contexts.rb @@ -123,10 +123,6 @@ def source_range(range, buffer: source_buffer) end end -RSpec.shared_context 'ruby 2.4', :ruby24 do - let(:ruby_version) { 2.4 } -end - RSpec.shared_context 'ruby 2.5', :ruby25 do let(:ruby_version) { 2.5 } end diff --git a/lib/rubocop/target_ruby.rb b/lib/rubocop/target_ruby.rb index 4b4c09d78ee..79599f4d051 100644 --- a/lib/rubocop/target_ruby.rb +++ b/lib/rubocop/target_ruby.rb @@ -4,11 +4,11 @@ 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].freeze + KNOWN_RUBIES = [2.5, 2.6, 2.7, 3.0].freeze DEFAULT_VERSION = KNOWN_RUBIES.first OBSOLETE_RUBIES = { - 1.9 => '0.41', 2.0 => '0.50', 2.1 => '0.57', 2.2 => '0.68', 2.3 => '0.81' + 1.9 => '0.41', 2.0 => '0.50', 2.1 => '0.57', 2.2 => '0.68', 2.3 => '0.81', 2.4 => '1.12' }.freeze private_constant :KNOWN_RUBIES, :OBSOLETE_RUBIES diff --git a/rubocop.gemspec b/rubocop.gemspec index 8326a5ffa60..db50e4d7e55 100644 --- a/rubocop.gemspec +++ b/rubocop.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = 'rubocop' s.version = RuboCop::Version::STRING s.platform = Gem::Platform::RUBY - s.required_ruby_version = '>= 2.4.0' + s.required_ruby_version = '>= 2.5.0' s.authors = ['Bozhidar Batsov', 'Jonas Arvidsson', 'Yuji Nakayama'] s.description = <<-DESCRIPTION RuboCop is a Ruby code style checking and code formatting tool. diff --git a/spec/rubocop/cli/autocorrect_spec.rb b/spec/rubocop/cli/autocorrect_spec.rb index cf864d8b8f6..171dca5f3c5 100644 --- a/spec/rubocop/cli/autocorrect_spec.rb +++ b/spec/rubocop/cli/autocorrect_spec.rb @@ -520,7 +520,7 @@ def verify_section it 'corrects Style/Next and Style/SafeNavigation offenses' do create_file('.rubocop.yml', <<~YAML) AllCops: - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 YAML source = <<~'RUBY' until x @@ -1440,7 +1440,7 @@ def self.some_method(foo, bar: 1) RUBY create_file('.rubocop.yml', <<~YAML) AllCops: - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 YAML create_file('example.rb', src) exit_status = cli.run( @@ -1471,7 +1471,7 @@ def self.some_method(foo, bar: 1) RUBY create_file('.rubocop.yml', <<~YAML) AllCops: - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 YAML create_file('example.rb', src) exit_status = cli.run( diff --git a/spec/rubocop/cli/options_spec.rb b/spec/rubocop/cli/options_spec.rb index ed192285c64..16222abf22b 100644 --- a/spec/rubocop/cli/options_spec.rb +++ b/spec/rubocop/cli/options_spec.rb @@ -1879,161 +1879,145 @@ def f describe '--stdin' do it 'causes source code to be read from stdin' do - begin - $stdin = StringIO.new('p $/') - argv = ['--only=Style/SpecialGlobalVars', - '--format=simple', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(1) - expect($stdout.string).to eq(<<~RESULT) - == fake.rb == - C: 1: 3: [Correctable] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. + $stdin = StringIO.new('p $/') + argv = ['--only=Style/SpecialGlobalVars', + '--format=simple', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(1) + expect($stdout.string).to eq(<<~RESULT) + == fake.rb == + C: 1: 3: [Correctable] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. - 1 file inspected, 1 offense detected, 1 offense auto-correctable - RESULT - ensure - $stdin = STDIN - end + 1 file inspected, 1 offense detected, 1 offense auto-correctable + RESULT + ensure + $stdin = STDIN end it 'requires a file path' do - begin - $stdin = StringIO.new('p $/') - argv = ['--only=Style/SpecialGlobalVars', - '--format=simple', - '--stdin'] - expect(cli.run(argv)).to eq(2) - expect($stderr.string).to include('missing argument: --stdin') - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--only=Style/SpecialGlobalVars', + '--format=simple', + '--stdin'] + expect(cli.run(argv)).to eq(2) + expect($stderr.string).to include('missing argument: --stdin') + ensure + $stdin = STDIN end it 'does not accept more than one file path' do - begin - $stdin = StringIO.new('p $/') - argv = ['--only=Style/SpecialGlobalVars', - '--format=simple', - '--stdin', - 'fake1.rb', - 'fake2.rb'] - expect(cli.run(argv)).to eq(2) - expect($stderr.string).to include( - '-s/--stdin requires exactly one path' - ) - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--only=Style/SpecialGlobalVars', + '--format=simple', + '--stdin', + 'fake1.rb', + 'fake2.rb'] + expect(cli.run(argv)).to eq(2) + expect($stderr.string).to include( + '-s/--stdin requires exactly one path' + ) + ensure + $stdin = STDIN end it 'prints corrected code to stdout if --auto-correct-all is used' do - begin - $stdin = StringIO.new('p $/') - argv = ['--auto-correct-all', - '--only=Style/SpecialGlobalVars', - '--format=simple', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(0) - expect($stdout.string).to eq(<<~RESULT.chomp) - == fake.rb == - C: 1: 3: [Corrected] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. - - 1 file inspected, 1 offense detected, 1 offense corrected - ==================== - p $INPUT_RECORD_SEPARATOR - RESULT - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--auto-correct-all', + '--only=Style/SpecialGlobalVars', + '--format=simple', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(0) + expect($stdout.string).to eq(<<~RESULT.chomp) + == fake.rb == + C: 1: 3: [Corrected] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. + + 1 file inspected, 1 offense detected, 1 offense corrected + ==================== + p $INPUT_RECORD_SEPARATOR + RESULT + ensure + $stdin = STDIN end it 'prints offence reports to stderr and corrected code to stdout if --auto-correct-all and --stderr are used' do - begin - $stdin = StringIO.new('p $/') - argv = ['--auto-correct-all', - '--only=Style/SpecialGlobalVars', - '--format=simple', - '--stderr', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(0) - expect($stderr.string).to eq(<<~RESULT) - == fake.rb == - C: 1: 3: [Corrected] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. - - 1 file inspected, 1 offense detected, 1 offense corrected - ==================== - RESULT - expect($stdout.string).to eq(<<~RESULT.chomp) - p $INPUT_RECORD_SEPARATOR - RESULT - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--auto-correct-all', + '--only=Style/SpecialGlobalVars', + '--format=simple', + '--stderr', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(0) + expect($stderr.string).to eq(<<~RESULT) + == fake.rb == + C: 1: 3: [Corrected] Style/SpecialGlobalVars: Prefer $INPUT_RECORD_SEPARATOR or $RS from the stdlib 'English' module (don't forget to require it) over $/. + + 1 file inspected, 1 offense detected, 1 offense corrected + ==================== + RESULT + expect($stdout.string).to eq(<<~RESULT.chomp) + p $INPUT_RECORD_SEPARATOR + RESULT + ensure + $stdin = STDIN end it 'can parse JSON result when specifying `--format=json` and `--stdin` options' do - begin - $stdin = StringIO.new('p $/') - argv = ['--auto-correct-all', - '--only=Style/SpecialGlobalVars', - '--format=json', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(0) - expect { JSON.parse($stdout.string) }.not_to raise_error(JSON::ParserError) - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--auto-correct-all', + '--only=Style/SpecialGlobalVars', + '--format=json', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(0) + expect { JSON.parse($stdout.string) }.not_to raise_error(JSON::ParserError) + ensure + $stdin = STDIN end it 'can parse JSON result when specifying `--format=j` and `--stdin` options' do - begin - $stdin = StringIO.new('p $/') - argv = ['--auto-correct-all', - '--only=Style/SpecialGlobalVars', - '--format=j', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(0) - expect { JSON.parse($stdout.string) }.not_to raise_error(JSON::ParserError) - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + argv = ['--auto-correct-all', + '--only=Style/SpecialGlobalVars', + '--format=j', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(0) + expect { JSON.parse($stdout.string) }.not_to raise_error(JSON::ParserError) + ensure + $stdin = STDIN end it 'detects CR at end of line' do - begin - create_file('example.rb', "puts 'hello world'\r") - # Make Style/EndOfLine give same output regardless of platform. - create_file('.rubocop.yml', <<~YAML) - Layout/EndOfLine: - EnforcedStyle: lf - YAML - File.open('example.rb') do |file| - # We must use a File object to simulate the behavior of - # STDIN, which is an IO object. StringIO won't do in this - # case, as its read() method doesn't handle line endings the - # same way IO#read() does. - $stdin = file - argv = ['--only=Layout/EndOfLine', - '--format=simple', - '--stdin', - 'fake.rb'] - expect(cli.run(argv)).to eq(1) - expect($stdout.string) - .to eq(<<~RESULT) - == fake.rb == - C: 1: 1: Layout/EndOfLine: Carriage return character detected. + create_file('example.rb', "puts 'hello world'\r") + # Make Style/EndOfLine give same output regardless of platform. + create_file('.rubocop.yml', <<~YAML) + Layout/EndOfLine: + EnforcedStyle: lf + YAML + File.open('example.rb') do |file| + # We must use a File object to simulate the behavior of + # STDIN, which is an IO object. StringIO won't do in this + # case, as its read() method doesn't handle line endings the + # same way IO#read() does. + $stdin = file + argv = ['--only=Layout/EndOfLine', + '--format=simple', + '--stdin', + 'fake.rb'] + expect(cli.run(argv)).to eq(1) + expect($stdout.string) + .to eq(<<~RESULT) + == fake.rb == + C: 1: 1: Layout/EndOfLine: Carriage return character detected. - 1 file inspected, 1 offense detected - RESULT - end - ensure - $stdin = STDIN + 1 file inspected, 1 offense detected + RESULT end + ensure + $stdin = STDIN end end diff --git a/spec/rubocop/cli_spec.rb b/spec/rubocop/cli_spec.rb index cd02752cc3a..cc189f283e7 100644 --- a/spec/rubocop/cli_spec.rb +++ b/spec/rubocop/cli_spec.rb @@ -155,7 +155,7 @@ def and_with_args expect($stderr.string).to eq '' expect($stdout.string) .to eq(["#{abs('example.rb')}:3:1: E: Lint/Syntax: unexpected " \ - 'token $end (Using Ruby 2.4 parser; configure using ' \ + 'token $end (Using Ruby 2.5 parser; configure using ' \ '`TargetRubyVersion` parameter, under `AllCops`)', ''].join("\n")) end @@ -929,7 +929,7 @@ def meow_at_4am? create_file('file.rb', 'x=0') # Included by default create_file('example', 'x=0') create_file('regexp', 'x=0') - create_file('vendor/bundle/ruby/2.4.0/gems/backports-3.6.8/.irbrc', 'x=0') + create_file('vendor/bundle/ruby/2.5.0/gems/backports-3.6.8/.irbrc', 'x=0') create_file('.dot1/file.rb', 'x=0') # Hidden but explicitly included create_file('.dot2/file.rb', 'x=0') # Hidden, excluded by default create_file('.dot3/file.rake', 'x=0') # Hidden, not included by wildcard @@ -1646,13 +1646,10 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85} end it 'shows an error if the input file cannot be found' do - begin - cli.run(%w[/tmp/not_a_file]) - rescue SystemExit => e - expect(e.status).to eq(1) - expect(e.message) - .to eq 'rubocop: No such file or directory -- /tmp/not_a_file' - end + cli.run(%w[/tmp/not_a_file]) + rescue SystemExit => e + expect(e.status).to eq(1) + expect(e.message).to eq 'rubocop: No such file or directory -- /tmp/not_a_file' end end @@ -1690,7 +1687,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/ + /Supported versions: 2.5, 2.6, 2.7, 3.0/ ) end end @@ -1713,7 +1710,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85} ) expect($stderr.string.strip).to match( - /Supported versions: 2.4/ + /Supported versions: 2.5/ ) end end @@ -2059,12 +2056,10 @@ def find_suggestions context 'when given --stdin' do it 'does not show the suggestion' do - begin - $stdin = StringIO.new('p $/') - expect { cli.run(['--stdin', 'example.rb']) }.not_to suggest_extensions - ensure - $stdin = STDIN - end + $stdin = StringIO.new('p $/') + expect { cli.run(['--stdin', 'example.rb']) }.not_to suggest_extensions + ensure + $stdin = STDIN end end diff --git a/spec/rubocop/config_obsoletion_spec.rb b/spec/rubocop/config_obsoletion_spec.rb index 53451362e68..7a6d00d4662 100644 --- a/spec/rubocop/config_obsoletion_spec.rb +++ b/spec/rubocop/config_obsoletion_spec.rb @@ -209,12 +209,10 @@ end it 'prints a warning message' do - begin - config_obsoletion.reject_obsolete! - raise 'Expected a RuboCop::ValidationError' - rescue RuboCop::ValidationError => e - expect(expected_message).to eq(e.message) - end + config_obsoletion.reject_obsolete! + raise 'Expected a RuboCop::ValidationError' + rescue RuboCop::ValidationError => e + expect(expected_message).to eq(e.message) end end @@ -247,12 +245,10 @@ end it 'prints a warning message' do - begin - config_obsoletion.reject_obsolete! - raise 'Expected a RuboCop::ValidationError' - rescue RuboCop::ValidationError => e - expect(expected_message).to eq(e.message) - end + config_obsoletion.reject_obsolete! + raise 'Expected a RuboCop::ValidationError' + rescue RuboCop::ValidationError => e + expect(expected_message).to eq(e.message) end end @@ -267,12 +263,10 @@ end it 'prints a warning message' do - begin - config_obsoletion.reject_obsolete! - raise 'Expected a RuboCop::ValidationError' - rescue RuboCop::ValidationError => e - expect(expected_message).to eq(e.message) - end + config_obsoletion.reject_obsolete! + raise 'Expected a RuboCop::ValidationError' + rescue RuboCop::ValidationError => e + expect(expected_message).to eq(e.message) end end @@ -395,12 +389,10 @@ end it 'prints a error message' do - begin - config_obsoletion.reject_obsolete! - raise 'Expected a RuboCop::ValidationError' - rescue RuboCop::ValidationError => e - expect(expected_message).to eq(e.message) - end + config_obsoletion.reject_obsolete! + raise 'Expected a RuboCop::ValidationError' + rescue RuboCop::ValidationError => e + expect(expected_message).to eq(e.message) end end diff --git a/spec/rubocop/cop/lint/suppressed_exception_spec.rb b/spec/rubocop/cop/lint/suppressed_exception_spec.rb index b4360f54a0f..cd5a5c7aac4 100644 --- a/spec/rubocop/cop/lint/suppressed_exception_spec.rb +++ b/spec/rubocop/cop/lint/suppressed_exception_spec.rb @@ -114,27 +114,25 @@ def self.foo end end - context 'Ruby 2.5 or higher', :ruby25 do - context 'when empty rescue for `do` block' do - it 'registers an offense for empty rescue without comment' do - expect_offense(<<~RUBY) - foo do - do_something - rescue - ^^^^^^ Do not suppress exceptions. - end - RUBY - end + context 'when empty rescue for `do` block' do + it 'registers an offense for empty rescue without comment' do + expect_offense(<<~RUBY) + foo do + do_something + rescue + ^^^^^^ Do not suppress exceptions. + end + RUBY + end - it 'registers an offense for empty rescue with comment' do - expect_offense(<<~RUBY) - foo do - rescue - ^^^^^^ Do not suppress exceptions. - # do nothing - end - RUBY - end + it 'registers an offense for empty rescue with comment' do + expect_offense(<<~RUBY) + foo do + rescue + ^^^^^^ Do not suppress exceptions. + # do nothing + end + RUBY end end end @@ -197,26 +195,24 @@ def self.foo end end - context 'Ruby 2.5 or higher', :ruby25 do - context 'when empty rescue for `do` block' do - it 'registers an offense for empty rescue without comment' do - expect_offense(<<~RUBY) - foo do - do_something - rescue - ^^^^^^ Do not suppress exceptions. - end - RUBY - end + context 'when empty rescue for `do` block' do + it 'registers an offense for empty rescue without comment' do + expect_offense(<<~RUBY) + foo do + do_something + rescue + ^^^^^^ Do not suppress exceptions. + end + RUBY + end - it 'does not register an offense for empty rescue with comment' do - expect_no_offenses(<<~RUBY) - foo do - rescue - # do nothing - end - RUBY - end + it 'does not register an offense for empty rescue with comment' do + expect_no_offenses(<<~RUBY) + foo do + rescue + # do nothing + end + RUBY end end diff --git a/spec/rubocop/cop/lint/syntax_spec.rb b/spec/rubocop/cop/lint/syntax_spec.rb index 89e60836c0e..b1d1be18548 100644 --- a/spec/rubocop/cop/lint/syntax_spec.rb +++ b/spec/rubocop/cop/lint/syntax_spec.rb @@ -12,7 +12,7 @@ expect(offenses.size).to eq(1) message = <<~MESSAGE.chomp unexpected token $end - (Using Ruby 2.4 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) + (Using Ruby 2.5 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) MESSAGE offense = offenses.first expect(offense.message).to eq(message) @@ -26,7 +26,7 @@ expect(offenses.size).to eq(1) message = <<~MESSAGE.chomp Lint/Syntax: unexpected token $end - (Using Ruby 2.4 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) + (Using Ruby 2.5 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) MESSAGE offense = offenses.first expect(offense.message).to eq(message) @@ -41,7 +41,7 @@ expect(offenses.size).to eq(1) message = <<~MESSAGE.chomp unexpected token $end - (Using Ruby 2.4 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) + (Using Ruby 2.5 parser; configure using `TargetRubyVersion` parameter, under `AllCops`) MESSAGE offense = offenses.first expect(offense.message).to eq(message) diff --git a/spec/rubocop/cop/style/hash_transform_keys_spec.rb b/spec/rubocop/cop/style/hash_transform_keys_spec.rb index 556bcf7110d..4d81e28c2b4 100644 --- a/spec/rubocop/cop/style/hash_transform_keys_spec.rb +++ b/spec/rubocop/cop/style/hash_transform_keys_spec.rb @@ -1,241 +1,233 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Style::HashTransformKeys, :config do - context 'when using Ruby 2.5 or newer', :ruby25 do - context 'with inline block' do - it 'flags each_with_object when transform_keys could be used' do - expect_offense(<<~RUBY) - x.each_with_object({}) {|(k, v), h| h[foo(k)] = v} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. - RUBY - - expect_correction(<<~RUBY) - x.transform_keys {|k| foo(k)} - RUBY - end - end - - context 'with multiline block' do - it 'flags each_with_object when transform_keys could be used' do - expect_offense(<<~RUBY) - some_hash.each_with_object({}) do |(key, val), memo| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. - memo[key.to_sym] = val - end - RUBY - - expect_correction(<<~RUBY) - some_hash.transform_keys do |key| - key.to_sym - end - RUBY - end - end - - context 'with safe navigation operator' do - it 'flags each_with_object when transform_keys could be used' do - expect_offense(<<~RUBY) - x&.each_with_object({}) {|(k, v), h| h[foo(k)] = v} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. - RUBY - - expect_correction(<<~RUBY) - x&.transform_keys {|k| foo(k)} - 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)} + context 'with inline block' do + it 'flags each_with_object when transform_keys could be used' do + expect_offense(<<~RUBY) + x.each_with_object({}) {|(k, v), h| h[foo(k)] = v} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. RUBY - end - - it 'does not flag each_with_object when key transformation uses value' do - expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[foo(v)] = 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.to_sym] = v} + expect_correction(<<~RUBY) + x.transform_keys {|k| foo(k)} RUBY end + end - it 'does not flag `each_with_object` when its argument is used in the key' do - expect_no_offenses(<<~RUBY) - x.each_with_object({}) { |(k, v), h| h[h[k.to_sym]] = v } + context 'with multiline block' do + it 'flags each_with_object when transform_keys could be used' do + expect_offense(<<~RUBY) + some_hash.each_with_object({}) do |(key, val), memo| + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. + memo[key.to_sym] = val + end RUBY - end - it 'does not flag each_with_object when its receiver is array literal' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].each_with_object({}) {|(k, v), h| h[foo(k)] = v} + expect_correction(<<~RUBY) + some_hash.transform_keys do |key| + key.to_sym + end RUBY end + 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.to_sym] = v } + context 'with safe navigation operator' do + it 'flags each_with_object when transform_keys could be used' do + expect_offense(<<~RUBY) + x&.each_with_object({}) {|(k, v), h| h[foo(k)] = v} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `each_with_object`. 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.to_sym] = v } + expect_correction(<<~RUBY) + x&.transform_keys {|k| foo(k)} RUBY end + 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.to_sym] = v } - RUBY - 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 'flags _.map{...}.to_h when transform_keys could be used' do - expect_offense(<<~RUBY) - x.map {|k, v| [k.to_sym, v]}.to_h - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. - RUBY + it 'does not flag each_with_object when key transformation uses value' do + expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[foo(v)] = v}') + end - expect_correction(<<~RUBY) - x.transform_keys {|k| k.to_sym} - RUBY - 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 'flags _.map{...}.to_h when transform_keys could be used ' \ - 'when line break before `to_h`' do - expect_offense(<<~RUBY) - x.map {|k, v| [k.to_sym, v]}. - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. - to_h - RUBY + 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.to_sym] = v} + RUBY + end - expect_correction(<<~RUBY) - x.transform_keys {|k| k.to_sym} - RUBY - end + it 'does not flag `each_with_object` when its argument is used in the key' do + expect_no_offenses(<<~RUBY) + x.each_with_object({}) { |(k, v), h| h[h[k.to_sym]] = v } + 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 each_with_object when its receiver is array literal' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].each_with_object({}) {|(k, v), h| h[foo(k)] = v} + RUBY + end - it 'flags Hash[_.map{...}] when transform_keys could be used' do - expect_offense(<<~RUBY) - Hash[x.map {|k, v| [k.to_sym, v]}] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `Hash[_.map {...}]`. - RUBY + 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.to_sym] = v } + RUBY + end - expect_correction(<<~RUBY) - x.transform_keys {|k| k.to_sym} - 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.to_sym] = 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 `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.to_sym] = v } + RUBY + end - it 'does not flag key transformation in the absence of to_h' do - expect_no_offenses('x.map {|k, v| [k.to_sym, v]}') - end + it 'flags _.map{...}.to_h when transform_keys could be used' do + expect_offense(<<~RUBY) + x.map {|k, v| [k.to_sym, v]}.to_h + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. + RUBY - it 'does not flag key transformation when receiver is array literal' do - expect_no_offenses(<<~RUBY) - [1, 2, 3].map {|k, v| [k.to_sym, v]}.to_h - RUBY - end + expect_correction(<<~RUBY) + x.transform_keys {|k| k.to_sym} + 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.to_sym, v] }.to_h - RUBY - end + it 'flags _.map{...}.to_h when transform_keys could be used ' \ + 'when line break before `to_h`' do + expect_offense(<<~RUBY) + x.map {|k, v| [k.to_sym, v]}. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. + to_h + RUBY + + expect_correction(<<~RUBY) + x.transform_keys {|k| k.to_sym} + 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.to_sym, v] }.to_h - 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 its receiver is `zip`' do - expect_no_offenses(<<~RUBY) - %i[a b c].zip([1, 2, 3]).map { |k, v| [k.to_sym, v] }.to_h - RUBY - end + it 'flags Hash[_.map{...}] when transform_keys could be used' do + expect_offense(<<~RUBY) + Hash[x.map {|k, v| [k.to_sym, v]}] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `Hash[_.map {...}]`. + RUBY - it 'correctly autocorrects _.map{...}.to_h without block' do - expect_offense(<<~RUBY) - {a: 1, b: 2}.map do |k, v| - ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. - [k.to_s, v] - end.to_h - RUBY + expect_correction(<<~RUBY) + x.transform_keys {|k| k.to_sym} + RUBY + end - expect_correction(<<~RUBY) - {a: 1, b: 2}.transform_keys do |k| - k.to_s - end - 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 'correctly autocorrects _.map{...}.to_h with block' do - expect_offense(<<~RUBY) - {a: 1, b: 2}.map {|k, v| [k.to_s, v]}.to_h {|k, v| [v, k]} - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. - RUBY + it 'does not flag key transformation in the absence of to_h' do + expect_no_offenses('x.map {|k, v| [k.to_sym, v]}') + end - expect_correction(<<~RUBY) - {a: 1, b: 2}.transform_keys {|k| k.to_s}.to_h {|k, v| [v, k]} - RUBY - end + it 'does not flag key transformation when receiver is array literal' do + expect_no_offenses(<<~RUBY) + [1, 2, 3].map {|k, v| [k.to_sym, v]}.to_h + RUBY + end - it 'correctly autocorrects Hash[_.map{...}]' do - expect_offense(<<~RUBY) - Hash[{a: 1, b: 2}.map do |k, v| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `Hash[_.map {...}]`. - [k.to_s, v] - end] - RUBY + 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.to_sym, v] }.to_h + RUBY + end - expect_correction(<<~RUBY) - {a: 1, b: 2}.transform_keys do |k| - k.to_s - end - 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.to_sym, v] }.to_h + 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.to_sym, v] }] - 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.to_sym, v] }.to_h + 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.to_sym, v] }] - RUBY - end + it 'correctly autocorrects _.map{...}.to_h without block' do + expect_offense(<<~RUBY) + {a: 1, b: 2}.map do |k, v| + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. + [k.to_s, v] + end.to_h + RUBY + + expect_correction(<<~RUBY) + {a: 1, b: 2}.transform_keys do |k| + k.to_s + end + 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.to_sym, v] }] - RUBY - end + it 'correctly autocorrects _.map{...}.to_h with block' do + expect_offense(<<~RUBY) + {a: 1, b: 2}.map {|k, v| [k.to_s, v]}.to_h {|k, v| [v, k]} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `map {...}.to_h`. + 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.to_sym, v] }] - RUBY - end + expect_correction(<<~RUBY) + {a: 1, b: 2}.transform_keys {|k| k.to_s}.to_h {|k, v| [v, k]} + RUBY end - context 'below Ruby 2.5', :ruby24 do - it 'does not flag even if transform_keys could be used' do - expect_no_offenses('x.each_with_object({}) {|(k, v), h| h[foo(k)] = v}') - end + it 'correctly autocorrects Hash[_.map{...}]' do + expect_offense(<<~RUBY) + Hash[{a: 1, b: 2}.map do |k, v| + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `transform_keys` over `Hash[_.map {...}]`. + [k.to_s, v] + end] + RUBY + + expect_correction(<<~RUBY) + {a: 1, b: 2}.transform_keys do |k| + k.to_s + end + 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.to_sym, 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.to_sym, 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.to_sym, 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.to_sym, v] }] + RUBY end context 'when using Ruby 2.6 or newer', :ruby26 do diff --git a/spec/rubocop/cop/style/redundant_begin_spec.rb b/spec/rubocop/cop/style/redundant_begin_spec.rb index f85db46c076..b78beabc60d 100644 --- a/spec/rubocop/cop/style/redundant_begin_spec.rb +++ b/spec/rubocop/cop/style/redundant_begin_spec.rb @@ -313,91 +313,75 @@ def method RUBY end - context '< Ruby 2.5', :ruby24 do - it 'accepts a do-end block with a begin-end' do - expect_no_offenses(<<~RUBY) - do_something do - begin - foo - rescue => e - bar - end + it 'registers an offense for a do-end block with redundant begin-end' do + expect_offense(<<~RUBY) + do_something do + begin + ^^^^^ Redundant `begin` block detected. + foo + rescue => e + bar end - RUBY - end - end + end + RUBY - context '>= ruby 2.5', :ruby25 do - it 'registers an offense for a do-end block with redundant begin-end' do - expect_offense(<<~RUBY) - do_something do - begin - ^^^^^ Redundant `begin` block detected. - foo - rescue => e - bar - end - end - RUBY + expect_correction(<<~RUBY) + do_something do + #{trailing_whitespace} + foo + rescue => e + bar + #{trailing_whitespace} + end + RUBY + end - expect_correction(<<~RUBY) - do_something do - #{trailing_whitespace} - foo - rescue => e - bar - #{trailing_whitespace} + it 'accepts a {} block with a begin-end' do + expect_no_offenses(<<~RUBY) + do_something { + begin + foo + rescue => e + bar end - RUBY - end + } + RUBY + end - it 'accepts a {} block with a begin-end' do - expect_no_offenses(<<~RUBY) - do_something { - begin - foo - rescue => e - bar - end - } - RUBY - end - - it 'accepts a block with a begin block after a statement' do - expect_no_offenses(<<~RUBY) - do_something do - something - begin - ala - rescue => e - bala - end + it 'accepts a block with a begin block after a statement' do + expect_no_offenses(<<~RUBY) + do_something do + something + begin + ala + rescue => e + bala end - RUBY - end + end + RUBY + end - it 'accepts a stabby lambda with a begin-end' do - expect_no_offenses(<<~RUBY) - -> do - begin - foo - rescue => e - bar - end + it 'accepts a stabby lambda with a begin-end' do + expect_no_offenses(<<~RUBY) + -> do + begin + foo + rescue => e + bar end - RUBY - end + end + RUBY + end - it 'accepts super with block' do - expect_no_offenses(<<~RUBY) - def a_method - super do |arg| - foo - rescue => e - bar - end + it 'accepts super with block' do + expect_no_offenses(<<~RUBY) + def a_method + super do |arg| + foo + rescue => e + bar end - RUBY - end + end + RUBY end end diff --git a/spec/rubocop/cop/style/slicing_with_range_spec.rb b/spec/rubocop/cop/style/slicing_with_range_spec.rb index 2250eea4273..25c760394a8 100644 --- a/spec/rubocop/cop/style/slicing_with_range_spec.rb +++ b/spec/rubocop/cop/style/slicing_with_range_spec.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Style::SlicingWithRange, :config do - context '<= Ruby 2.5', :ruby25 do - it 'reports no offense for array slicing with -1' do - expect_no_offenses(<<~RUBY) - ary[1..-1] - RUBY - end + it 'reports no offense for array slicing with -1' do + expect_no_offenses(<<~RUBY) + ary[1..-1] + RUBY end context '>= Ruby 2.6', :ruby26 do diff --git a/spec/rubocop/cop/style/symbol_array_spec.rb b/spec/rubocop/cop/style/symbol_array_spec.rb index f1e1566baa9..f75c2283e60 100644 --- a/spec/rubocop/cop/style/symbol_array_spec.rb +++ b/spec/rubocop/cop/style/symbol_array_spec.rb @@ -105,11 +105,6 @@ expect_no_offenses('[:one, :two, :"space here"]') end - # Bug: https://github.com/rubocop/rubocop/issues/4481 - it 'does not register an offense in an ambiguous block context' do - expect_no_offenses('foo [:bar, :baz] { qux }') - end - it 'registers an offense in a non-ambiguous block context' do expect_offense(<<~RUBY) foo([:bar, :baz]) { qux } diff --git a/spec/rubocop/cop/style/word_array_spec.rb b/spec/rubocop/cop/style/word_array_spec.rb index a6a45fe5df2..99202266baf 100644 --- a/spec/rubocop/cop/style/word_array_spec.rb +++ b/spec/rubocop/cop/style/word_array_spec.rb @@ -150,11 +150,6 @@ expect_no_offenses("['-', '----']") end - # Bug: https://github.com/rubocop/rubocop/issues/4481 - it 'does not register an offense in an ambiguous block context' do - expect_no_offenses('foo ["bar", "baz"] { qux }') - end - it 'registers an offense in a non-ambiguous block context' do expect_offense(<<~RUBY) foo(['bar', 'baz']) { qux } diff --git a/spec/rubocop/cop/team_spec.rb b/spec/rubocop/cop/team_spec.rb index f4a0a4b9f3c..fe44ba60a93 100644 --- a/spec/rubocop/cop/team_spec.rb +++ b/spec/rubocop/cop/team_spec.rb @@ -259,7 +259,7 @@ def self.support_multiple_source? it 'returns cop instances' do expect(cops.empty?).to be(false) - expect(cops.all? { |c| c.is_a?(RuboCop::Cop::Base) }).to be_truthy + expect(cops.all?(RuboCop::Cop::Base)).to be_truthy end context 'when only some cop classes are passed to .new' do diff --git a/spec/rubocop/formatter/formatter_set_spec.rb b/spec/rubocop/formatter/formatter_set_spec.rb index 61edc3ca42f..6b5cb905071 100644 --- a/spec/rubocop/formatter/formatter_set_spec.rb +++ b/spec/rubocop/formatter/formatter_set_spec.rb @@ -82,12 +82,10 @@ end around do |example| - begin - $stdout = StringIO.new - example.run - ensure - $stdout = STDOUT - end + $stdout = StringIO.new + example.run + ensure + $stdout = STDOUT end it 'closes all output files' do diff --git a/spec/rubocop/target_ruby_spec.rb b/spec/rubocop/target_ruby_spec.rb index e8c8109a7de..73b36d5ca3b 100644 --- a/spec/rubocop/target_ruby_spec.rb +++ b/spec/rubocop/target_ruby_spec.rb @@ -12,7 +12,7 @@ let(:loaded_path) { 'example/.rubocop.yml' } context 'when TargetRubyVersion is set' do - let(:ruby_version) { 2.4 } + let(:ruby_version) { 2.5 } let(:hash) do { @@ -46,8 +46,8 @@ end context 'when .ruby-version contains an MRI version' do - let(:ruby_version) { '2.3.8' } - let(:ruby_version_to_f) { 2.3 } + let(:ruby_version) { '2.4.10' } + let(:ruby_version_to_f) { 2.4 } it 'reads it to determine the target ruby version' do expect(target_ruby.version).to eq ruby_version_to_f @@ -64,8 +64,8 @@ end context 'when .ruby-version contains a version prefixed by "ruby-"' do - let(:ruby_version) { 'ruby-2.3.0' } - let(:ruby_version_to_f) { 2.3 } + let(:ruby_version) { 'ruby-2.4.0' } + let(:ruby_version_to_f) { 2.4 } it 'correctly determines the target ruby version' do expect(target_ruby.version).to eq ruby_version_to_f @@ -299,13 +299,13 @@ <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '>= 2.6.1' + s.required_ruby_version = '>= 2.7.2' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.6 + expect(target_ruby.version).to eq 2.7 end it 'sets target_ruby from exclusive range' do @@ -313,13 +313,13 @@ <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '> 2.4.1' + s.required_ruby_version = '> 2.5.8' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.4 + expect(target_ruby.version).to eq 2.5 end it 'sets target_ruby from approximate version' do @@ -327,13 +327,13 @@ <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '~> 2.5.0' + s.required_ruby_version = '~> 2.6.0' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.5 + expect(target_ruby.version).to eq 2.6 end end @@ -393,13 +393,13 @@ <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = ['<=2.7.4', '>2.4.5', '~>2.5.1'] + s.required_ruby_version = ['<=3.0.0', '>2.5.8', '~>2.6.1'] s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.5 + expect(target_ruby.version).to eq 2.6 end end @@ -428,11 +428,11 @@ context 'when .ruby-version is in a parent directory' do before do dir = configuration.base_dir_for_path_parameters - create_file(File.join(dir, '..', '.ruby-version'), '2.4.1') + create_file(File.join(dir, '..', '.ruby-version'), '2.5.8') end it 'reads it to determine the target ruby version' do - expect(target_ruby.version).to eq 2.4 + expect(target_ruby.version).to eq 2.5 end end diff --git a/spec/rubocop/version_spec.rb b/spec/rubocop/version_spec.rb index ceccda35cec..8e7b3acf5cf 100644 --- a/spec/rubocop/version_spec.rb +++ b/spec/rubocop/version_spec.rb @@ -17,7 +17,7 @@ before do create_file('.rubocop.yml', <<~YAML) AllCops: - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 YAML end