From 9b6eeae4cb6c8562c9d04a06eadf07146e6bbdae Mon Sep 17 00:00:00 2001 From: Eric Proulx Date: Mon, 6 Jul 2026 14:34:38 +0200 Subject: [PATCH] Stop populating the write-only namespace description in desc `desc` stored its settings under both the route scope (`route_setting(:description)`) and the namespace scope (`namespace_setting(:description)`). The namespace copy was never read: `route` consumes only `route[:description]`, the namespace scope is not wired for inheritance (`InheritableSetting#inherit_from` skips `@namespace`), and grape-swagger reads neither. `desc` now writes only the route scope. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 1 + UPGRADING.md | 4 ++++ lib/grape/dsl/desc.rb | 4 +++- spec/grape/dsl/desc_spec.rb | 6 +++--- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4e383979..462e98dda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#2782](https://github.com/ruby-grape/grape/pull/2782): Remove the dead `format` keyword from `Grape::Router::Pattern` - [@ericproulx](https://github.com/ericproulx). * [#2783](https://github.com/ruby-grape/grape/pull/2783): Read a route's `version`, `anchor` and `requirements` from its pattern instead of storing them again on the route - [@ericproulx](https://github.com/ericproulx). * [#2784](https://github.com/ruby-grape/grape/pull/2784): Move HEAD route creation into `Grape::Router::Route#to_head` - [@ericproulx](https://github.com/ericproulx). +* [#2787](https://github.com/ruby-grape/grape/pull/2787): Stop populating the write-only `namespace_setting(:description)` in `desc` - [@ericproulx](https://github.com/ericproulx). * Your contribution here. #### Fixes diff --git a/UPGRADING.md b/UPGRADING.md index 9e0a070c8..25320eb67 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -60,6 +60,10 @@ The `:format` member was removed from the endpoint's internal `Options`. Nothing `Grape::Router::Pattern#initialize` no longer accepts `format:` either. It was never given a non-`nil` value — a route's `:format` capture comes from the path suffix built by `Grape::Path`, not from the pattern — so the keyword was dead. `Grape::Router::Pattern.new(..., format: …)` now raises `unknown keyword: :format`. +#### `desc` no longer populates `namespace_setting(:description)` + +`desc` used to store its settings under both the route scope (`route_setting(:description)`) and the namespace scope (`namespace_setting(:description)`). The namespace copy was write-only — the namespace scope isn't wired for inheritance and nothing in Grape or grape-swagger ever read it — so `desc` now writes only the route scope. `namespace_setting(:description)` returns `nil`; read a route's description through `route_setting(:description)` or the `route.description` reader. + ### Upgrading to >= 3.3 #### Minimum required Ruby is now 3.3 diff --git a/lib/grape/dsl/desc.rb b/lib/grape/dsl/desc.rb index 200d69073..3d358bfd4 100644 --- a/lib/grape/dsl/desc.rb +++ b/lib/grape/dsl/desc.rb @@ -63,7 +63,9 @@ def desc(description, *legacy_options, **options, &config_block) else options.merge(description:) end - inheritable_setting.namespace[:description] = settings + # Only the route scope is consumed downstream (by +route+ and the + # route's readers, e.g. +http_codes+); the namespace scope was + # write-only, so it is no longer populated. inheritable_setting.route[:description] = settings end end diff --git a/spec/grape/dsl/desc_spec.rb b/spec/grape/dsl/desc_spec.rb index 3d7c7f30f..40e82e343 100644 --- a/spec/grape/dsl/desc_spec.rb +++ b/spec/grape/dsl/desc_spec.rb @@ -15,8 +15,8 @@ desc_text = 'The description' options = { message: 'none' } subject.desc desc_text, **options - expect(subject.namespace_setting(:description)).to eq(options.merge(description: desc_text)) expect(subject.route_setting(:description)).to eq(options.merge(description: desc_text)) + expect(subject.namespace_setting(:description)).to be_nil end context 'when a positional options Hash is passed' do @@ -31,8 +31,8 @@ Grape.deprecator.silence do subject.desc desc_text, options end - expect(subject.namespace_setting(:description)).to eq(options.merge(description: desc_text)) expect(subject.route_setting(:description)).to eq(options.merge(description: desc_text)) + expect(subject.namespace_setting(:description)).to be_nil end end @@ -103,8 +103,8 @@ security %w[array of security schemes] end - expect(subject.namespace_setting(:description)).to eq(expected_options) expect(subject.route_setting(:description)).to eq(expected_options) + expect(subject.namespace_setting(:description)).to be_nil end end end