Class: LazyGraph::ObjectNode

Inherits:
Node
  • Object
show all
Defined in:
lib/lazy_graph/node/object_node.rb,
lib/lazy_graph/node/symbol_hash.rb

Defined Under Namespace

Classes: SymbolHash

Constant Summary

Constants included from Node::DerivedRules

Node::DerivedRules::PLACEHOLDER_VAR_REGEX

Instance Attribute Summary

Attributes inherited from Node

#children, #depth, #derived, #invisible, #is_object, #name, #parent, #path, #root, #type

Instance Method Summary collapse

Methods inherited from Node

#absolute_path, #ancestors, #clear_visits!, #copy_item!, #define_missing_value_proc!, #derive_item!, #fetch_item, #initialize, #lazy_init_node!, #resolve_input

Methods included from Node::DerivedRules

#build_derived_inputs, #create_derived_input_context, #extract_derived_src, extract_expr_from_source_location, #interpret_derived_proc, #map_derived_inputs_to_paths, #parse_args_with_conditions, #parse_derived_inputs, #parse_rule_string

Constructor Details

This class inherits a constructor from LazyGraph::Node

Instance Method Details

#children=(value) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/lazy_graph/node/object_node.rb', line 88

def children=(value)
  @children = value

  @properties = @children.fetch(:properties, {})
  @properties.compare_by_identity
  @pattern_properties = @children.fetch(:pattern_properties, [])

  @properties_a = @properties.to_a

  @has_properties = @properties.any? || @pattern_properties.any?

  return unless @properties.any? || @pattern_properties.any?

  if @pattern_properties.any?
    @property_class = SymbolHash
  else
    invisible = @properties.select { |_k, v| v.invisible }.map(&:first)
    @property_class = PROPERTY_CLASSES[{ members: @properties.keys + (@debug && !parent ? [:DEBUG] : []),
                                         invisible: invisible }]
  end
  define_singleton_method(:cast, build_caster)
end

#find_resolver_for(segment) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/lazy_graph/node/object_node.rb', line 78

def find_resolver_for(segment)
  if segment == :'$'
    root
  elsif @properties.key?(segment)
    self
  else
    @parent&.find_resolver_for(segment)
  end
end

#resolve(path, stack_memory, should_recycle = stack_memory, preserve_keys: false) ⇒ Object

An object supports the following types of path resolutions.

  1. Property name: obj.property => value

  2. Property name group: obj[property1, property2] => { property1: value1, property2: value2 }

  3. All [*]



9
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
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
69
70
71
72
73
74
75
76
# File 'lib/lazy_graph/node/object_node.rb', line 9

def resolve(
  path,
  stack_memory,
  should_recycle = stack_memory,
  preserve_keys: false
)
  input = stack_memory.frame

  @visited[input.object_id >> 2 ^ path.shifted_id] ||= begin
    return input if input.is_a?(MissingValue)

    if (path_segment = path.segment).is_a?(PathParser::PathGroup)
      return path_segment.options.each_with_object({}.tap(&:compare_by_identity)) do |part, object|
        resolve(part.merge(path.next), stack_memory, nil, preserve_keys: object)
      end
    end

    if !segment = path_segment&.part
      @properties_a.each do |key, node|
        item = node.fetch_item(input, key, stack_memory)
        node.resolve(path.next, stack_memory.push(item, key))
      end
      if @pattern_properties.any? && input.keys.length > @properties_a.length
        input.each_key do |key|
          node = !@properties[key] && @pattern_properties.find { |(pattern, _value)| pattern.match?(key) }&.last
          item = node.fetch_item(input, key, stack_memory)
          node.resolve(path.next, stack_memory.push(item, key))
        end
      end
      input
    elsif (prop = @properties[segment])
      item = prop.fetch_item(input, segment, stack_memory)
      value = prop.resolve(
        path.next, stack_memory.push(item, segment)
      )
      preserve_keys ? preserve_keys[segment] = value : value
    elsif segment == :*
      # rubocop:disable
      (input.keys | @properties_a.map(&:first)).each do |key|
        next unless (node = @properties[key] || @pattern_properties.find do |(pattern, _value)|
          pattern.match?(key)
        end&.last)

        item = node.fetch_item(input, key, stack_memory)
        preserve_keys[key] = node.resolve(path.next, stack_memory.push(item, key))
      end
    elsif (_, prop = @pattern_properties.find { |(key, _val)| key.match?(segment) })
      item = prop.fetch_item(input, segment, stack_memory)
      value = prop.resolve(
        path.next, stack_memory.push(item, segment)
      )
      preserve_keys ? preserve_keys[segment] = value : value
    elsif input.key?(segment)
      prop = @properties[segment] = lazy_init_node!(input[segment], segment)
      @properties_a = @properties.to_a
      item = prop.fetch_item(input, segment, stack_memory)
      value = prop.resolve(
        path.next, stack_memory.push(item, segment)
      )
      preserve_keys ? preserve_keys[segment] = value : value
    else
      value = MissingValue()
      preserve_keys ? preserve_keys[segment] = value : value
    end
  end
ensure
  should_recycle&.recycle!
end