Module: Axn::Internal::Text
- Defined in:
- lib/axn/internal/text.rb
Overview
Foreign String BYTES, rendered so axn can write them into prose of its own.
Every message axn builds is UTF-8, and joining a String whose bytes have no UTF-8-compatible
rendering to one raises Encoding::CompatibilityError from the reporting itself — so a caller gets an
encoding failure instead of the failure being reported, or loses a log line entirely. Two
ASCII-compatible encodings concatenate fine, which is why this only bites once a message carries
non-ASCII text from BOTH sides: a Latin-1 caf\xE9 beside a UTF-8 naïve, or axn's own decoration.
ZERO requires, deliberately. This is the lowest layer in the gem, and it has to be: axn/exceptions
renders its own messages, the reflection layer is built on axn/exceptions, and axn/extensions — the
guard config boot itself runs through — can afford to require none of them. A file that reached back up
into the reflection layer would leave a message path NameError-ing under the standalone loads
spec/axn/standalone_require_spec.rb pins.
Every read is a BOUND String method. A String SUBCLASS can override encoding, valid_encoding?,
ascii_only?, encode and inspect, and one whose valid_encoding? returns true over bytes that
aren't valid defeats this check on exactly the value it exists to catch (verified: the lying override
is believed, and a JSON::GeneratorError or an Encoding::CompatibilityError follows). Callers type-test
for String first; these take no responsibility for anything else.
Class Method Summary collapse
-
.escaped(string) ⇒ Object
The escaped spelling of
string—String#inspect, bound. -
.renderable(string) ⇒ Object
stringas a frozen plain UTF-8 String axn owns, for writing into a message: byte-identical for ASCII, its text for another encoding, and the escaped spelling when the bytes have no UTF-8 rendering at all. -
.transcode_to_utf8(string) ⇒ Object
EncodingErroris exactly the three refusals a transcode can raise (no converter for the pair, an undefined mapping, an invalid byte sequence) and nothing else. -
.utf8_rendering(string) ⇒ Object
A UTF-8 rendering of
string's bytes, or nil when they have none.
Class Method Details
.escaped(string) ⇒ Object
The escaped spelling of string — String#inspect, bound. Every non-ASCII byte comes back as an
escape, so the result is ASCII and joins to anything.
60 |
# File 'lib/axn/internal/text.rb', line 60 def escaped(string) = INSPECT.bind_call(string) |
.renderable(string) ⇒ Object
string as a frozen plain UTF-8 String axn owns, for writing into a message: byte-identical for
ASCII, its text for another encoding, and the escaped spelling when the bytes have no UTF-8
rendering at all. Escaping rather than scrubbing, because a message that names an offender must
not quietly alter what it names; Identity.utf8_string takes the other fallback for text that has
to render at any cost.
67 68 69 70 71 |
# File 'lib/axn/internal/text.rb', line 67 def renderable(string) utf8 = utf8_rendering(string) || escaped(string) ::String.new(utf8).force_encoding(::Encoding::UTF_8).freeze end |
.transcode_to_utf8(string) ⇒ Object
EncodingError is exactly the three refusals a transcode can raise (no converter for the pair, an
undefined mapping, an invalid byte sequence) and nothing else. The transcoded String is the answer
rather than a boolean because performing the transcode IS the check — there is nothing to save by
throwing the result away.
52 53 54 55 56 |
# File 'lib/axn/internal/text.rb', line 52 def transcode_to_utf8(string) ENCODE.bind_call(string, ::Encoding::UTF_8) rescue ::EncodingError nil end |
.utf8_rendering(string) ⇒ Object
A UTF-8 rendering of string's bytes, or nil when they have none.
The ASCII-only fast path returns the argument ITSELF, subclass and all. That is safe for every
consumer because interpolating a String never dispatches its to_s — "#{}" uses a String as it
stands — so a subclass whose to_s raises still renders as its bytes. A consumer that needs a
plain String it owns copies it (see renderable, canonical_wire_key).
39 40 41 42 43 44 45 46 |
# File 'lib/axn/internal/text.rb', line 39 def utf8_rendering(string) return string if ASCII_ONLY.bind_call(string) case ENCODING.bind_call(string) when ::Encoding::UTF_8 then VALID_ENCODING.bind_call(string) ? string : nil else transcode_to_utf8(string) end end |