diff --git a/.github/workflows/edge.yml b/.github/workflows/edge.yml index 789184085..d02615971 100644 --- a/.github/workflows/edge.yml +++ b/.github/workflows/edge.yml @@ -6,7 +6,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.1', '3.2', '3.3', '3.4', ruby-head, truffleruby-head, jruby-head] + ruby: ['3.1', '3.2', '3.3', '3.4', '4.0', ruby-head, truffleruby-head, jruby-head] gemfile: [rails_edge, rack_edge] exclude: - ruby: '3.1' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a6074c37..2cf9f2d84 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,28 +23,34 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['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/rack_3_2.gemfile, gemfiles/rails_7_1.gemfile, gemfiles/rails_7_2.gemfile, gemfiles/rails_8_0.gemfile, gemfiles/rails_8_1.gemfile] - specs: ['spec --exclude-pattern=spec/integration/**/*_spec.rb'] + ruby: ['3.1', '3.2', '3.3', '3.4', '4.0'] + gemfile: + - Gemfile + - gemfiles/rack_2_2.gemfile + - gemfiles/rack_3_0.gemfile + - gemfiles/rack_3_1.gemfile + - gemfiles/rack_3_2.gemfile + - gemfiles/rails_7_1.gemfile + - gemfiles/rails_7_2.gemfile + - gemfiles/rails_8_0.gemfile + - gemfiles/rails_8_1.gemfile + specs: ['spec --exclude-pattern=spec/integration/{grape_entity,hashie,dry_validation,multi_*}/*_spec.rb'] include: - - ruby: '3.3' + - ruby: '4.0' gemfile: gemfiles/grape_entity.gemfile specs: 'spec/integration/grape_entity' - - ruby: '3.3' + - ruby: '4.0' gemfile: gemfiles/hashie.gemfile specs: 'spec/integration/hashie' - - ruby: '3.3' + - ruby: '4.0' gemfile: gemfiles/dry_validation.gemfile specs: 'spec/integration/dry_validation' - - ruby: '3.3' - gemfile: gemfiles/rails_7_1.gemfile - specs: 'spec/integration/rails' - - ruby: '3.3' - gemfile: gemfiles/rails_7_2.gemfile - specs: 'spec/integration/rails' - - ruby: '3.3' - gemfile: gemfiles/rails_8_0.gemfile - specs: 'spec/integration/rails' + - ruby: '4.0' + gemfile: gemfiles/multi_json.gemfile + specs: 'spec/integration/multi_json' + - ruby: '4.0' + gemfile: gemfiles/multi_xml.gemfile + specs: 'spec/integration/multi_xml' exclude: - ruby: '3.1' gemfile: gemfiles/rails_8_0.gemfile diff --git a/docker-compose.yml b/docker-compose.yml index 5afa9f0ec..842ea3719 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: context: . dockerfile: docker/Dockerfile args: - - RUBY_VERSION=${RUBY_VERSION:-3} + - RUBY_VERSION=${RUBY_VERSION:-4.0} stdin_open: true tty: true volumes: diff --git a/docker/Dockerfile b/docker/Dockerfile index 5cca3aa5b..9ed90e57a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,15 +1,17 @@ -ARG RUBY_VERSION=3 -FROM ruby:${RUBY_VERSION}-alpine +ARG RUBY_VERSION=4 +FROM ruby:${RUBY_VERSION}-slim ENV BUNDLE_PATH /usr/local/bundle/gems ENV LIB_PATH /var/grape -ENV RUBYOPT --enable-frozen-string-literal --yjit -ENV LD_PRELOAD libjemalloc.so.2 -ENV MALLOC_CONF dirty_decay_ms:1000,narenas:2,background_thread:true -RUN apk add --update --no-cache make gcc git libc-dev yaml-dev gcompat jemalloc && \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential curl git pkg-config libyaml-dev libjemalloc2 && \ gem update --system && gem install bundler +ENV LD_PRELOAD libjemalloc.so.2 +ENV MALLOC_CONF dirty_decay_ms:1000,narenas:2,background_thread:true +ENV RUBYOPT --enable-frozen-string-literal --yjit + WORKDIR $LIB_PATH COPY /docker/entrypoint.sh /usr/local/bin/docker-entrypoint.sh diff --git a/gemfiles/rack_2_0.gemfile b/gemfiles/rack_2_2.gemfile similarity index 71% rename from gemfiles/rack_2_0.gemfile rename to gemfiles/rack_2_2.gemfile index f43035ba6..ce497fecf 100644 --- a/gemfiles/rack_2_0.gemfile +++ b/gemfiles/rack_2_2.gemfile @@ -2,4 +2,4 @@ eval_gemfile '../Gemfile' -gem 'rack', '~> 2.0' +gem 'rack', '~> 2.2.0' diff --git a/gemfiles/rack_3_1.gemfile b/gemfiles/rack_3_1.gemfile index c57807e9f..ba2b3eeca 100644 --- a/gemfiles/rack_3_1.gemfile +++ b/gemfiles/rack_3_1.gemfile @@ -2,4 +2,4 @@ eval_gemfile '../Gemfile' -gem 'rack', '~> 3.1' +gem 'rack', '~> 3.1.0' diff --git a/gemfiles/rack_3_2.gemfile b/gemfiles/rack_3_2.gemfile index 37834aaa6..bf13a72ab 100644 --- a/gemfiles/rack_3_2.gemfile +++ b/gemfiles/rack_3_2.gemfile @@ -2,4 +2,4 @@ eval_gemfile '../Gemfile' -gem 'rack', '~> 3.2' +gem 'rack', '~> 3.2.0' diff --git a/gemfiles/rails_8_0.gemfile b/gemfiles/rails_8_0.gemfile index 715b61502..2b78cf133 100644 --- a/gemfiles/rails_8_0.gemfile +++ b/gemfiles/rails_8_0.gemfile @@ -2,5 +2,5 @@ eval_gemfile '../Gemfile' -gem 'rails', '~> 8.0' +gem 'rails', '~> 8.0.0' gem 'tzinfo-data', require: false diff --git a/gemfiles/rails_8_1.gemfile b/gemfiles/rails_8_1.gemfile index dbea0b803..8b1fe4d6d 100644 --- a/gemfiles/rails_8_1.gemfile +++ b/gemfiles/rails_8_1.gemfile @@ -2,5 +2,5 @@ eval_gemfile '../Gemfile' -gem 'rails', '~> 8.1' +gem 'rails', '~> 8.1.0' gem 'tzinfo-data', require: false diff --git a/lib/grape.rb b/lib/grape.rb index ac1f9e8af..b36e5c40b 100644 --- a/lib/grape.rb +++ b/lib/grape.rb @@ -71,5 +71,5 @@ def self.deprecator # https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html # adding Grape.deprecator to Rails App if any -require 'grape/railtie' if defined?(Rails::Railtie) && ActiveSupport.gem_version >= Gem::Version.new('7.1') +require 'grape/railtie' if defined?(Rails::Railtie) loader.eager_load diff --git a/lib/grape/dsl/declared.rb b/lib/grape/dsl/declared.rb index 29f59af5c..021e8aaa1 100644 --- a/lib/grape/dsl/declared.rb +++ b/lib/grape/dsl/declared.rb @@ -105,7 +105,7 @@ def handle_passed_param(params_nested_path, has_passed_children: false, &_block) {} elsif type == 'Array' || (type&.start_with?('[') && !type.include?(',')) [] - elsif type == 'Set' || type&.start_with?('#', []]).to include(body['empty_set']) - expect(['#', []]).to include(body['empty_typed_set']) - expect(['#', []]).to include(body['nested']['empty_set']) - expect(['#', []]).to include(body['nested']['empty_typed_set']) + expect(body['empty_set']).to eq(json_empty_set) + expect(body['empty_typed_set']).to eq(json_empty_set) + expect(body['nested']['empty_set']).to eq(json_empty_set) + expect(body['nested']['empty_typed_set']).to eq(json_empty_set) end it 'sets objects with type=Array to be an array' do diff --git a/spec/grape/validations/validators/coerce_validator_spec.rb b/spec/grape/validations/validators/coerce_validator_spec.rb index decca5870..126154a79 100644 --- a/spec/grape/validations/validators/coerce_validator_spec.rb +++ b/spec/grape/validations/validators/coerce_validator_spec.rb @@ -1119,7 +1119,7 @@ def self.parse(_val) get '/', d: %w[1 two] expect(last_response).to be_successful - expect(last_response.body).to eq('#') + expect(last_response.body).to eq([1, 'two'].to_set.to_s) end end diff --git a/spec/integration/hashie/hashie_spec.rb b/spec/integration/hashie/hashie_spec.rb index b617aa0e9..96d3388f9 100644 --- a/spec/integration/hashie/hashie_spec.rb +++ b/spec/integration/hashie/hashie_spec.rb @@ -240,7 +240,8 @@ get '/', d: %w[1 two] expect(last_response).to be_successful - expect(last_response.body).to eq('#') + json_set = JSON.parse([1, 'two'].to_set.to_json) + expect(last_response.body).to eq(json_set) end end end diff --git a/spec/integration/rack_3_0/headers_spec.rb b/spec/integration/rack_3_0/headers_spec.rb deleted file mode 100644 index 735807c7e..000000000 --- a/spec/integration/rack_3_0/headers_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -# frozen_string_literal: true - -describe Grape::API do - subject { last_response.headers } - - describe 'returned headers should all be in lowercase' do - context 'when setting an header in an API' do - let(:app) do - Class.new(described_class) do - get do - header['GRAPE'] = '1' - return_no_content - end - end - end - - before { get '/' } - - it { is_expected.to include('grape' => '1') } - end - - context 'when error!' do - let(:app) do - Class.new(described_class) do - rescue_from ArgumentError do - error!('error!', 500, { 'GRAPE' => '1' }) - end - - get { raise ArgumentError } - end - end - - before { get '/' } - - it { is_expected.to include('grape' => '1') } - end - - context 'when redirect' do - let(:app) do - Class.new(described_class) do - get do - redirect 'https://www.ruby-grape.org/' - end - end - end - - before { get '/' } - - it { is_expected.to include('location' => 'https://www.ruby-grape.org/') } - end - - context 'when options' do - let(:app) do - Class.new(described_class) do - get { return_no_content } - end - end - - before { options '/' } - - it { is_expected.to include('allow' => 'OPTIONS, GET, HEAD') } - end - - context 'when cascade' do - let(:app) do - Class.new(described_class) do - version 'v0', using: :path, cascade: true - get { return_no_content } - end - end - - before { get '/v1' } - - it { is_expected.to include('x-cascade' => 'pass') } - end - end -end diff --git a/spec/integration/rack_3_0/version_spec.rb b/spec/integration/rack_3_0/version_spec.rb deleted file mode 100644 index 1352ee6a5..000000000 --- a/spec/integration/rack_3_0/version_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -describe Rack do - it { expect(Gem::Version.new(described_class.release).segments.first).to eq 3 } -end diff --git a/spec/integration/rails/railtie_spec.rb b/spec/integration/rails/railtie_spec.rb index 7583fc29c..6b40a9f50 100644 --- a/spec/integration/rails/railtie_spec.rb +++ b/spec/integration/rails/railtie_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -if defined?(Rails) && ActiveSupport.gem_version >= Gem::Version.new('7.1') +if defined?(Rails) describe Grape::Railtie do describe '.railtie' do subject { test_app.deprecators[:grape] }