Skip to content

doc: say what a build converting case by ASCII stops refusing - #7231

Merged
matz merged 1 commit into
mruby:masterfrom
takumin:doc-ascii-case-refusal
Aug 17, 2026
Merged

doc: say what a build converting case by ASCII stops refusing#7231
matz merged 1 commit into
mruby:masterfrom
takumin:doc-ascii-case-refusal

Conversation

@takumin

@takumin takumin commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

doc/guides/mrbconf.md, under MRB_UTF8_STRING:

  • A string read as bytes (String#b) converts and folds ASCII alone, and one
    holding bytes that spell no character is refused with ArgumentError.

and, two bullets down, what the option beside it takes away:

  • MRB_USE_ASCII_CASE narrows the case half back to ASCII, leaving the
    indexing.

The MRB_USE_ASCII_CASE section says the same at greater length: it narrows which
characters convert, and names the case table and the regexp i flag as what goes with
them. Neither place says the refusal goes too, so a reader carries the promise across.

What happens

It goes too. The refusal is raised inside the walk over characters, src/string.c:2197,
and the whole walk sits inside #if defined(MRB_UTF8_STRING) && !defined(MRB_USE_ASCII_CASE),
src/string.c:2080-2251. Compiled out, every method falls to its own ASCII loop, and
that loop asks nothing about what the bytes spell.

"abc\x80", on three of the build_config/ci/gcc-clang.rb builds:

bintest ascii-case byte-string
downcase ArgumentError "abc\x80" "abc\x80"
upcase ArgumentError "ABC\x80" "ABC\x80"
capitalize ArgumentError "Abc\x80" "Abc\x80"
swapcase ArgumentError "ABC\x80" "ABC\x80"
casecmp?("ABC\x80") ArgumentError true true

Every ArgumentError above carries the message input string invalid.

Why this changes the documents and not the code

The refusal is there because answering as though a stray byte were the character it
starts with hands back a string nobody asked for. A build that converts nothing above
ASCII writes nothing over those bytes, so there is no wrong answer left to refuse, and
reading the string through to find them would buy only the exception. The ascii-case
column above is also the byte-string column, which is the shape the last bullet of the
section already promises: a build reading its strings as bytes converts ASCII alone
whatever the option says.

Both readings are pinned already:

  • test/t/string.rb:452 asks for the ArgumentError from #downcase, #upcase,
    #capitalize and #downcase!, gated if UNICODECASE.
  • test/t/string.rb:498 asks the same bytes back untouched from #downcase and
    #upcase, gated unless UNICODECASE.
  • mrbgems/mruby-string-ext/test/string.rb:360-362 asks for it from #casecmp? and
    #swapcase, gated skip unless UNICODECASE, and :376 asks #casecmp? for false
    instead, gated skip if UNICODECASE.

So what is missing is the sentence.

Fix

Three sentences, no code.

  • The MRB_USE_ASCII_CASE section gains a bullet: bytes that spell no character are
    handed back as they stand rather than refused, the refusal belonging to the walk the
    option narrows away.
  • The MRB_UTF8_STRING bullet that sends the reader to that option names the refusal
    as part of what it takes, so the promise two bullets above is not carried across.
  • doc/limitations.md, which said only that the option "narrows that half back without
    giving up the indexing", gains the same qualification.

Verification

No build output changes: the diff is two Markdown files. The table above was measured on
this branch, and rake -m test on build_config/ci/gcc-clang.rb reports KO 0 and
Crash 0 in all five builds, unchanged from 03daa666.

Environment

Details
OS Ubuntu 24.04.4 LTS
Kernel Linux 7.0.0-28-generic x86_64
CPU AMD Ryzen 9 5950X (16 cores, 32 threads)
C compiler gcc 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1)
binutils GNU ld 2.47.20260726
CRuby (build host) ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM

The lines that actually compiled src/string.c in the three builds the table reads,
with -MMD -c, -I and -o dropped:

# ci/gcc-clang, bintest
gcc -std=gnu99 -g -O3 -Wall -Wundef -Werror-implicit-function-declaration -Wwrite-strings -DMRB_GC_FIXED_ARENA -DMRB_USE_BIGINT -DMRB_USE_COMPLEX -DHAVE_MRUBY_ENCODING_GEM -DMRB_UTF8_STRING -DHAVE_MRUBY_IO_GEM -DMRB_USE_RATIONAL -DHAVE_MRUBY_REGEXP_GEM -DMRB_USE_SET -DMRB_USE_TASK_SCHEDULER -DMRB_USE_DEBUG_HOOK src/string.c

