Class: Kumi::Core::Compiler::Accessors::EachIndexedAccessor

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

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, with_indices = true) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/kumi/core/compiler/accessors/each_indexed_accessor.rb', line 10

def self.build(operations, path_key, policy, key_policy, with_indices = true)
  walker = build_each_walker(operations, path_key, policy, key_policy)
  if with_indices
    lambda do |data, &blk|
      if blk
        walker.call(data, 0, [], ->(val, idx) { blk.call(val, idx) })
        nil
      else
        out = []
        walker.call(data, 0, [], ->(val, idx) { out << [val, idx] })
        out
      end
    end
  else
    lambda do |data, &blk|
      if blk
        walker.call(data, 0, [], ->(val, _idx) { blk.call(val) })
        nil
      else
        out = []
        walker.call(data, 0, [], ->(val, _idx) { out << val })
        out
      end
    end
  end
end

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

Depth-first traversal yielding (value, nd_index)



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
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/kumi/core/compiler/accessors/each_indexed_accessor.rb', line 38

def self.build_each_walker(operations, path_key, policy, key_policy)
  mode = :each_indexed
  walk = nil
  walk = lambda do |node, pc, ndx, y|
    if pc >= operations.length
      y.call(node, ndx)
      return
    end

    op = operations[pc]
    case op[:type]
    when :enter_hash
      # If the *next* op is an array hop, relax to indifferent for that fetch
      policy_for = next_enters_array?(operations, pc) ? :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 y.call(nil, ndx)
        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, ndx, y)

    when :enter_array
      if node.nil?
        case missing_array_action(policy)
        when :yield_nil then y.call(nil, ndx)
        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_with_index { |child, i| walk.call(child, pc + 1, ndx + [i], y) }

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