diff --git a/.github/workflows/edge.yml b/.github/workflows/edge.yml index 5f2a5f5f4..fe3e14393 100644 --- a/.github/workflows/edge.yml +++ b/.github/workflows/edge.yml @@ -6,11 +6,9 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4', ruby-head, truffleruby-head, jruby-head] + ruby: ['3.0', '3.1', '3.2', '3.3', '3.4', ruby-head, truffleruby-head, jruby-head] gemfile: [rails_edge, rack_edge] exclude: - - ruby: '2.7' - gemfile: rails_edge - ruby: '3.0' gemfile: rails_edge runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b1914942..8977442e0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,19 +23,10 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4'] - gemfile: [Gemfile, gemfiles/rack_2_0.gemfile, gemfiles/rack_3_0.gemfile, gemfiles/rack_3_1.gemfile, gemfiles/rails_6_1.gemfile, gemfiles/rails_7_0.gemfile, gemfiles/rails_7_1.gemfile, gemfiles/rails_7_2.gemfile, gemfiles/rails_8_0.gemfile] + ruby: ['3.0', '3.1', '3.2', '3.3', '3.4'] + gemfile: [Gemfile, gemfiles/rack_2_0.gemfile, gemfiles/rack_3_0.gemfile, gemfiles/rack_3_1.gemfile, gemfiles/rails_7_0.gemfile, gemfiles/rails_7_1.gemfile, gemfiles/rails_7_2.gemfile, gemfiles/rails_8_0.gemfile] specs: ['spec --exclude-pattern=spec/integration/**/*_spec.rb'] include: - - ruby: '2.7' - gemfile: gemfiles/multi_json.gemfile - specs: 'spec/integration/multi_json' - - ruby: '2.7' - gemfile: gemfiles/multi_xml.gemfile - specs: 'spec/integration/multi_xml' - - ruby: '2.7' - gemfile: gemfiles/rack_3_0.gemfile - specs: 'spec/integration/rack_3_0' - ruby: '3.3' gemfile: gemfiles/grape_entity.gemfile specs: 'spec/integration/grape_entity' @@ -45,9 +36,6 @@ jobs: - ruby: '3.3' gemfile: gemfiles/dry_validation.gemfile specs: 'spec/integration/dry_validation' - - ruby: '3.3' - gemfile: gemfiles/rails_6_1.gemfile - specs: 'spec/integration/rails' - ruby: '3.3' gemfile: gemfiles/rails_7_0.gemfile specs: 'spec/integration/rails' @@ -61,12 +49,8 @@ jobs: gemfile: gemfiles/rails_8_0.gemfile specs: 'spec/integration/rails' exclude: - - ruby: '2.7' - gemfile: gemfiles/rails_7_2.gemfile - ruby: '3.0' gemfile: gemfiles/rails_7_2.gemfile - - ruby: '2.7' - gemfile: gemfiles/rails_8_0.gemfile - ruby: '3.0' gemfile: gemfiles/rails_8_0.gemfile - ruby: '3.1' diff --git a/.rubocop.yml b/.rubocop.yml index 78c6b010d..a43dfa720 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,16 +1,14 @@ AllCops: NewCops: enable - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.0 SuggestExtensions: false Exclude: - vendor/**/* - bin/**/* -require: - - rubocop-rspec - plugins: - rubocop-performance + - rubocop-rspec inherit_from: .rubocop_todo.yml diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f93343852..53d6756ab 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-02-23 19:41:28 UTC using RuboCop version 1.71.2. +# on 2025-06-18 20:27:19 UTC using RuboCop version 1.76.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -15,7 +15,7 @@ Metrics/MethodLength: # Offense count: 18 # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. # SupportedStyles: snake_case, normalcase, non_integer -# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 +# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 Naming/VariableNumber: Exclude: - 'spec/grape/dsl/settings_spec.rb' @@ -39,7 +39,7 @@ RSpec/ExampleWording: - 'spec/grape/integration/global_namespace_function_spec.rb' - 'spec/grape/validations_spec.rb' -# Offense count: 7 +# Offense count: 6 # This cop supports safe autocorrection (--autocorrect). RSpec/ExpectActual: Exclude: @@ -60,7 +60,7 @@ RSpec/IndexedLet: - 'spec/grape/presenters/presenter_spec.rb' - 'spec/shared/versioning_examples.rb' -# Offense count: 39 +# Offense count: 40 # Configuration parameters: AssignmentOnly. RSpec/InstanceVariable: Exclude: @@ -75,7 +75,7 @@ RSpec/MessageChain: Exclude: - 'spec/grape/middleware/formatter_spec.rb' -# Offense count: 12 +# Offense count: 10 RSpec/MissingExampleGroupArgument: Exclude: - 'spec/grape/middleware/exception_spec.rb' @@ -149,12 +149,11 @@ Style/CombinableLoops: Exclude: - 'spec/grape/endpoint_spec.rb' -# Offense count: 12 +# Offense count: 11 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - - 'lib/grape/api.rb' - 'lib/grape/dsl/inside_route.rb' - 'lib/grape/dsl/parameters.rb' - 'lib/grape/endpoint.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fd58cda8..a5cd07963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ #### Features +* [#2572](https://github.com/ruby-grape/grape/pull/2572): Drop support ruby 2.7 and active_support 6.1 - [@ericproulx](https://github.com/ericproulx). * Your contribution here. #### Fixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18500e912..1295d21c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ Here are some examples: - running rspec on a specific file `docker-compose run --rm --build grape rspec spec/:file_path` - running task `docker-compose run --rm --build grape rake ` - running rubocop `docker-compose run --rm --build grape rubocop` -- running all specs on a specific ruby version (e.g 2.7.7) `RUBY_VERSION=2.7.7 docker-compose run --rm --build grape rspec` +- running all specs on a specific ruby version (e.g 3.0) `RUBY_VERSION=3.0 docker-compose run --rm --build grape rspec` - running specs on a specific gemfile (e.g rails_7_0.gemfile) `docker-compose run -e GEMFILE=rails_7_0 --rm --build grape rspec` #### Bundle Install and Test @@ -60,14 +60,6 @@ bundle install bundle exec rake ``` -Run tests against all supported versions of Rails. - -``` -gem install appraisal -appraisal install -appraisal rake spec -``` - #### Write Tests Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/grape](spec/grape). diff --git a/Gemfile b/Gemfile index 6b3afac54..e7bdb6c79 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,5 @@ # frozen_string_literal: true -# when changing this file, run appraisal install ; rubocop -a gemfiles/*.gemfile - source('https://rubygems.org') gemspec @@ -10,9 +8,9 @@ group :development, :test do gem 'builder', require: false gem 'bundler' gem 'rake' - gem 'rubocop', '1.75.8', require: false + gem 'rubocop', '1.76.2', require: false gem 'rubocop-performance', '1.25.0', require: false - gem 'rubocop-rspec', '3.4.0', require: false + gem 'rubocop-rspec', '3.6.0', require: false end group :development do diff --git a/README.md b/README.md index 91b077531..b01cd6dac 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support ## Installation -Ruby 2.7 or newer is required. +Ruby 3.0 or newer is required. Grape is available as a gem, to install it run: diff --git a/SECURITY.md b/SECURITY.md index 6a8cc7d6a..496742efb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -Version 1.2.0 or newer is currently supported. +Version 2.2 or newer is currently supported. ## Reporting a Vulnerability diff --git a/gemfiles/rails_6_1.gemfile b/gemfiles/rails_6_1.gemfile deleted file mode 100644 index edb73448c..000000000 --- a/gemfiles/rails_6_1.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -eval_gemfile '../Gemfile' - -gem 'mutex_m' -gem 'rails', '~> 6.1' -gem 'tzinfo-data', require: false diff --git a/grape.gemspec b/grape.gemspec index 5aca62670..942597d50 100644 --- a/grape.gemspec +++ b/grape.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| 'rubygems_mfa_required' => 'true' } - s.add_dependency 'activesupport', '>= 6.1' + s.add_dependency 'activesupport', '>= 7.0' s.add_dependency 'dry-types', '>= 1.1' s.add_dependency 'mustermann-grape', '~> 1.1.0' s.add_dependency 'rack', '>= 2' @@ -29,5 +29,5 @@ Gem::Specification.new do |s| s.files = Dir['lib/**/*', 'CHANGELOG.md', 'CONTRIBUTING.md', 'README.md', 'grape.png', 'UPGRADING.md', 'LICENSE', 'grape.gemspec'] s.require_paths = ['lib'] - s.required_ruby_version = '>= 2.7.0' + s.required_ruby_version = '>= 3.0' end diff --git a/lib/grape.rb b/lib/grape.rb index 4dfffc257..41859b8d8 100644 --- a/lib/grape.rb +++ b/lib/grape.rb @@ -5,7 +5,7 @@ require 'active_support/concern' require 'active_support/configurable' require 'active_support/version' -require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6 +require 'active_support/isolated_execution_state' require 'active_support/core_ext/array/conversions' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/array/wrap' diff --git a/lib/grape/dsl/request_response.rb b/lib/grape/dsl/request_response.rb index 7f0a0d27d..75bf8d703 100644 --- a/lib/grape/dsl/request_response.rb +++ b/lib/grape/dsl/request_response.rb @@ -11,7 +11,7 @@ module ClassMethods # Specify the default format for the API's serializers. # May be `:json` or `:txt` (default). def default_format(new_format = nil) - namespace_inheritable(:default_format, new_format.nil? ? nil : new_format.to_sym) + namespace_inheritable(:default_format, new_format&.to_sym) end # Specify the format for the API's serializers. diff --git a/lib/grape/middleware/formatter.rb b/lib/grape/middleware/formatter.rb index 1c6907a1b..f69ac3563 100644 --- a/lib/grape/middleware/formatter.rb +++ b/lib/grape/middleware/formatter.rb @@ -132,7 +132,7 @@ def format_from_extension dot_pos = request_path.rindex('.') return unless dot_pos - extension = request_path[dot_pos + 1..] + extension = request_path[(dot_pos + 1)..] extension if content_type_for(extension) end diff --git a/lib/grape/middleware/stack.rb b/lib/grape/middleware/stack.rb index 1ba65080e..cfcb034e6 100644 --- a/lib/grape/middleware/stack.rb +++ b/lib/grape/middleware/stack.rb @@ -59,9 +59,9 @@ def insert(index, klass, *args, &block) alias insert_before insert - def insert_after(index, *args, &block) + def insert_after(index, ...) index = assert_index(index, :after) - insert(index + 1, *args, &block) + insert(index + 1, ...) end def use(klass, *args, &block) diff --git a/lib/grape/middleware/versioner/base.rb b/lib/grape/middleware/versioner/base.rb index b12026906..8662d2a88 100644 --- a/lib/grape/middleware/versioner/base.rb +++ b/lib/grape/middleware/versioner/base.rb @@ -5,7 +5,7 @@ module Middleware module Versioner class Base < Grape::Middleware::Base DEFAULT_OPTIONS = { - pattern: /.*/i.freeze, + pattern: /.*/i, version_options: { strict: false, cascade: true, diff --git a/lib/grape/middleware/versioner/path.rb b/lib/grape/middleware/versioner/path.rb index dd4379767..7146057f8 100644 --- a/lib/grape/middleware/versioner/path.rb +++ b/lib/grape/middleware/versioner/path.rb @@ -28,7 +28,7 @@ def before slash_position = path_info.index('/', 1) # omit the first one return unless slash_position - potential_version = path_info[1..slash_position - 1] + potential_version = path_info[1..(slash_position - 1)] return unless potential_version.match?(pattern) version_not_found! unless potential_version_match?(potential_version) diff --git a/lib/grape/router.rb b/lib/grape/router.rb index 6a9e3f5df..7d91de7a2 100644 --- a/lib/grape/router.rb +++ b/lib/grape/router.rb @@ -19,7 +19,7 @@ def self.normalize_path(path) # Slow path encoding = path.encoding - path = +"/#{path}" + path = "/#{path}" path.squeeze!('/') unless path == '/' diff --git a/lib/grape/util/media_type.rb b/lib/grape/util/media_type.rb index 1812fafa6..ea4c2c3d9 100644 --- a/lib/grape/util/media_type.rb +++ b/lib/grape/util/media_type.rb @@ -7,7 +7,7 @@ class MediaType # based on the HTTP Accept header with the pattern: # application/vnd.:vendor-:version+:format - VENDOR_VERSION_HEADER_REGEX = /\Avnd\.(?[a-z0-9.\-_!^]+?)(?:-(?[a-z0-9*.]+))?(?:\+(?[a-z0-9*\-.]+))?\z/.freeze + VENDOR_VERSION_HEADER_REGEX = /\Avnd\.(?[a-z0-9.\-_!^]+?)(?:-(?[a-z0-9*.]+))?(?:\+(?[a-z0-9*\-.]+))?\z/ def initialize(type:, subtype:) @type = type diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 2720ccc89..7467e7f1b 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -1090,7 +1090,7 @@ def to_txt it 'adds a before filter to current and child namespaces only' do subject.get '/' do - "root - #{instance_variable_defined?(:@foo) ? @foo : nil}" + "root - #{@foo if instance_variable_defined?(:@foo)}" end subject.namespace :blah do before { @foo = 'foo' } @@ -1676,13 +1676,13 @@ def call(env) it 'has access to helper methods' do subject.helpers do - def authorize(user, password) + def authorize?(user, password) user == 'allow' && password == 'whatever' end end subject.http_basic do |u, p| - authorize(u, p) + authorize?(u, p) end subject.get(:hello) { 'Hello, world.' } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4a8e2f1b0..358f002b1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,15 +8,13 @@ Grape.deprecator.behavior = :raise %w[config support].each do |dir| - Dir["#{File.dirname(__FILE__)}/#{dir}/**/*.rb"].sort.each do |file| + Dir["#{File.dirname(__FILE__)}/#{dir}/**/*.rb"].each do |file| require file end end Grape.config.lint = true # lint all apis by default Grape::Util::Registry.include(Deregister) -# issue with ruby 2.7 with ^. We need to extend it again -Grape::Validations.extend(Grape::Util::Registry) if Gem::Version.new(RUBY_VERSION).release < Gem::Version.new('3.0') # The default value for this setting is true in a standard Rails app, # so it should be set to true here as well to reflect that. diff --git a/spec/support/chunked_response.rb b/spec/support/chunked_response.rb index 4c66e9384..e516e3416 100644 --- a/spec/support/chunked_response.rb +++ b/spec/support/chunked_response.rb @@ -5,7 +5,7 @@ class ChunkedResponse class Body TERM = "\r\n" - TAIL = "0#{TERM}" + TAIL = "0#{TERM}".freeze # Store the response body to be chunked. def initialize(body) diff --git a/spec/support/deprecated_warning_handlers.rb b/spec/support/deprecated_warning_handlers.rb index 040410fb1..16d55bef7 100644 --- a/spec/support/deprecated_warning_handlers.rb +++ b/spec/support/deprecated_warning_handlers.rb @@ -5,7 +5,7 @@ module DeprecatedWarningHandler class DeprecationWarning < StandardError; end - DEPRECATION_REGEX = /is deprecated/.freeze + DEPRECATION_REGEX = /is deprecated/ def warn(message) return super unless message.match?(DEPRECATION_REGEX)