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.
27 28 29 |
# File 'lib/sycamore/path.rb', line 27 def node @node end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
27 28 29 |
# File 'lib/sycamore/path.rb', line 27 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.
62 63 64 65 66 67 68 |
# File 'lib/sycamore/path.rb', line 62 def self.of(*args) if (parent = args.first).is_a? Path parent.branch(*args[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.
225 226 227 228 229 |
# File 'lib/sycamore/path.rb', line 225 def ==(other) other.is_a?(Enumerable) and 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.
97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/sycamore/path.rb', line 97 def branch(*nodes) return branch(*nodes.first) if nodes.size == 1 && 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.
161 162 163 164 165 166 167 168 |
# File 'lib/sycamore/path.rb', line 161 def each_node(&block) return enum_for(__callee__) unless block 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.
214 215 216 217 218 219 |
# File 'lib/sycamore/path.rb', line 214 def eql?(other) other.is_a?(self.class) and length == other.length and begin i = other.each; all? { |node| node.eql? i.next } end end |
#hash ⇒ Fixnum
Returns hash code for this path.
206 207 208 |
# File 'lib/sycamore/path.rb', line 206 def hash to_a.hash ^ self.class.hash end |
#inspect ⇒ String
Returns a more verbose string representation of this path.
260 261 262 |
# File 'lib/sycamore/path.rb', line 260 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.
246 247 248 |
# File 'lib/sycamore/path.rb', line 246 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.
144 145 146 147 148 |
# File 'lib/sycamore/path.rb', line 144 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.
183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/sycamore/path.rb', line 183 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.
137 138 139 |
# File 'lib/sycamore/path.rb', line 137 def root? false end |
#to_s ⇒ String
Returns a compact string representation of this path.
253 254 255 |
# File 'lib/sycamore/path.rb', line 253 def to_s "#<Path: #{join}>" end |
#up(distance = 1) ⇒ Path
Returns the n-th last parent path.
123 124 125 126 127 128 129 130 131 132 |
# File 'lib/sycamore/path.rb', line 123 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 |