Module: Hecks::Rendering

Defined in:
lib/hecks/rendering.rb

Overview

HOW A VALUE READS INSIDE A REFUSAL, in one place, because a refusal is an ANSWER and its wording is contract — pinned byte-for-byte by the corpus.

inspect and JSON agree on scalars and disagree on everything composite : a hash is {"cents"=>100} against {"cents":100}, an array is ["a", "b"] against ["a","b"]. Each such spelling is invisible until a composite actually reaches a message, which is why both known cases were found by something deliberately passing the wrong shape rather than by review — the first by hand in spec/corpus/banking.json, the second by bin/fuzz, at a different site, after the first was patched where it was found.

So it lives here rather than in whichever file noticed it, and the house style is JSON because that is what every other refusal in the corpus already prints.

Class Method Summary collapse

Class Method Details

.describe(value) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/hecks/rendering.rb', line 20

def describe(value)
  case value
  when nil then "nil"
  when Hash, Array then JSON.generate(value)
  else
    # A Hecks::Runtime::Value reaching a refusal message (an
    # arithmetic op's own `amount`/`current`, an Admissibility
    # `current`, ...) had no case here, falling straight through to
    # Ruby's own #inspect and leaking a raw object pointer
    # ("#<Hecks::Runtime::Value:0x...>") into an otherwise
    # correct domain refusal. Duck-typed on `respond_to?(:to_h)`
    # rather than naming `Runtime::Value` directly — `Runtime::Value`
    # itself requires THIS file (`runtime/value.rb`'s own
    # `require_relative "../rendering"`), so naming it here would be
    # circular. A single-field wrapper (the overwhelming common case
    # — an amount, an id, a lifecycle field) unwraps to its bare
    # scalar, described recursively; a genuinely multi-field value
    # renders as its fields' JSON, same as a bare Hash already does
    # two lines up.
    if value.respond_to?(:to_h) && !value.is_a?(Hash) && !value.is_a?(Array)
      fields = value.to_h
      fields.size == 1 ? describe(fields.values.first) : JSON.generate(fields)
    else
      value.inspect
    end
  end
end