Class: Rigor::Type::Refined
- Inherits:
-
Object
- Object
- Rigor::Type::Refined
- Defined in:
- lib/rigor/type/refined.rb
Overview
‘Refined[base, predicate_id]` — predicate-subset half of the OQ3 refinement-carrier strategy ([ADR-3](docs/adr/3-type-representation.md), Working Decision Option C). Sibling of `Type::Difference`, which carries the point-removal half.
lowercase-string = Refined[Nominal[String], :lowercase]
uppercase-string = Refined[Nominal[String], :uppercase]
numeric-string = Refined[Nominal[String], :numeric]
The carrier wraps a base type and a ‘predicate_id` Symbol drawn from PREDICATES. The recogniser is invoked at constant-fold and acceptance time over a `Constant<base>` value; for non-Constant receivers the carrier is a marker the catalog tier consults to project `String#downcase` / `String#upcase` (etc.) into the matching refinement.
Display routes through CANONICAL_NAMES: registered ‘(base_class_name, predicate_id)` pairs print in their kebab-case spelling (`lowercase-string`); unregistered combinations fall back to the `base & predicate?` operator form per [`type-operators.md`](docs/type-specification/type-operators.md).
Construction MUST go through ‘Type::Combinator.refined` / the per-name factories (`Combinator.lowercase_string`, `Combinator.uppercase_string`, `Combinator.numeric_string`). Direct `.new` is an internal escape hatch for tests and combinator’s own implementation.
Constant Summary collapse
- PREDICATES =
{ lowercase: ->(v) { v.is_a?(String) && v == v.downcase }, uppercase: ->(v) { v.is_a?(String) && v == v.upcase }, numeric: ->(v) { v.is_a?(String) && NUMERIC_STRING_PATTERN.match?(v) }, decimal_int: ->(v) { v.is_a?(String) && DECIMAL_INT_STRING_PATTERN.match?(v) }, octal_int: ->(v) { v.is_a?(String) && OCTAL_INT_STRING_PATTERN.match?(v) }, hex_int: ->(v) { v.is_a?(String) && HEX_INT_STRING_PATTERN.match?(v) } }.freeze
Instance Attribute Summary collapse
-
#base ⇒ Object
readonly
Returns the value of attribute base.
-
#predicate_id ⇒ Object
readonly
Returns the value of attribute predicate_id.
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?)
- #accepts(other, mode: :gradual) ⇒ Object
- #bot ⇒ Object
- #describe(verbosity = :short) ⇒ Object
- #dynamic ⇒ Object
-
#erase_to_rbs ⇒ Object
Erases to the base nominal: every refinement MUST erase to its base per [‘rbs-erasure.md`](docs/type-specification/rbs-erasure.md).
- #hash ⇒ Object
-
#initialize(base, predicate_id) ⇒ Refined
constructor
A new instance of Refined.
- #inspect ⇒ Object
-
#matches?(value) ⇒ Boolean
Recognises a Ruby value against this carrier’s predicate.
- #top ⇒ Object
Constructor Details
#initialize(base, predicate_id) ⇒ Refined
Returns a new instance of Refined.
39 40 41 42 43 44 45 |
# File 'lib/rigor/type/refined.rb', line 39 def initialize(base, predicate_id) raise ArgumentError, "predicate_id must be a Symbol" unless predicate_id.is_a?(Symbol) @base = base @predicate_id = predicate_id freeze end |
Instance Attribute Details
#base ⇒ Object (readonly)
Returns the value of attribute base.
37 38 39 |
# File 'lib/rigor/type/refined.rb', line 37 def base @base end |
#predicate_id ⇒ Object (readonly)
Returns the value of attribute predicate_id.
37 38 39 |
# File 'lib/rigor/type/refined.rb', line 37 def predicate_id @predicate_id end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
76 77 78 |
# File 'lib/rigor/type/refined.rb', line 76 def ==(other) other.is_a?(Refined) && base == other.base && predicate_id == other.predicate_id end |
#accepts(other, mode: :gradual) ⇒ Object
72 73 74 |
# File 'lib/rigor/type/refined.rb', line 72 def accepts(other, mode: :gradual) Inference::Acceptance.accepts(self, other, mode: mode) end |
#describe(verbosity = :short) ⇒ Object
47 48 49 50 51 52 |
# File 'lib/rigor/type/refined.rb', line 47 def describe(verbosity = :short) named = canonical_name return named if named "#{base.describe(verbosity)} & #{predicate_id}?" end |
#dynamic ⇒ Object
68 69 70 |
# File 'lib/rigor/type/refined.rb', line 68 def dynamic base.respond_to?(:dynamic) ? base.dynamic : Trinary.no end |
#erase_to_rbs ⇒ Object
Erases to the base nominal: every refinement MUST erase to its base per [‘rbs-erasure.md`](docs/type-specification/rbs-erasure.md).
56 57 58 |
# File 'lib/rigor/type/refined.rb', line 56 def erase_to_rbs base.erase_to_rbs end |
#hash ⇒ Object
81 82 83 |
# File 'lib/rigor/type/refined.rb', line 81 def hash [Refined, base, predicate_id].hash end |
#inspect ⇒ Object
85 86 87 |
# File 'lib/rigor/type/refined.rb', line 85 def inspect "#<Rigor::Type::Refined #{describe(:short)}>" end |
#matches?(value) ⇒ Boolean
Recognises a Ruby value against this carrier’s predicate. The trinary return is intentional: ‘true` / `false` when the predicate registry decides, `nil` when the predicate is unknown to the registry, so callers (today Inference::Acceptance) can fall through to gradual-mode `:maybe`. rubocop:disable Style/ReturnNilInPredicateMethodDefinition
96 97 98 99 100 101 |
# File 'lib/rigor/type/refined.rb', line 96 def matches?(value) recogniser = PREDICATES[predicate_id] return nil if recogniser.nil? !!recogniser.call(value) end |