Skip to content

String#encode: fallback #to_str/validation, xml NCRs, IBM437, default_internal, converter-not-found - #523

Merged
tannevaled merged 3 commits into
mainfrom
feat/agent-encode2
Aug 31, 2026
Merged

tannevaled merged 3 commits into
mainfrom
feat/agent-encode2

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Advances core/string/encode_spec.rb conformance against MRI Ruby 4.0.6, from 106 to 146 passing examples (was 28 fail / 18 error, now 4 fail / 2 error).

Changes (all in internal/vm/string_encode.go + string_encode_xtext.go)

  • :fallback semantics. A non-String fallback result is converted through #to_str (never #to_s); a substitute that is itself unrepresentable in the target raises ArgumentError, "too big fallback string"; and a fallback object with no #[] is treated as no fallback, so the character falls through to the normal Encoding::UndefinedConversionError.
  • xml: :text / :attr. A character absent from the destination is rendered as an upper-case numeric character reference (ü) instead of raising.
  • IBM437 gains a codec (charmap.CodePage437).
  • Encoding.default_internal. #encode with no destination transcodes to default_internal when one is set.
  • Converter resolution. An unusable destination — an unregistered name, or a dummy encoding like Emacs-Mule — is reported as Encoding::ConverterNotFoundError rather than an unknown-encoding ArgumentError or a premature UndefinedConversionError. A 7-bit ASCII String still transcodes to any ASCII-compatible destination as a byte-identical copy, matching MRI.
  • String#encode! raises FrozenError on a frozen receiver, even for a no-op transcoding.
  • Removed the resulting dead unsupported-target branches in charEncodableIn / encodeFromUTF8 / xtextEncode, and updated two stale expectations in encoding_encode_test.go to MRI's actual behaviour.

Remaining (out of scope for these files)

6 example-instances still fail: two need an Emacs-Mule codec (absent from golang.org/x/text), and the rest hinge on Encoding::Converter.new(Emacs_Mule, BINARY) raising ConverterNotFoundError (lives in converter_impl.go).

Verification

  • core/string/encode_spec.rb: 106 → 146 passing, no regressions (spot-checked upcase_spec).
  • go test ./internal/vm/ green; go test ./... green; GOOS=wasip1 GOARCH=wasm go build ./... OK; gofmt -l clean on changed files.
  • MERGED coverage (-coverpkg over all internal/...): 100.0%.

🤖 Generated with Claude Code

tannevaled and others added 3 commits August 31, 2026 13:24
…frozen

Advance core/string/encode_spec.rb from 106 to 134 passing examples:
- :fallback now converts a non-String result via #to_str (never #to_s),
  rejects a substitute unrepresentable in the target with ArgumentError
  "too big fallback string", and treats an object without #[] as no fallback
  (the char falls through to the normal UndefinedConversionError).
- xml: :text / :attr render a character absent from the destination as an
  upper-case numeric character reference (&#xHH;) instead of raising.
- IBM437 gains a codec (charmap.CodePage437).
- String#encode! raises FrozenError on a frozen receiver, even for a no-op.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hortcut

Continue advancing core/string/encode_spec.rb (134 -> 146 passing):
- #encode with no destination transcodes to Encoding.default_internal when set.
- An unusable destination (an unregistered name, or a dummy encoding like
  Emacs-Mule) is reported as Encoding::ConverterNotFoundError rather than an
  unknown-encoding ArgumentError or a premature UndefinedConversionError; a
  7-bit ASCII String still transcodes to any ASCII-compatible destination as a
  byte-identical copy, matching MRI.
- Encoding-name arguments resolve through the registry but pass an unknown name
  through verbatim so the missing-converter path reports it.
- Adds internal/vm/encode_residuals_test.go and updates two stale expectations
  in encoding_encode_test.go to MRI's actual behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er residuals

The early converter check in stringEncode guarantees a supported destination
before decode/encode/fallback run, and caseMapBytes decodes first, so the
downstream unsupported-target branches in charEncodableIn, encodeFromUTF8 and
xtextEncode became unreachable dead code. Remove them (xtextEncode no longer
returns a found bool) and extend encode_residuals_test.go with the TypeError
path for a non-convertible encoding argument. Merged coverage back to 100.0%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 5940453 into main Aug 31, 2026
7 checks passed
@tannevaled
tannevaled deleted the feat/agent-encode2 branch August 31, 2026 12:33
tannevaled added a commit that referenced this pull request Aug 31, 2026
* Raise ruby/spec floor to 17470 after wave-3 conformance work

Locks in the gains from #521 (regexp \xHH), #523 (String#encode
fallback/xml/IBM437/default_internal), #524 (Marshal Data + Regexp
encoding), #525 (Module#define_method arity/visibility/hooks) and #522
(sprintf %c/named-default/hex-float). Measured 17470 passing on the
pinned corpus, up from 17310.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: re-trigger after transient GOPROXY stream errors

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant