Skip to content

Restore the nil-base fallback in Grape::API::Instance#to_s - #2833

Merged
ericproulx merged 1 commit into
masterfrom
instance-to-s-nil-fallback
Jul 27, 2026
Merged

Restore the nil-base fallback in Grape::API::Instance#to_s#2833
ericproulx merged 1 commit into
masterfrom
instance-to-s-nil-fallback

Conversation

@ericproulx

Copy link
Copy Markdown
Contributor

Summary

Fixes #2832.

Grape::API::Instance.to_s returns "" instead of its class name. #name is still correct — only #to_s is blank, which is what makes it surprising.

Cause

PR #2581 replaced an explicit, nil-guarded to_s override with:

def_delegators :@base, :to_s

@base is only assigned via base=, which runs when Grape::API.mount_instance builds a mount instance (lib/grape/api.rb). The bare Grape::API::Instance class is never mounted and never has base= called on it, so it stays @base-less forever — not a transient state, but permanent for that specific class. The delegator then evaluates nil.to_s, yielding "".

Anything that enumerates loaded classes and renders them by string representation (Sorbet/Tapioca RBI generation, log/error message interpolation) sees an empty name instead of Grape::API::Instance.

Fix

Before After
def_delegators :@base, :to_s (via extend Forwardable) `def to_s; @base&.to_s

super resolves through the singleton-class ancestry to Module#to_s, restoring the pre-3.0.0 behavior. The @base set case is unaffected — empty string is truthy in Ruby, so the delegation branch behaves exactly as before once an instance is mounted.

extend Forwardable is dropped from Grape::API::Instance's singleton class since it existed solely for this one delegator.

Notes

  • Added describe '.to_s' coverage in spec/grape/api/instance_spec.rb: one example for the unmounted fallback, one mirroring the issue's repro (SomeAPI.base_instance.to_s == 'SomeAPI') for the mounted case.
  • Full bundle exec rubocop and bundle exec rspec (2515 examples) pass clean.

🤖 Generated with Claude Code

def_delegators :@base, :to_s (#2581) evaluates nil.to_s and returns ""
for any Instance whose @base is unset -- notably the bare
Grape::API::Instance class itself, which is never mounted and never
has base= called on it, so it stays base-less forever. Anything that
enumerates loaded classes and renders them by string (Sorbet/Tapioca
RBI generation, log/error interpolation) sees an empty name instead of
"Grape::API::Instance", while #name stays correct -- the disagreement
is what makes it surprising.

Replace the delegator with an explicit method that falls back to
Module#to_s via super when @base is nil, matching the pre-3.0 behavior.

Fixes #2832.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Danger Report

No issues found.

View run

@ericproulx
ericproulx merged commit 013a5b8 into master Jul 27, 2026
69 checks passed
@ericproulx
ericproulx deleted the instance-to-s-nil-fallback branch July 27, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grape::API::Instance.to_s returns "" since 3.0.0 (nil-guard lost when converted to def_delegators)

1 participant