Class: HashTree::Node
- Inherits:
-
Object
- Object
- HashTree::Node
- Defined in:
- lib/hash_tree.rb
Overview
The base Node type for HashTree implementations. It is not supposed to be called from user-code
Instance Attribute Summary collapse
-
#children ⇒ Object
readonly
Hash from key to child node.
-
#parent ⇒ Object
readonly
Parent node.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Lookup node by key.
-
#aggregate(filter = lambda { |node| true }, &block) ⇒ Object
EXPERIMENTAL.
-
#ancestors(include_self = false) ⇒ Object
List of parents from the root element down to parent.
-
#attach(key, child) ⇒ Object
Attach a child to self.
-
#detach(key, ignore_not_attached: false) ⇒ Object
Detach a child from self.
-
#dot(path_or_keys, raise_on_not_found: true) ⇒ Object
Recursively lookup object by dot-separated list of keys.
-
#dot?(path_or_keys) ⇒ Boolean
True if path_or_keys address a node.
-
#each(&block) ⇒ Object
List of [key, child] tuples.
-
#initialize(parent, key, attach: true) ⇒ Node
constructor
A new instance of Node.
-
#key?(key) ⇒ Boolean
Returns true iff key is included in children.
-
#keys ⇒ Object
List of keys.
-
#parents(include_self = false) ⇒ Object
List of parents up to the root element.
-
#postorder ⇒ Object
Return list of nodes in postorder.
-
#preorder ⇒ Object
Return list of nodes in preorder.
-
#root ⇒ Object
The root object or self if parent is nil.
-
#traverse(&block) ⇒ Object
EXPERIMENTAL.
-
#values ⇒ Object
List of values.
Constructor Details
#initialize(parent, key, attach: true) ⇒ Node
Returns a new instance of Node.
45 46 47 48 49 50 51 52 |
# File 'lib/hash_tree.rb', line 45 def initialize(parent, key, attach: true) @children = {} if attach parent&.do_attach(key, self) else @parent = parent end end |
Instance Attribute Details
#children ⇒ Object (readonly)
Hash from key to child node
43 44 45 |
# File 'lib/hash_tree.rb', line 43 def children @children end |
#parent ⇒ Object (readonly)
Parent node. nil for the root node
40 41 42 |
# File 'lib/hash_tree.rb', line 40 def parent @parent end |
Instance Method Details
#[](key) ⇒ Object
Lookup node by key
71 |
# File 'lib/hash_tree.rb', line 71 def [](key) @children[key] end |
#aggregate(filter = lambda { |node| true }, &block) ⇒ Object
EXPERIMENTAL
Process nodes in postorder (bottom-up). The block is called with the current node and a list of aggregated children. The optional filter argument is a lambda. The lambda is called with the current node as argument and the node if skipped if the lambda returns falsy
154 155 156 157 158 159 160 |
# File 'lib/hash_tree.rb', line 154 def aggregate(filter = lambda { |node| true }, &block) if filter.nil? || filter.call(self) yield(self, values.map { |child| child.aggregate(filter, &block) }.compact) else nil end end |
#ancestors(include_self = false) ⇒ Object
List of parents from the root element down to parent. If include_self is true, also include self as the last element
93 94 95 |
# File 'lib/hash_tree.rb', line 93 def ancestors(include_self = false) (@ancestors ||= parents(false).reverse) + (include_self ? [self] : []) end |
#attach(key, child) ⇒ Object
Attach a child to self
Implementation is in #do_attach to share code with HashTree::Set#attach that only takes one parameters
58 |
# File 'lib/hash_tree.rb', line 58 def attach(key, child) do_attach(key, child) end |
#detach(key, ignore_not_attached: false) ⇒ Object
Detach a child from self
61 62 63 64 65 66 67 68 |
# File 'lib/hash_tree.rb', line 61 def detach(key, ignore_not_attached: false) @children.key?(key) or raise Error, "Non-existing child key: #{key.inspect}" child = children[key] ignore_not_attached || child.parent or raise Error, "Child is not attached" child.instance_variable_set(:@parent, nil) @children.delete(key) child.send(:clear_cached_properties) end |
#dot(path_or_keys, raise_on_not_found: true) ⇒ Object
Recursively lookup object by dot-separated list of keys. Note that for this to work, key names must not contain dot characters (‘.’)
The reverse method, #path, is only defined for HashTree::Set because a HashTree::Map node doesn’t know its own key
102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/hash_tree.rb', line 102 def dot(path_or_keys, raise_on_not_found: true) keys = path_or_keys.is_a?(String) ? path_or_keys.split(".") : path_or_keys key = keys.shift or return self if child = dot_lookup(key) child.send(:dot, keys, raise_on_not_found: raise_on_not_found) elsif raise_on_not_found raise KeyNotFound, "Can't lookup '#{key}' in #{self.path.inspect}" else nil end end |
#dot?(path_or_keys) ⇒ Boolean
True if path_or_keys address a node
115 116 117 |
# File 'lib/hash_tree.rb', line 115 def dot?(path_or_keys) !dot(path_or_keys, raise_on_not_found: false).nil? end |
#each(&block) ⇒ Object
List of [key, child] tuples
120 121 122 123 124 125 126 |
# File 'lib/hash_tree.rb', line 120 def each(&block) if block_given? children.each { |key, child| yield(key, child) } else children.each end end |
#key?(key) ⇒ Boolean
Returns true iff key is included in children
74 |
# File 'lib/hash_tree.rb', line 74 def key?(key) @children.key?(key) end |
#keys ⇒ Object
List of keys
77 |
# File 'lib/hash_tree.rb', line 77 def keys() @children.keys end |
#parents(include_self = false) ⇒ Object
List of parents up to the root element. If include_self is true, also include self as the first element
87 88 89 |
# File 'lib/hash_tree.rb', line 87 def parents(include_self = false) (include_self ? [self] : []) + (@parents ||= (parent&.parents(true) || [])) end |
#postorder ⇒ Object
Return list of nodes in postorder
134 135 136 |
# File 'lib/hash_tree.rb', line 134 def postorder values.inject([]) { |a,e| a + e.postorder } + [self] end |
#preorder ⇒ Object
Return list of nodes in preorder
129 130 131 |
# File 'lib/hash_tree.rb', line 129 def preorder [self] + values.inject([]) { |a,e| a + e.preorder } end |
#root ⇒ Object
The root object or self if parent is nil
83 |
# File 'lib/hash_tree.rb', line 83 def root() @root ||= (parent&.root || self) end |
#traverse(&block) ⇒ Object
EXPERIMENTAL
Process nodes in preorder. The block is called with the current node as argument and can return true to process its child nodes or false or nil to skip them. #traverse doesn’t accumulate a result, this is the responsibily of the block
144 145 146 |
# File 'lib/hash_tree.rb', line 144 def traverse(&block) values.each { |child| child.traverse(&block) } if yield(self) end |
#values ⇒ Object
List of values
80 |
# File 'lib/hash_tree.rb', line 80 def values() @children.values end |