errgonomic 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +7 -3
- data/lib/errgonomic/option.rb +25 -14
- data/lib/errgonomic/result.rb +30 -11
- data/lib/errgonomic/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e5dd5bf1efa4f12df029b4084a03a8a16eacac628f9481c35cbac8d03164b0c
|
|
4
|
+
data.tar.gz: c61b4e0944afd847636e0e7a1beb44a60793b2124fb9b390cdc408cb3899fb6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bafdcc2538e9603d54fc0452912fddf9f86f912074f9a94dd0af3de3783df26917263cca09d0a5ea9440844016fb3da7190127327602a18506c62723ee81c4d8
|
|
7
|
+
data.tar.gz: 43a642d0ebfc22610b0f0ad0fe14f954d23c9b6909cc72e1a4ed56543e7e7d3e3c6e6173ce5443a12f33504045aacc734a5ea922d9a7998d4bd5a03f80a889c7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.9.1] - 2026-09-10
|
|
4
|
+
|
|
5
|
+
This release reverts the 0.9.0 change that made `to_s` render an Option or a Result. The raise is back, with a message that says what to call instead.
|
|
6
|
+
|
|
7
|
+
### Upgrading from 0.9.0
|
|
8
|
+
|
|
9
|
+
`to_s` on an Option or a Result raises `Errgonomic::SerializeError` again, so a string built from a wrapped reader fails where it is built rather than writing `Some("...")` or `None` into it. Code written against 0.9.0's rendering, whether a string interpolation, an `Array#join`, a `format`, a `String()` or a bare ERB `<%= %>`, has to take the value first: `unwrap_or` or `expect!` for the value, or `inspect` for a log line. A `rescue` that interpolates a wrapper into its message writes `inspect` there. A `rescue Errgonomic::SerializeError` written against 0.8.x still matches. A `logger.info(opt)` that rendered through 0.9.0 still renders through a plain `Logger`, but raises under Rails' `TaggedLogging` once a tag such as `request_id` is set, so it can pass in tests and raise in production: write `logger.info(opt.inspect)`. The README's Option section describes this and a `case/in` that matches nothing on a wrapper, whose `NoMatchingPatternError` no longer prints its subject.
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
- [Behavior change] `to_s` on an Option or a Result raises `Errgonomic::SerializeError` where 0.9.0 rendered it as `inspect` does. The message names the value with its `inspect`, bounded to 60 characters, says `to_s` is refused, and names `inspect` for a log line and `unwrap_or` / `expect!` for the value: `Some(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value`. 0.9.0's rendering wrote wrapper text into data at every site that built a string from a wrapped reader, with no exception to find the site by: a UNIQUE identity column, a hostname, a hashed auth token and a customer-facing page. A raise that names the remedy serves the log-line case 0.9.0 traded for, and `inspect` is unchanged
|
|
14
|
+
- An Option or a Result in a Hash key raises on its way to JSON again. The json gem and ActiveSupport's `as_json` both stringify a key with `to_s`, so 0.9.0's rendering let `{ Some(1) => 2 }.as_json` write `{"Some(1)" => 2}` where a value position had always raised
|
|
15
|
+
- `Result#unwrap_err!` on an `Ok` raises an `Errgonomic::UnwrapError` whose message is the Ok's value as `inspect` renders it, bounded to 60 characters, and whose `value` is the value itself. The message used to be the value's `to_s`, so once `to_s` refuses, `Ok(Some(1)).unwrap_err!` printed only the class name and its `message` raised. A String value is quoted in the message, as `inspect` quotes it
|
|
16
|
+
|
|
3
17
|
## [0.9.0] - 2026-09-08
|
|
4
18
|
|
|
5
19
|
This release turns the ActiveRecord integration from a set of wrapped readers into a full set of boundaries, covering readers, writers, query binds, validation and serialization, with the behavior changes named in the bullets below.
|
data/README.md
CHANGED
|
@@ -122,9 +122,13 @@ in Errgonomic::Option::None
|
|
|
122
122
|
end
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
An unhandled Option refuses to leak into your output: `to_json` and `as_json` raise `Errgonomic::SerializeError`, so you handle the inner value deliberately rather than shipping
|
|
125
|
+
An unhandled Option refuses to leak into your output: `to_s`, `to_json` and `as_json` raise `Errgonomic::SerializeError`, so you handle the inner value deliberately rather than shipping `Some("...")` to a user. The refusal names what it was carrying (`cannot serialize an unwrapped Some("cell-a1b2")`), so a payload built out of many values says which one went unhandled; the value's `inspect` is bounded to 60 characters, with an ellipsis past that. The refusal covers `as_json` because Hash and Array serialization recurses through that method, and an Option nested in a payload would otherwise serialize as `{"value": ...}`. A converted ActiveRecord model is the one exception, at the model boundary: it unwraps each attribute as it serializes, so a record's own `as_json` says what an unconverted record's says. See [Rails integration](#rails-integration).
|
|
126
126
|
|
|
127
|
-
`to_s`
|
|
127
|
+
The `to_s` refusal is the loudest guard of the three, because a string is where a wrapper turns into data: string interpolation, `Array#join`, `format`, `String()`, a bare ERB `<%= %>` and the key of a Hash on its way to JSON all reach the value through `to_s`, and every one of them raises rather than writing `Some("...")` into a hostname, a column or a page. Rust gives `Option` a `Debug` and no `Display`, and `inspect` is the `Debug` here: it renders `Some(1)`, and it is what a log line or a `rescue` should call (`"got #{opt.inspect}"`). The refusal says so: `Some(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value`.
|
|
128
|
+
|
|
129
|
+
Two places reach `to_s` on your behalf, and read badly when it refuses. The first is a `case/in` with more than one `in` branch where none matches. Ruby raises `NoMatchingPatternError` with the unmatched Option or Result itself as the message, and printing that message calls `to_s`. Uncaught, it prints as a bare `NoMatchingPatternError` with no subject, and inside a Minitest test the reporter crashes on it with `Some(1) refuses to_s; …` before it prints the test's name or the run summary. The subject is a variant the `case` has no branch for, such as a Result handed to Option patterns, so the fix is the missing `in` branch, or an `else`; an `inspect` has nowhere to go. A single-branch `case/in` and a rightward `=>` build their message with `inspect` and print normally.
|
|
130
|
+
|
|
131
|
+
The second is a logger. `logger.info(opt)` renders `Some(1)` through a plain `Logger`, whose formatter calls `inspect` on a message that is not a String, but raises through Rails' `ActiveSupport::TaggedLogging` once a tag is set, because the tagged formatter interpolates the message. Rails' generated `production.rb` tags every request with `log_tags = [:request_id]`, so the same line passes in tests and raises in production. Write `logger.info(opt.inspect)`.
|
|
128
132
|
|
|
129
133
|
`expect!` also takes a block, on an Option and a Result alike, so a message that interpolates is built only on the branch that raises: `tier.expect! { "no tier for #{account.id}" }`. `present_or_raise!` takes one on the same terms. The positional form is unchanged.
|
|
130
134
|
|
|
@@ -177,7 +181,7 @@ in Errgonomic::Result::Err, Exception => e
|
|
|
177
181
|
end
|
|
178
182
|
```
|
|
179
183
|
|
|
180
|
-
Like Options, unwrapped Results refuse `to_json` and `as_json`, and render
|
|
184
|
+
Like Options, unwrapped Results refuse `to_s`, `to_json` and `as_json`, and render through `inspect`. And `Object#result?` / `Object#assert_result!` help enforce at runtime that a value is a Result.
|
|
181
185
|
|
|
182
186
|
### Optional collections
|
|
183
187
|
|
data/lib/errgonomic/option.rb
CHANGED
|
@@ -678,18 +678,22 @@ module Errgonomic
|
|
|
678
678
|
Some(other)
|
|
679
679
|
end
|
|
680
680
|
|
|
681
|
-
#
|
|
682
|
-
#
|
|
683
|
-
#
|
|
684
|
-
#
|
|
685
|
-
#
|
|
686
|
-
# @example
|
|
687
|
-
# Some(1).to_s # => "Some(1)"
|
|
688
|
-
#
|
|
689
|
-
#
|
|
690
|
-
# "
|
|
681
|
+
# Refuse to render as a String. Rust gives Option a Debug and no
|
|
682
|
+
# Display: a wrapper that reaches a string went unhandled, and a string
|
|
683
|
+
# is where it turns into data, a hostname, a hash key or a page. The
|
|
684
|
+
# refusal names the value and says how to log it or take it.
|
|
685
|
+
#
|
|
686
|
+
# @example
|
|
687
|
+
# Some(1).to_s # => raise Errgonomic::SerializeError, "Some(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
688
|
+
# None().to_s # => raise Errgonomic::SerializeError, "None refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
689
|
+
# "value: #{Some(1)}" # => raise Errgonomic::SerializeError, "Some(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
690
|
+
# [Some("org"), Some("metrics")].join("/") # => raise Errgonomic::SerializeError, "Some(\"org\") refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
691
|
+
# format("%s", None()) # => raise Errgonomic::SerializeError, "None refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
692
|
+
# String(Some(1)) # => raise Errgonomic::SerializeError, "Some(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
693
|
+
# Some("a" * 100).to_s # => raise Errgonomic::SerializeError, "Some(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
694
|
+
# Some(1).inspect # => "Some(1)"
|
|
691
695
|
def to_s
|
|
692
|
-
|
|
696
|
+
raise Errgonomic::SerializeError, to_s_refusal
|
|
693
697
|
end
|
|
694
698
|
|
|
695
699
|
# Refuse to serialize an unwrapped Option as JSON. Not only should we
|
|
@@ -773,12 +777,19 @@ module Errgonomic
|
|
|
773
777
|
|
|
774
778
|
private
|
|
775
779
|
|
|
780
|
+
def to_s_refusal
|
|
781
|
+
"#{bounded_inspect} refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def serialize_refusal
|
|
785
|
+
"cannot serialize an unwrapped #{bounded_inspect}"
|
|
786
|
+
end
|
|
787
|
+
|
|
776
788
|
# Name the value the caller failed to handle, bounded: an inspect of a
|
|
777
789
|
# record or a long payload would bury the message carrying it.
|
|
778
|
-
def
|
|
790
|
+
def bounded_inspect
|
|
779
791
|
rendered = inspect
|
|
780
|
-
rendered
|
|
781
|
-
"cannot serialize an unwrapped #{rendered}"
|
|
792
|
+
rendered.length > 60 ? "#{rendered[0, 57]}..." : rendered
|
|
782
793
|
end
|
|
783
794
|
|
|
784
795
|
def presence_nudge(from, to)
|
data/lib/errgonomic/result.rb
CHANGED
|
@@ -241,12 +241,16 @@ module Errgonomic
|
|
|
241
241
|
end
|
|
242
242
|
|
|
243
243
|
# Return the inner value of an Err, else raise an exception when Ok.
|
|
244
|
+
# The message is the Ok's value as inspect renders it, bounded, so an
|
|
245
|
+
# Ok holding an Option or a Result still has a message to print.
|
|
244
246
|
#
|
|
245
247
|
# @example
|
|
246
|
-
# Ok(1).unwrap_err! # => raise Errgonomic::UnwrapError, 1
|
|
248
|
+
# Ok(1).unwrap_err! # => raise Errgonomic::UnwrapError, "1"
|
|
249
|
+
# Ok(Some(1)).unwrap_err! # => raise Errgonomic::UnwrapError, "Some(1)"
|
|
250
|
+
# Ok("a" * 100).unwrap_err! # => raise Errgonomic::UnwrapError, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..."
|
|
247
251
|
# Err(:e).unwrap_err! # => :e
|
|
248
252
|
def unwrap_err!
|
|
249
|
-
raise Errgonomic::UnwrapError, value unless err?
|
|
253
|
+
raise Errgonomic::UnwrapError.new(bounded_inspect(value), value) unless err?
|
|
250
254
|
|
|
251
255
|
@value
|
|
252
256
|
end
|
|
@@ -405,18 +409,22 @@ module Errgonomic
|
|
|
405
409
|
Err(block.call(value))
|
|
406
410
|
end
|
|
407
411
|
|
|
408
|
-
#
|
|
409
|
-
#
|
|
410
|
-
#
|
|
411
|
-
#
|
|
412
|
+
# Refuse to render as a String. Rust gives Result a Debug and no
|
|
413
|
+
# Display: a wrapper that reaches a string went unhandled, and a string
|
|
414
|
+
# is where it turns into data, a hostname, a hash key or a page. The
|
|
415
|
+
# refusal names the value and says how to log it or take it.
|
|
412
416
|
#
|
|
413
417
|
# @example
|
|
414
|
-
# Ok(1).to_s # => "Ok(1)"
|
|
415
|
-
# Err(:nope).to_s # => "Err(:nope)"
|
|
416
|
-
#
|
|
417
|
-
#
|
|
418
|
+
# Ok(1).to_s # => raise Errgonomic::SerializeError, "Ok(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
419
|
+
# Err(:nope).to_s # => raise Errgonomic::SerializeError, "Err(:nope) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
420
|
+
# "outcome: #{Ok(1)}" # => raise Errgonomic::SerializeError, "Ok(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
421
|
+
# [Ok(1), Err(:x)].join(",") # => raise Errgonomic::SerializeError, "Ok(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
422
|
+
# format("%s", Err(:x)) # => raise Errgonomic::SerializeError, "Err(:x) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
423
|
+
# String(Ok(1)) # => raise Errgonomic::SerializeError, "Ok(1) refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
424
|
+
# Err("a" * 100).to_s # => raise Errgonomic::SerializeError, "Err(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
425
|
+
# Err(:nope).inspect # => "Err(:nope)"
|
|
418
426
|
def to_s
|
|
419
|
-
|
|
427
|
+
raise Errgonomic::SerializeError, to_s_refusal
|
|
420
428
|
end
|
|
421
429
|
|
|
422
430
|
# Refuse to serialize an unwrapped Result as JSON. Not only should we
|
|
@@ -471,6 +479,17 @@ module Errgonomic
|
|
|
471
479
|
|
|
472
480
|
private
|
|
473
481
|
|
|
482
|
+
def to_s_refusal
|
|
483
|
+
"#{bounded_inspect} refuses to_s; use inspect for a log line, or unwrap_or / expect! for the value"
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Name the value the caller failed to handle, bounded: an inspect of a
|
|
487
|
+
# record or a long payload would bury the message carrying it.
|
|
488
|
+
def bounded_inspect(object = self)
|
|
489
|
+
rendered = object.inspect
|
|
490
|
+
rendered.length > 60 ? "#{rendered[0, 57]}..." : rendered
|
|
491
|
+
end
|
|
492
|
+
|
|
474
493
|
def strict_equality!(other, operator)
|
|
475
494
|
return unless Errgonomic.strict_equality?
|
|
476
495
|
return if other.is_a?(Errgonomic::Result::Any)
|
data/lib/errgonomic/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: errgonomic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nick Zadrozny
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 1980-01-
|
|
10
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: concurrent-ruby
|