diff --git a/.github/workflows/edge.yml b/.github/workflows/edge.yml index b5c940278..789184085 100644 --- a/.github/workflows/edge.yml +++ b/.github/workflows/edge.yml @@ -6,11 +6,9 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.0', '3.1', '3.2', '3.3', '3.4', ruby-head, truffleruby-head, jruby-head] + ruby: ['3.1', '3.2', '3.3', '3.4', ruby-head, truffleruby-head, jruby-head] gemfile: [rails_edge, rack_edge] exclude: - - ruby: '3.0' - gemfile: rails_edge - ruby: '3.1' gemfile: rails_edge runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5215ca20..2a6074c37 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,8 +23,8 @@ jobs: strategy: fail-fast: false matrix: - 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/rack_3_2.gemfile, gemfiles/rails_7_0.gemfile, gemfiles/rails_7_1.gemfile, gemfiles/rails_7_2.gemfile, gemfiles/rails_8_0.gemfile, gemfiles/rails_8_1.gemfile] + 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'] include: - ruby: '3.3' @@ -36,9 +36,6 @@ jobs: - ruby: '3.3' gemfile: gemfiles/dry_validation.gemfile specs: 'spec/integration/dry_validation' - - ruby: '3.3' - gemfile: gemfiles/rails_7_0.gemfile - specs: 'spec/integration/rails' - ruby: '3.3' gemfile: gemfiles/rails_7_1.gemfile specs: 'spec/integration/rails' @@ -49,12 +46,6 @@ jobs: gemfile: gemfiles/rails_8_0.gemfile specs: 'spec/integration/rails' exclude: - - ruby: '3.0' - gemfile: gemfiles/rails_7_2.gemfile - - ruby: '3.0' - gemfile: gemfiles/rails_8_0.gemfile - - ruby: '3.0' - gemfile: gemfiles/rails_8_1.gemfile - ruby: '3.1' gemfile: gemfiles/rails_8_0.gemfile - ruby: '3.1' diff --git a/.rubocop.yml b/.rubocop.yml index 144f1cbca..4ec2046a7 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,6 @@ AllCops: NewCops: enable - TargetRubyVersion: 3.0 + TargetRubyVersion: 3.1 SuggestExtensions: false Exclude: - vendor/**/* diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index be6b3e5f1..5b7a0538c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-11-15 17:39:14 UTC using RuboCop version 1.81.7. +# on 2025-12-20 20:56:19 UTC using RuboCop version 1.81.7. # 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 @@ -145,12 +145,11 @@ Style/CombinableLoops: Exclude: - 'spec/grape/endpoint_spec.rb' -# Offense count: 11 +# Offense count: 10 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - - 'lib/grape/dsl/inside_route.rb' - 'lib/grape/dsl/parameters.rb' - 'lib/grape/endpoint.rb' - 'lib/grape/serve_stream/sendfile_response.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 44cd40538..123610c04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#2643](https://github.com/ruby-grape/grape/pull/2638): Remove `try` method in codebase - [@ericproulx](https://github.com/ericproulx). * [#2646](https://github.com/ruby-grape/grape/pull/2646): Call `valid_encoding?` before scrub - [@ericproulx](https://github.com/ericproulx). * [#2644](https://github.com/ruby-grape/grape/pull/2644): Clean useless/not valuable dependencies - [@ericproulx](https://github.com/ericproulx). +* [#2649](https://github.com/ruby-grape/grape/pull/2644): Drop support Ruby 3.0 and ActiveSupport 7.0 - [@ericproulx](https://github.com/ericproulx). * [#2648](https://github.com/ruby-grape/grape/pull/2648): Remove deprecated ParamsBuilders extensions - [@ericproulx](https://github.com/ericproulx). * [#2645](https://github.com/ruby-grape/grape/pull/2645): Endpoints are compiled when API is compiled - [@ericproulx](https://github.com/ericproulx). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1295d21c6..9b4fac85e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,8 +48,8 @@ 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 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` +- running all specs on a specific ruby version (e.g 3.4) `RUBY_VERSION=3.4 docker-compose run --rm --build grape rspec` +- running specs on a specific gemfile (e.g rails_8_1.gemfile) `docker-compose run -e GEMFILE=rails_8_1 --rm --build grape rspec` #### Bundle Install and Test diff --git a/README.md b/README.md index 5e6112896..824c8e3bd 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support ## Installation -Ruby 3.0 or newer is required. +Ruby 3.1 or newer is required. Grape is available as a gem, to install it run: diff --git a/gemfiles/rails_7_0.gemfile b/gemfiles/rails_7_0.gemfile deleted file mode 100644 index b458a7d6f..000000000 --- a/gemfiles/rails_7_0.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -eval_gemfile '../Gemfile' - -gem 'mutex_m' -gem 'rails', '~> 7.0.0' -gem 'tzinfo-data', require: false diff --git a/grape.gemspec b/grape.gemspec index 5759b6d5b..60c5795c9 100644 --- a/grape.gemspec +++ b/grape.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| 'rubygems_mfa_required' => 'true' } - s.add_dependency 'activesupport', '>= 7.0' + s.add_dependency 'activesupport', '>= 7.1' s.add_dependency 'dry-configurable' s.add_dependency 'dry-types', '>= 1.1' s.add_dependency 'mustermann-grape', '~> 1.1.0' @@ -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 = '>= 3.0' + s.required_ruby_version = '>= 3.1' end diff --git a/lib/grape/dsl/helpers.rb b/lib/grape/dsl/helpers.rb index 9d618d836..cfcb07c15 100644 --- a/lib/grape/dsl/helpers.rb +++ b/lib/grape/dsl/helpers.rb @@ -50,9 +50,9 @@ def include_block(block) end end - def make_inclusion(mod, &block) + def make_inclusion(mod, &) define_boolean_in_mod(mod) - inject_api_helpers_to_mod(mod, &block) + inject_api_helpers_to_mod(mod, &) inheritable_setting.namespace_stackable[:helpers] = mod end diff --git a/lib/grape/dsl/parameters.rb b/lib/grape/dsl/parameters.rb index 43e65452e..d5fb59166 100644 --- a/lib/grape/dsl/parameters.rb +++ b/lib/grape/dsl/parameters.rb @@ -160,9 +160,9 @@ def optional(*attrs, **opts, &block) # Define common settings for one or more parameters # @param (see #requires) # @option (see #requires) - def with(*attrs, &block) + def with(*attrs, &) new_group_attrs = [@group, attrs.clone.first].compact.reduce(&:deep_merge) - new_group_scope([new_group_attrs], &block) + new_group_scope([new_group_attrs], &) end %i[mutually_exclusive exactly_one_of at_least_one_of all_or_none_of].each do |validator| @@ -178,12 +178,12 @@ def with(*attrs, &block) # @raise Grape::Exceptions::UnknownParameter if `attr` has not been # defined in this scope yet # @yield a parameter definition DSL - def given(*attrs, &block) + def given(*attrs, &) attrs.each do |attr| proxy_attr = first_hash_key_or_param(attr) raise Grape::Exceptions::UnknownParameter.new(proxy_attr) unless declared_param?(proxy_attr) end - new_lateral_scope(dependent_on: attrs, &block) + new_lateral_scope(dependent_on: attrs, &) end # Test for whether a certain parameter has been defined in this params diff --git a/lib/grape/dsl/routing.rb b/lib/grape/dsl/routing.rb index c075f825e..d80eb23ca 100644 --- a/lib/grape/dsl/routing.rb +++ b/lib/grape/dsl/routing.rb @@ -5,10 +5,10 @@ module DSL module Routing attr_reader :endpoints - def given(conditional_option, &block) + def given(conditional_option, &) return unless conditional_option - mounted(&block) + mounted(&) end def mounted(&block) @@ -157,7 +157,7 @@ def mount(mounts, *opts) # {hello: 'world'} # end # end - def route(methods, paths = ['/'], route_options = {}, &block) + def route(methods, paths = ['/'], route_options = {}, &) method = methods == :any ? '*' : methods endpoint_params = inheritable_setting.namespace_stackable_with_hash(:params) || {} endpoint_description = inheritable_setting.route[:description] @@ -171,7 +171,7 @@ def route(methods, paths = ['/'], route_options = {}, &block) path: paths, for: self, route_options: all_route_options, - &block + & ) endpoints << new_endpoint unless endpoints.any? { |e| e.equals?(new_endpoint) } @@ -223,7 +223,7 @@ def routes # # @param param [Symbol] The name of the parameter you wish to declare. # @option options [Regexp] You may supply a regular expression that the declared parameter must meet. - def route_param(param, **options, &block) + def route_param(param, **options, &) options = options.dup options[:requirements] = { @@ -234,7 +234,7 @@ def route_param(param, **options, &block) requires param, type: options[:type] end if options.key?(:type) - namespace(":#{param}", options, &block) + namespace(":#{param}", options, &) end # @return array of defined versions diff --git a/lib/grape/dsl/validations.rb b/lib/grape/dsl/validations.rb index 0cf83c84e..5ec5dc2b0 100644 --- a/lib/grape/dsl/validations.rb +++ b/lib/grape/dsl/validations.rb @@ -6,8 +6,8 @@ module Validations # Opens a root-level ParamsScope, defining parameter coercions and # validations for the endpoint. # @yield instance context of the new scope - def params(&block) - Grape::Validations::ParamsScope.new(api: self, type: Hash, &block) + def params(&) + Grape::Validations::ParamsScope.new(api: self, type: Hash, &) end # Declare the contract to be used for the endpoint's parameters. diff --git a/lib/grape/middleware/auth/dsl.rb b/lib/grape/middleware/auth/dsl.rb index 6cd9d9541..14610e5dd 100644 --- a/lib/grape/middleware/auth/dsl.rb +++ b/lib/grape/middleware/auth/dsl.rb @@ -16,12 +16,12 @@ def auth(type = nil, options = {}, &block) # # @param [Hash] options A hash of options. # @option options [String] :realm "API Authorization" The HTTP Basic realm. - def http_basic(options = {}, &block) + def http_basic(options = {}, &) options[:realm] ||= 'API Authorization' - auth :http_basic, options, &block + auth(:http_basic, options, &) end - def http_digest(options = {}, &block) + def http_digest(options = {}, &) options[:realm] ||= 'API Authorization' if options[:realm].respond_to?(:values_at) @@ -30,7 +30,7 @@ def http_digest(options = {}, &block) options[:opaque] ||= 'secret' end - auth :http_digest, options, &block + auth(:http_digest, options, &) end end end diff --git a/lib/grape/util/api_description.rb b/lib/grape/util/api_description.rb index 0b007c4d0..e3daa54ed 100644 --- a/lib/grape/util/api_description.rb +++ b/lib/grape/util/api_description.rb @@ -23,10 +23,10 @@ class ApiDescription tags ].freeze - def initialize(description, endpoint_configuration, &block) + def initialize(description, endpoint_configuration, &) @endpoint_configuration = endpoint_configuration @attributes = { description: description } - instance_eval(&block) + instance_eval(&) end DSL_METHODS.each do |attribute| diff --git a/lib/grape/validations/attributes_iterator.rb b/lib/grape/validations/attributes_iterator.rb index 97d7f0280..a4d5287f1 100644 --- a/lib/grape/validations/attributes_iterator.rb +++ b/lib/grape/validations/attributes_iterator.rb @@ -14,8 +14,8 @@ def initialize(validator, scope, params) @params = Array.wrap(@original_params) end - def each(&block) - do_each(@params, &block) # because we need recursion for nested arrays + def each(&) + do_each(@params, &) # because we need recursion for nested arrays end private diff --git a/lib/grape/validations/params_scope.rb b/lib/grape/validations/params_scope.rb index da8de4d00..612d65f05 100644 --- a/lib/grape/validations/params_scope.rb +++ b/lib/grape/validations/params_scope.rb @@ -267,7 +267,7 @@ def validate_attributes(attrs, opts, &block) # @param optional [Boolean] whether the parameter this are nested under # is optional or not (and hence, whether this block's params will be). # @yield parameter scope - def new_scope(attrs, opts, optional = false, &block) + def new_scope(attrs, opts, optional = false, &) # if required params are grouped and no type or unsupported type is provided, raise an error type = opts[:type] if attrs.first && !optional @@ -283,7 +283,7 @@ def new_scope(attrs, opts, optional = false, &block) optional: optional, type: type || Array, group: @group, - &block + & ) end @@ -294,7 +294,7 @@ def new_scope(attrs, opts, optional = false, &block) # scope should only validate if this parameter from the above scope is # present # @yield parameter scope - def new_lateral_scope(options, &block) + def new_lateral_scope(options, &) self.class.new( api: @api, element: nil, @@ -302,7 +302,7 @@ def new_lateral_scope(options, &block) options: @optional, type: type == Array ? Array : Hash, dependent_on: options[:dependent_on], - &block + & ) end @@ -311,8 +311,8 @@ def new_lateral_scope(options, &block) # @param attrs [Array] the attributes passed to the `requires` or # `optional` invocation that opened this scope. # @yield parameter scope - def new_group_scope(attrs, &block) - self.class.new(api: @api, parent: self, group: attrs.first, &block) + def new_group_scope(attrs, &) + self.class.new(api: @api, parent: self, group: attrs.first, &) end # Pushes declared params to parent or settings diff --git a/spec/support/chunked_response.rb b/spec/support/chunked_response.rb index bcc47c303..c3bc8a8dc 100644 --- a/spec/support/chunked_response.rb +++ b/spec/support/chunked_response.rb @@ -14,7 +14,7 @@ def initialize(body) # For each element yielded by the response body, yield # the element in chunked encoding. - def each(&block) + def each(&) term = TERM @body.each do |chunk| size = chunk.bytesize @@ -23,7 +23,7 @@ def each(&block) yield [size.to_s(16), term, chunk.b, term].join end yield TAIL - yield_trailers(&block) + yield_trailers(&) yield term end