# ci/gcc-clang, ascii-case
gcc -std=gnu99 -g -O3 -Wall -Wundef -Werror-implicit-function-declaration -Wwrite-strings -DMRB_USE_ASCII_CASE -DMRB_USE_BIGINT -DMRB_USE_COMPLEX -DHAVE_MRUBY_ENCODING_GEM -DMRB_UTF8_STRING -DHAVE_MRUBY_IO_GEM -DMRB_USE_RATIONAL -DHAVE_MRUBY_REGEXP_GEM -DMRB_USE_SET -DMRB_USE_TASK_SCHEDULER src/string.c

# ci/gcc-clang, byte-string
gcc -std=gnu99 -g -O3 -Wall -Wundef -Werror-implicit-function-declaration -Wwrite-strings -DMRB_USE_BIGINT -DMRB_USE_COMPLEX -DHAVE_MRUBY_IO_GEM -DMRB_USE_RATIONAL -DHAVE_MRUBY_REGEXP_GEM -DMRB_USE_SET -DMRB_USE_TASK_SCHEDULER src/string.c

🤖 Generated with Claude Code

https://claude.ai/code/session_01F57Qh8PB4NJRGZPbg9QvHU

Summary by CodeRabbit

  • Documentation
    • Clarified that ASCII narrowing returns invalid UTF-8 byte sequences unchanged instead of raising an ArgumentError.
    • Expanded encoding limitation guidance to explain behavior under Unicode conversion and ASCII narrowing.

`MRB_UTF8_STRING` promises that a string holding bytes that spell no
character is refused with `ArgumentError`. `MRB_USE_ASCII_CASE` is
written up as narrowing which characters convert, and nothing beside it
says the refusal narrows away with them, so a reader carries the promise
across.

It does not hold. The refusal is raised inside the walk over characters,
and the option compiles that walk out, so every method falls to its own
ASCII loop and the loop asks nothing about what the bytes spell:

```ruby
"abc\x80".downcase             #=> "abc\x80"
"abc\x80".casecmp?("ABC\x80")  #=> true
```

where a build with the Unicode tables answers `ArgumentError: input
string invalid` to both. That is the wanted behaviour: a build writing
nothing over those bytes has no wrong answer left to refuse, and reading
them through would buy only the exception. Both readings are already
pinned, in `test/t/string.rb` and `mrbgems/mruby-string-ext/test/string.rb`.

What was missing is the sentence. Say in the `MRB_USE_ASCII_CASE` section
that the refusal belongs to the walk being narrowed away, name it in the
`MRB_UTF8_STRING` bullet that sends the reader there, and give
`doc/limitations.md` the same qualification.
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d164fe9-9f74-41c8-af2f-3ed1d186bfce

📥 Commits

Reviewing files that changed from the base of the PR and between 03daa66 and b9bcad9.

📒 Files selected for processing (2)
  • doc/guides/mrbconf.md
  • doc/limitations.md

Included review availability: Your plan includes up to 8 reviews per rolling hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The documentation clarifies MRB_USE_ASCII_CASE behavior. ASCII conversion preserves UTF-8 indexing and returns invalid bytes unchanged. Unicode conversion rejects invalid byte sequences with ArgumentError.

Changes

Encoding documentation

Layer / File(s) Summary
Case conversion behavior
doc/guides/mrbconf.md, doc/limitations.md
Documents ASCII case narrowing, preserved UTF-8 indexing, unchanged invalid bytes in ASCII mode, and ArgumentError for invalid bytes during Unicode conversion.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Merge Risk: ⚪ Minimal · up to b9bca

This documentation-only change clarifies existing behavior without changing code or build outputs; no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

  • mruby/mruby#7131: Changes string internals and tests for malformed UTF-8 behavior.
  • mruby/mruby#7132: Fixes preservation and validation of invalid UTF-8 bytes in strings.
  • mruby/mruby#7223: Tests invalid-byte behavior during ASCII case conversion.

Suggested reviewers: matz

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the documentation change and the removal of refusal for invalid byte sequences during ASCII case conversion.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@matz
matz merged commit b3fa897 into mruby:master Aug 17, 2026
21 checks passed
@takumin
takumin deleted the doc-ascii-case-refusal branch August 17, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants