Class: Sycamore::Path
- Inherits:
-
Object
- Object
- Sycamore::Path
- Extended by:
- Forwardable
- Includes:
- Enumerable
- Defined in:
- lib/sycamore/path.rb,
lib/sycamore/path_root.rb
Overview
Measure the performance and memory consumption in comparison with a pure Array-based implementation (where tree nodes are duplicated), esp. in the most common use case of property-value structures.
A compact, immutable representation of Tree paths, i.e. node sequences.
This class is optimized for its usage in Tree#each_path, where it can efficiently represent the whole tree as a set of paths by sharing the parent paths. It is not intended to be instantiated by the user.
Direct Known Subclasses
Defined Under Namespace
Classes: Root
Constant Summary collapse
- ROOT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Root.instance
Instance Attribute Summary collapse
-
#node ⇒ Object
readonly
Returns the value of attribute node.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
Construction collapse
-
.of(*args) ⇒ Object
(also: [])
Creates a new path.
-
.root ⇒ Object
The root of all Paths.
Elements collapse
-
#branch(*nodes) ⇒ Path
(also: #+, #/)
Returns a new path based on this path, but with the given nodes extended.
-
#each_node(&block) ⇒ Object
(also: #each)
Iterates over all nodes on this path.
-
#length ⇒ Integer
(also: #size)
The number of nodes on this path.
-
#present_in?(struct) ⇒ Boolean
(also: #in?)
If a given structure contains this path.
-
#root? ⇒ Boolean
If this is the root path.
-
#up(distance = 1) ⇒ Path
The n-th last parent path.
Equality collapse
-
#==(other) ⇒ Boolean
If the other is an Enumerable with the same nodes in the same order.
-
#eql?(other) ⇒ Boolean
If the other is a Path with the same nodes in the same order.
-
#hash ⇒ Fixnum
Hash code for this path.
Conversion collapse
-
#inspect ⇒ String
A more verbose string representation of this path.
-
#join(separator = '/') ⇒ String
A string created by converting each node on this path to a string, separated by the given separator.
-
#to_s ⇒ String
A compact string representation of this path.
Instance Attribute Details
#node ⇒ Object (readonly)
Returns the value of attribute node.
28 29 30 |
# File 'lib/sycamore/path.rb', line 28 def node @node end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
28 29 30 |
# File 'lib/sycamore/path.rb', line 28 def parent @parent end |
Class Method Details
.of(path, nodes) ⇒ Path .of(nodes) ⇒ Path Also known as: []
Creates a new path.
Depending on whether the first argument is a Sycamore::Path, the new Path is #branched from this path or the root.
63 64 65 66 67 68 69 |
# File 'lib/sycamore/path.rb', line 63 def self.of(*args) if (parent = args.first).is_a? Path parent.branch(*args[1..-1]) else root.branch(*args) end end |
Instance Method Details
#==(other) ⇒ Boolean
Returns if the other is an Enumerable with the same nodes in the same order.
226 227 228 229 230 |
# File 'lib/sycamore/path.rb', line 226 def ==(other) other.is_a?(Enumerable) and self.length == other.length and begin i = other.each ; all? { |node| node == i.next } end end |
#branch(*nodes) ⇒ Path Also known as: +, /
Returns a new path based on this path, but with the given nodes extended.
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/sycamore/path.rb', line 98 def branch(*nodes) return branch(*nodes.first) if nodes.size == 1 and nodes.first.is_a? Enumerable parent = self nodes.each do |node| raise InvalidNode, "#{node} in Path #{nodes.inspect} is not a valid tree node" if node.is_a? Enumerable parent = Path.__send__(:new, parent, node) end parent end |
#each_node {|node| ... } ⇒ Object #each_node ⇒ Enumerator<node> Also known as: each
Iterates over all nodes on this path.
162 163 164 165 166 167 168 169 |
# File 'lib/sycamore/path.rb', line 162 def each_node(&block) return enum_for(__callee__) unless block_given? if @parent @parent.each_node(&block) yield @node end end |
#eql?(other) ⇒ Boolean
Returns if the other is a Path with the same nodes in the same order.
215 216 217 218 219 220 |
# File 'lib/sycamore/path.rb', line 215 def eql?(other) other.is_a?(self.class) and self.length == other.length and begin i = other.each ; all? { |node| node.eql? i.next } end end |
#hash ⇒ Fixnum
Returns hash code for this path.
207 208 209 |
# File 'lib/sycamore/path.rb', line 207 def hash to_a.hash ^ self.class.hash end |
#inspect ⇒ String
Returns a more verbose string representation of this path.
261 262 263 |
# File 'lib/sycamore/path.rb', line 261 def inspect "#<Sycamore::Path[#{each_node.map(&:inspect).join(',')}]>" end |
#join(separator = '/') ⇒ String
Since the root path with no node is at the beginning of each path, the returned string always begins with the given separator.
Returns a string created by converting each node on this path to a string, separated by the given separator.
247 248 249 |
# File 'lib/sycamore/path.rb', line 247 def join(separator = '/') @parent.join(separator) + separator + node.to_s end |
#length ⇒ Integer Also known as: size
Returns the number of nodes on this path.
145 146 147 148 149 |
# File 'lib/sycamore/path.rb', line 145 def length i, parent = 1, self i += 1 until (parent = parent.parent).root? i end |
#present_in?(struct) ⇒ Boolean Also known as: in?
If a given structure contains this path.
184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/sycamore/path.rb', line 184 def present_in?(struct) each do |node| case when struct.is_a?(Enumerable) return false unless struct.include? node struct = (Tree.like?(struct) ? struct[node] : Nothing ) else return false unless struct.eql? node struct = Nothing end end true end |
#root? ⇒ Boolean
Returns if this is the root path.
138 139 140 |
# File 'lib/sycamore/path.rb', line 138 def root? false end |
#to_s ⇒ String
Returns a compact string representation of this path.
254 255 256 |
# File 'lib/sycamore/path.rb', line 254 def to_s "#<Path: #{join}>" end |
#up(distance = 1) ⇒ Path
Returns the n-th last parent path.
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/sycamore/path.rb', line 124 def up(distance = 1) raise TypeError, "expected an integer, but got #{distance.inspect}" unless distance.is_a? Integer case distance when 1 then @parent when 0 then self else parent.up(distance - 1) end end |