Class: Plumb::Or

Inherits:
Object
  • Object
show all
Includes:
Composable, Disjunction
Defined in:
lib/plumb/or.rb

Overview

LEFT-BIASED CHOICE — try left, fall back to right, built by Composable#| when some branch changes the value. The all-branches-preserving case (a genuine set union) is Union; see Disjunction.

A choice's ends differ, because a converting branch accepts an input the join of the outputs would reject: Integer | String.transform(:to_i) consumes Integer | String and produces Integer | Integer.

Instance Attribute Summary

Attributes included from Disjunction

#children

Instance Method Summary collapse

Methods included from Disjunction

build, #call, #initialize, #input_type, merge_errors, #with_children

Methods included from Composable

#&, #/, #>>, #[], #absorb_input, #absorb_output, #accepted_type, #as_node, #build, #check, #children, #defer, #fusable_step?, #fuse_with, #generate, #idempotent?, included, #input_type, #invalid, #invoke, #match, #metadata, #not, #pipeline, #policy, resolve_operand, #static, #subtype_identity, #to_json_schema, #to_mermaid, #to_plumb_type, #to_s, #transform, #value, #where, #with, wrap, #|

Methods included from Callable

#call, #parse, #resolve

Instance Method Details

#output_typeObject

(A | B).output_type == A.output_type | B.output_type. A converting branch produces something other than what it consumed, so this genuinely has to map over the branches — which is exactly what Union does NOT have to do. #input_type is shared with Union; see Disjunction#input_type.



22
23
24
25
26
# File 'lib/plumb/or.rb', line 22

def output_type
  l = @left.output_type
  r = @right.output_type
  l.equal?(@left) && r.equal?(@right) ? self : Disjunction.build(l, r)
end

#value_preserving?Boolean

A disjunction preserves the value only if EVERY branch does — a branch that transforms (a coercion) changes it when taken. Recurses through the cached accessor so shared subtrees are memoized once.

Kept computed rather than hardcoded false: Disjunction.build only routes the converting case here, but Or.new remains callable directly (the Decorator rebuilds by class), so an Or may still hold two preserving branches.

Returns:

  • (Boolean)


35
# File 'lib/plumb/or.rb', line 35

def value_preserving? = children.all? { |c| Plumb::Subtyping.value_preserving?(c) }