Class: Kumi::Core::Compiler::Accessors::RavelAccessor

Inherits:
Object
  • Object
show all
Extended by:
Base
Defined in:
lib/kumi/core/compiler/accessors/ravel_accessor.rb

Overview

Ravel: collect leaf elements reached by the op sequence. Invariants guaranteed by the planner for :ravel:

  • Every array edge along the path has an :enter_array op.

  • If the leaf container is an array, a terminal :enter_array is appended, so the leaf we see here is the element, not the array.

Constant Summary

Constants included from Base

Base::MISSING

Class Method Summary collapse

Methods included from Base

assert_array!, assert_hash!, fetch_key, missing_array_action, missing_key_action, next_enters_array?, warn_mismatch

Class Method Details

.build(operations, path_key, policy, key_policy) ⇒ Object



15
16
17
18
19
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kumi/core/compiler/accessors/ravel_accessor.rb', line 15

def self.build(operations, path_key, policy, key_policy)
  mode = :ravel

  lambda do |data|
    out = []

    walk = nil
    walk = lambda do |node, pc|
      # Leaf: ops exhausted ⇒ emit this element (scalar/object/array element).
      if pc >= operations.length
        out << node
        return
      end

      op = operations[pc]
      case op[:type]
      when :enter_hash
        # If the next step is an array, we don’t care about key symbol/string
        # (we’ll just iterate) → use indifferent lookup.
        preview_array = next_enters_array?(operations, pc)
        policy_for = preview_array ? :indifferent : key_policy

        next_node = fetch_key(node, op[:key], policy_for)
        if next_node == Base::MISSING
          case missing_key_action(policy)
          when :yield_nil then out << nil
          when :skip      then return
          when :raise     then raise KeyError, "Missing key '#{op[:key]}' at '#{path_key}' (#{mode})"
          end
          return
        end
        walk.call(next_node, pc + 1)

      when :enter_array
        if node.nil?
          case missing_array_action(policy)
          when :yield_nil then out << nil
          when :skip      then return
          when :raise     then raise KeyError, "Missing array at '#{path_key}' (#{mode})"
          end
          return
        end
        assert_array!(node, path_key, mode)
        node.each { |child| walk.call(child, pc + 1) }

      else
        raise "Unknown operation: #{op.inspect}"
      end
    end

    walk.call(data, 0)
    out
  end
end