|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +# Named coercions for property definitions, passed as the prop’s block: |
| 4 | +# |
| 5 | +# prop :name, String, &Immutable |
| 6 | +# prop :bio, _Nilable(String), &(NilIfEmpty >> Literal::Coercions.Truncated(255)) |
| 7 | +# |
| 8 | +# These are plain procs, so they compose with `Proc#>>`. |
| 9 | +module Literal::Coercions |
| 10 | + # Shallow: freezes a copy, so the caller’s object is never mutated. |
| 11 | + # References held by the value (array elements, hash values) stay mutable. |
| 12 | + Immutable = proc { |it| it.frozen? ? it : it.dup.freeze } |
| 13 | + |
| 14 | + # Deep: makes the value Ractor-shareable, freezing the entire object graph. |
| 15 | + # Works on a deep copy, so the caller’s object is never mutated. Raises |
| 16 | + # Ractor::IsolationError for values that cannot be made shareable (IO, |
| 17 | + # Thread, procs capturing mutable state). |
| 18 | + DeepImmutable = proc do |it| |
| 19 | + Ractor.shareable?(it) ? it : Ractor.make_shareable(it, copy: true) |
| 20 | + end |
| 21 | + |
| 22 | + # Converts empty values ("", [], {}) to nil, for optional properties where |
| 23 | + # empty input means absent. Everything else passes through untouched. |
| 24 | + NilIfEmpty = proc { |it| (it.respond_to?(:empty?) && it.empty?) ? nil : it } |
| 25 | +end |
0 commit comments