Class: RichText::Node
- Inherits:
-
Object
- Object
- RichText::Node
- Includes:
- Enumerable
- Defined in:
- lib/richtext/node.rb
Overview
Node
A Node can have children, which themselvs can have children. A tree like structure can thus be formed by composing multiple Nodes. An example of such a tree structure can be seen below.
The Node class implements some convenience methods for iterating, left to right, over either all
- nodes in the tree
- leafs in the tree
- direct decendant of a node
In addition to having children a Node can also have attributes, represented by simple key => value pairs.
Example Tree
+--------------------------+
A <- Root Node | Left to right order: ABC |
/ \ +--------------------------+
Leaf Node -> B C <- Child to A
(no children) /|\
...
Direct Known Subclasses
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Returns the value of attribute attributes.
Instance Method Summary collapse
-
#+(other) ⇒ Object
Add (+).
-
#<<(child) ⇒ Object
Append.
-
#==(other) ⇒ Object
Deep equality (include children).
-
#[](attribute) ⇒ Object
Attribute accessor.
- #[]=(attribute, value) ⇒ Object
-
#count ⇒ Object
Count.
-
#create_child(**attributes) ⇒ Object
Create Child.
-
#each {|_self| ... } ⇒ Object
Each.
-
#each_child(&block) ⇒ Object
Each child.
-
#each_leaf(&block) ⇒ Object
Each Leaf.
-
#equal?(other) ⇒ Boolean
Shallow equality (exclude children).
-
#initialize(**attributes) ⇒ Node
constructor
A new instance of Node.
- #initialize_copy(original) ⇒ Object
- #inspect ⇒ Object
-
#leaf? ⇒ Boolean
Leaf?.
-
#minimal? ⇒ Boolean
Minimal?.
- #optimize ⇒ Object
-
#optimize! ⇒ Object
Optimize!.
-
#size ⇒ Object
Size.
Constructor Details
#initialize(**attributes) ⇒ Node
31 32 33 34 |
# File 'lib/richtext/node.rb', line 31 def initialize(**attributes) @children = [] @attributes = attributes end |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Returns the value of attribute attributes.
28 29 30 |
# File 'lib/richtext/node.rb', line 28 def attributes @attributes end |
Instance Method Details
#+(other) ⇒ Object
Add (+)
Combines two nodes by creating a new root and adding the two as children.
77 78 79 |
# File 'lib/richtext/node.rb', line 77 def +(other) self.class.new.tap { |root| root << self << other } end |
#<<(child) ⇒ Object
Append
Add a child to the end of the node child list. The child must be of this class to be accepted. Note that subclasses of Node will not accept regular Nodes. The method returns self so that multiple children can be added via chaining:
root << child_a << child_b
55 56 57 58 59 60 61 62 63 |
# File 'lib/richtext/node.rb', line 55 def <<(child) unless child.is_a? self.class raise TypeError, "Only objects of class #{self.class.name} can be appended" end @children << child self end |
#==(other) ⇒ Object
Deep equality (include children)
Returns true if the other node has the same attributes and its children are also identical.
200 201 202 203 204 205 206 |
# File 'lib/richtext/node.rb', line 200 def ==(other) # First make sure the nodes child count matches return false unless equal? other # Lastly make sure all of the children are equal each_child.zip(other.each_child).all? { |c| c[0] == c[1] } end |
#[](attribute) ⇒ Object
Attribute accessor
Read and write an attribute of the node. Attributes are simply key-value pairs stored internally in a hash.
123 124 125 |
# File 'lib/richtext/node.rb', line 123 def [](attribute) @attributes[attribute] end |
#[]=(attribute, value) ⇒ Object
127 128 129 |
# File 'lib/richtext/node.rb', line 127 def []=(attribute, value) @attributes[attribute] = value end |
#count ⇒ Object
Count
Returns the child count of this node.
134 135 136 |
# File 'lib/richtext/node.rb', line 134 def count @children.size end |
#create_child(**attributes) ⇒ Object
Create Child
Create and append a new child, initialized with the given attributes.
68 69 70 71 72 |
# File 'lib/richtext/node.rb', line 68 def create_child(**attributes) child = self.class.new(**attributes) self << child child end |
#each {|_self| ... } ⇒ Object
Each
Iterate over each node in the tree, including self.
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/richtext/node.rb', line 84 def each(&block) return to_enum(__callee__) unless block_given? yield self @children.each do |child| yield child child.each(&block) unless child.leaf? end end |
#each_child(&block) ⇒ Object
Each child
Iterate over the children of this node.
115 116 117 |
# File 'lib/richtext/node.rb', line 115 def each_child(&block) @children.each(&block) end |
#each_leaf(&block) ⇒ Object
Each Leaf
Iterate over each leaf in the tree. This method will yield the leaf nodes of the tree from left to right.
99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/richtext/node.rb', line 99 def each_leaf(&block) return to_enum(__callee__) unless block_given? return yield self if leaf? @children.each do |child| if child.leaf? yield child else child.each_leaf(&block) end end end |
#equal?(other) ⇒ Boolean
Shallow equality (exclude children)
Returns true if the other node has the exact same attributes.
192 193 194 |
# File 'lib/richtext/node.rb', line 192 def equal?(other) count == other.count && @attributes == other.attributes end |
#initialize_copy(original) ⇒ Object
36 37 38 39 |
# File 'lib/richtext/node.rb', line 36 def initialize_copy(original) @children = original.children.map(&:dup) @attributes = original.attributes.dup end |
#inspect ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/richtext/node.rb', line 208 def inspect children = @children.reduce('') do |s, c| s + "\n" + c.inspect.gsub(/(^)/) { |m| m + ' ' } end format '#<%{name} %<attrs>p:%<id>#x>%{children}', name: self.class.name, id: object_id, attrs: @attributes, children: children end |
#leaf? ⇒ Boolean
Leaf?
Returns true if this node a leaf (childless) node.
44 45 46 |
# File 'lib/richtext/node.rb', line 44 def leaf? @children.empty? end |
#minimal? ⇒ Boolean
Minimal?
Test if the tree under this node is minimal or not. A non minimal tree contains children which themselvs only have one child.
149 150 151 |
# File 'lib/richtext/node.rb', line 149 def minimal? all? { |node| node.count != 1 } end |
#optimize ⇒ Object
185 186 187 |
# File 'lib/richtext/node.rb', line 185 def optimize dup.optimize! end |
#optimize! ⇒ Object
Optimize!
Go through each child and merge any node that a) is not a lead node and b) only has one child, with its child. The attributes of the child will override those of the parent.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/richtext/node.rb', line 158 def optimize! # If the node is a leaf it cannot be optimized further return self if leaf? # First optimize each of the children. If a block was # given each child will be yielded to it, and children # for which the block returns false will be removed if block_given? @children.select! { |child| yield child.optimize! } else @children.map(&:optimize!) end # If we only have one child it is superfluous and # should be merged. That means this node will inherrit # the children of the single child as well as its # attributes if count == 1 child = @children[0] # Move the children over @children = child.children @attributes.merge! child.attributes end self end |
#size ⇒ Object
Size
Returns the size of the tree where this node is the root.
141 142 143 |
# File 'lib/richtext/node.rb', line 141 def size @children.reduce(1) { |a, e| a + e.size } end |