Encapsulate namespace_reverse_stackable behind rescue-handler methods#2795
Merged
dblock merged 1 commit intoJul 12, 2026
Merged
Conversation
namespace_reverse_stackable existed only to store rescue-handler maps, yet it was a public attr_reader that callers reached into with raw keys from two different files (the rescue_from write and the endpoint read). That's how the base-only handlers write/read drifted onto mismatched stores. Make the store internal (protected, still used by inherit_from/copy_state_from/ to_hash) and expose intent-revealing methods on InheritableSetting instead: rescue_handlers / base_only_rescue_handlers (merged, child-scope-first) and add_rescue_handlers(mapping, subclasses:). The DSL write and endpoint reads go through those, so there's one place that knows the key, store and merge. The reverse-ordering behaviour stays covered by ReverseStackableValues' own spec; the InheritableSetting specs that poked the raw store are replaced with tests for the new methods. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ericproulx
force-pushed
the
refactor/encapsulate-reverse-stackable
branch
from
July 12, 2026 13:34
dfdb251 to
7b4e99a
Compare
Danger ReportNo issues found. |
dblock
approved these changes
Jul 12, 2026
ericproulx
added a commit
that referenced
this pull request
Jul 13, 2026
Since #2795 internalized namespace_reverse_stackable into InheritableSetting, ReverseStackableValues had a single consumer holding exactly two keys (rescue_handlers / base_only_rescue_handlers). Its only job was reverse-order chain traversal, but InheritableSetting already tracks the same chain through #parent. Replace the store with a plain per-scope Hash of rescue_from registrations and merge it recursively over #parent. Hash#merge natively yields the ordering Middleware::Error's find-based scan depends on: the nearest scope's keys first (registration order preserved within a scope), inherited keys appended, nearer handler winning on collision. InheritableSetting#to_hash now exposes the merged rescue_handlers / base_only_rescue_handlers instead of a namespace_reverse_stackable key. Also drops the per-layer ReverseStackableValues allocation and the intermediate arrays StackableValues#[] built on every read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2794. That bug happened because
namespace_reverse_stackable— a store whose only purpose is rescue-handler maps — was a publicattr_readerthat two different files reached into with raw keys, so the base-only write and read could drift onto different stores.Change
Make
namespace_reverse_stackableprotected(still used internally byinherit_from/copy_state_from/to_hash), and expose intent-revealing methods onInheritableSetting:dsl/request_response.rb): thehandler_typebranch collapses intoadd_rescue_handlers(mapping, subclasses: rescue_subclasses).endpoint.rb):error_middleware_optionscallsns_stack.rescue_handlers/.base_only_rescue_handlers; the child-precedence merge moves out ofEndpointontoInheritableSetting, and the threeEndpointprivates from Fix base-only rescue handlers never firing #2794 go away.Now one place knows the key, the store, and the merge — the write/read can't drift apart again.
Tests
The reverse-ordering behaviour is already covered by
ReverseStackableValues' own spec (14 examples), so theInheritableSettingspecs that pokedsubject.namespace_reverse_stackable[...]are replaced with tests forrescue_handlers/base_only_rescue_handlers/add_rescue_handlers(including nested-scope override).request_response_specassertions switch from the raw store to the named readers.Full suite: 2353 examples, 0 failures. RuboCop clean.
🤖 Generated with Claude Code