Module: Plumb::Implementation::TypeInterface

Includes:
TypedStep
Defined in:
lib/plumb/implementation.rb

Overview

The typed-node interface, shared by both paths. The OTHER implementation of TypedStep — same contract as Function, differing only in that the host owns the object, so the declared pair comes from the mixin and the core is reached through the host's private #_call.

Instance Method Summary collapse

Methods included from TypedStep

#accepted_type, #checks_output?, #fusable_step?, #opaque?, #subtype_identity

Instance Method Details

#_call(_result) ⇒ Result

The value-level contract, implemented by the host (privately, by convention — it is the inside of #call, not part of the step interface).

Parameters:

  • result (Result)

    already validated against #input_type

Returns:

  • (Result)

    validated against #output_type by #call

Raises:

  • (NotImplementedError)


215
216
217
218
# File 'lib/plumb/implementation.rb', line 215

def _call(_result)
  raise NotImplementedError,
        "Implement #{is_a?(::Module) ? 'self.' : '#'}_call(Plumb::Result) => Plumb::Result in #{_host_name}"
end

#call(result) ⇒ Result

The step interface, owned by the mixin: the declared checks around the host's #_call. Included AFTER Composable, so this is the #call that runs (Callable#call, the "implement me" stub, sits behind it).

Parameters:

Returns:



166
167
168
169
170
171
# File 'lib/plumb/implementation.rb', line 166

def call(result)
  result = result.map(input_type)
  return result if result.invalid?

  _checked_call(result).map(output_type)
end

#childrenObject

Visitors (and Composable#==) read a node's children. Computed, unlike Function's frozen ivar — the host owns its constructor, so there is no #initialize here to build one in.



223
# File 'lib/plumb/implementation.rb', line 223

def children = [input_type, output_type]

#fnObject

The middle of #call — the host's #_call plus the contract check on what it returned — as a Result => Result callable, which is exactly what a Function's fn is. Exposing it is what lets a chain of Implementations FUSE: Length.new >> Double.new collapses to a single Function running both, instead of an And re-checking Integer at the seam.

A fresh Method object per call, so read it at COMPOSITION time only (as #fuse_with does), never per value.



181
# File 'lib/plumb/implementation.rb', line 181

def fn = method(:_checked_call)

#fuse_with(other) ⇒ Object

Fuse forwards through a temporary Function — the same input -> fn -> output shape this node already runs, so Function#fuse_with's proofs hold verbatim and there is no second implementation of them to keep in step.



194
195
196
197
198
# File 'lib/plumb/implementation.rb', line 194

def fuse_with(other)
  return nil unless fusable_step?

  Plumb::Function.new(input_type, output_type, fn, identity:).fuse_with(other)
end

#identityObject

What this step IS, for Function#== once fused: the host itself, so two fused chains compare by whatever equality the host defines.



185
# File 'lib/plumb/implementation.rb', line 185

def identity = self

#standard_call?Boolean

This family's canonical #call is the one defined above, so a host that replaced it runs different checks. @see Plumb::TypedStep#fusable_step?

Returns:

  • (Boolean)


189
# File 'lib/plumb/implementation.rb', line 189

def standard_call? = method(:call).owner.equal?(TypeInterface)