Repository navigation
feat(format): %c coercion, hash-default, hex-float #/0 fill, *n$ and width/precision overflow - #7
Merged
Conversation
… *n$, width/precision overflow
Add the host hooks and directive-parsing fixes the rbgo binding needs to
match MRI 4.0.6 sprintf/String#% for cases the engine alone could not reach:
- charCoercer (CoerceChar) lets a host resolve a %c operand via its own
to_str-then-to_int protocol; renderChar consults it before the Kind path.
- NamedArgs.SetDefault registers a resolver for a %<name>/%{name} key absent
from the map, so a host can apply Ruby's Hash#default / default_proc.
- formatHexFloat honours the alternate (#) form, forcing the radix point on
%a/%A even when no fractional hex digit remains ("%#a" of 16.0 -> "0x1.p+4").
- padFloat zero-fills a hex-float body after its "0x"/"0X" prefix
("%020a" -> "0x000...1.9p+3") instead of before it.
- A "n$" value reference may follow '*'-supplied width/precision, as in
"%*1$.*2$3$d"; maybeArgNum records it before the verb is read.
- parseNumber reports overflow so a width/precision digit run too big for int
raises MRI's "width too big" / "precision too big" ArgumentError.
Golden corpus and oracle cases extended; 100% statement coverage preserved.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
tannevaled
added a commit
to go-embedded-ruby/ruby
that referenced
this pull request
Aug 31, 2026
…l in sprintf (#522) * Match MRI %c coercion, Hash#default named refs, and hex-float # / 0-fill in sprintf Wire the format binding to the new go-ruby-format host hooks so Kernel#sprintf / Kernel#format / String#% match MRI 4.0.6 for cases the engine could not reach alone: - formatValue.CoerceChar resolves a %c operand with MRI's to_str-then-to_int protocol via the method table (never #respond_to?, so a BasicObject that defines only #to_str is coerced): a String feeds first-character rendering, an Integer a code point, a non-String/#to_int result raises the matching "can't convert X into String/Integer" TypeError, and an object answering neither raises "no implicit conversion of X into Integer". - formatNamedArgs registers a NamedArgs default resolver so a %<name>/%{name} reference to an absent key consults the hash's own #[] (Hash#default / default_proc): a non-nil default is used, a nil one raises MRI's KeyError. A present key (even a nil value) stays in the map and never hits the resolver. The hex-float alternate-form (%#a) and zero-fill (%020a), the "%*1$.*2$3$d" argument-numbered star width/precision, and the width/precision "too big" ArgumentError are fixed in the engine (go-ruby-format/format#7) and land here through the dependency bump. core/string/modulo_spec: 252 -> 263 examples pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Probe %c/to_ary coercion methods without sending #respond_to? to a BasicObject String#% unpacked its right-hand side by asking respondsToDynamic whether the object answered #to_ary, whose fallback *sends* #respond_to? — which a BasicObject operand does not have, so `"%c" % basic_object_with_to_str` raised NoMethodError instead of coercing. Add formatRespondsTo, which probes the method table first and only dispatches #respond_to? (and thus #respond_to_missing?) to an object that actually provides it, matching MRI's rb_check_funcall. Use it for the %c to_str/to_int coercion and the to_ary unpacking. Covers CoerceChar and the named-hash default resolver with a new format_c_named_test.go. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(deps): re-pin go-ruby-format/format to merged main Engine PR #7 merged; repoint from the PR-branch pseudoversion to the resulting main pseudoversion so the sprintf/format binding builds against released engine code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- 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.
Summary
Adds the host hooks and directive-parsing fixes the rbgo binding needs to match MRI 4.0.6
sprintf/Kernel#format/String#%for cases the engine alone could not reach:charCoercer(CoerceChar) — lets a host resolve a%coperand through its ownto_str-then-to_intprotocol;renderCharconsults it before the Kind-based path.NamedArgs.SetDefault— registers a resolver consulted when a%<name>/%{name}key is absent from the map, the hook through which a host applies Ruby'sHash#default/default_proc.%#a/%#A— the alternate (#) form now forces the radix point on hex-float even when no fractional hex digit remains ("%#a" % 16.0→"0x1.p+4").%0…azero-fill — a hex-float body is zero-filled after its0x/0Xprefix ("%020a" % 12.5→"0x000…1.9p+3").%*1$.*2$3$d— an$value reference may follow*-supplied width/precision;maybeArgNumrecords it before the verb is read.intraises MRI'swidth too big/precision too bigArgumentError.Testing
GOWORK=off go test ./...green; 100.0% statement coverage preserved (golden corpus and oracle cases extended).🤖 Generated with Claude Code