Class: Astrolabe::Node
- Inherits:
-
Parser::AST::Node
- Object
- Parser::AST::Node
- Astrolabe::Node
- Defined in:
- lib/astrolabe/node.rb
Overview
Astrolabe::Node
is a subclass of Parser::AST::Node
. It provides an access to parent node and
an object-oriented way to handle AST with the power of Enumerable
.
Though not described in the auto-generated API documentation, it has predicate methods for every
node type. These methods would be useful especially when combined with Enumerable
methods.
Instance Method Summary collapse
-
#ancestors ⇒ Array<Node>
Returns an array of ancestor nodes.
-
#child_nodes ⇒ Array<Node>
Returns an array of child nodes.
-
#descendants ⇒ Array<Node>
Returns an array of descendant nodes.
-
#each_ancestor(*types) {|node| ... } ⇒ self, Enumerator
Calls the given block for each ancestor node in the order from parent to root.
-
#each_child_node(*types) {|node| ... } ⇒ self, Enumerator
Calls the given block for each child node.
-
#each_descendant(*types) {|node| ... } ⇒ self, Enumerator
Calls the given block for each descendant node with depth first order.
-
#each_node(*types) {|node| ... } ⇒ self, Enumerator
Calls the given block for the receiver and each descendant node with depth first order.
-
#initialize(type, children = [], properties = {}) ⇒ Node
constructor
A new instance of Node.
-
#parent ⇒ Node?
Returns the parent node, or
nil
if the receiver is a root node. -
#root? ⇒ Boolean
Returns whether the receiver is a root node or not.
-
#sibling_index ⇒ Integer
Returns the index of the receiver node in its siblings.
Constructor Details
#initialize(type, children = [], properties = {}) ⇒ Node
Returns a new instance of Node.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/astrolabe/node.rb', line 23 def initialize(type, children = [], properties = {}) @mutable_attributes = {} # ::AST::Node#initialize freezes itself. super # #parent= would be invoked multiple times for a node because there are pending nodes while # constructing AST and they are replaced later. # For example, `lvar` and `send` type nodes are initially created as an `ident` type node and # fixed to each type later. # So, the #parent attribute needs to be mutable. each_child_node do |child_node| child_node.parent = self end end |
Instance Method Details
#ancestors ⇒ Array<Node>
Returns an array of ancestor nodes.
This is a shorthand for node.each_ancestor.to_a
.
109 110 111 |
# File 'lib/astrolabe/node.rb', line 109 def ancestors each_ancestor.to_a end |
#child_nodes ⇒ Array<Node>
Returns an array of child nodes.
This is a shorthand for node.each_child_node.to_a
.
151 152 153 |
# File 'lib/astrolabe/node.rb', line 151 def child_nodes each_child_node.to_a end |
#descendants ⇒ Array<Node>
Returns an array of descendant nodes.
This is a shorthand for node.each_descendant.to_a
.
191 192 193 |
# File 'lib/astrolabe/node.rb', line 191 def descendants each_descendant.to_a end |
#each_ancestor ⇒ self, Enumerator #each_ancestor(type) ⇒ self, Enumerator #each_ancestor(type_a, type_b, ...) ⇒ self, Enumerator #each_ancestor(types) ⇒ self, Enumerator
Calls the given block for each ancestor node in the order from parent to root.
If no block is given, an Enumerator
is returned.
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/astrolabe/node.rb', line 91 def each_ancestor(*types, &block) return to_enum(__method__, *types) unless block_given? types.flatten! if types.empty? visit_ancestors(&block) else visit_ancestors_with_types(types, &block) end self end |
#each_child_node ⇒ self, Enumerator #each_child_node(type) ⇒ self, Enumerator #each_child_node(type_a, type_b, ...) ⇒ self, Enumerator #each_child_node(types) ⇒ self, Enumerator
Calls the given block for each child node.
If no block is given, an Enumerator
is returned.
Note that this is different from node.children.each { |child| ... }
which yields all
children including non-node element.
134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/astrolabe/node.rb', line 134 def each_child_node(*types) return to_enum(__method__, *types) unless block_given? types.flatten! children.each do |child| next unless child.is_a?(Node) yield child if types.empty? || types.include?(child.type) end self end |
#each_descendant ⇒ self, Enumerator #each_descendant(type) ⇒ self, Enumerator #each_descendant(type_a, type_b, ...) ⇒ self, Enumerator #each_descendant(types) ⇒ self, Enumerator
Calls the given block for each descendant node with depth first order.
If no block is given, an Enumerator
is returned.
173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/astrolabe/node.rb', line 173 def each_descendant(*types, &block) return to_enum(__method__, *types) unless block_given? types.flatten! if types.empty? visit_descendants(&block) else visit_descendants_with_types(types, &block) end self end |
#each_node ⇒ self, Enumerator #each_node(type) ⇒ self, Enumerator #each_node(type_a, type_b, ...) ⇒ self, Enumerator #each_node(types) ⇒ self, Enumerator
Calls the given block for the receiver and each descendant node with depth first order.
If no block is given, an Enumerator
is returned.
This method would be useful when you treat the receiver node as a root of tree and want to iterate all nodes in the tree.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/astrolabe/node.rb', line 216 def each_node(*types, &block) return to_enum(__method__, *types) unless block_given? types.flatten! yield self if types.empty? || types.include?(type) if types.empty? visit_descendants(&block) else visit_descendants_with_types(types, &block) end self end |
#parent ⇒ Node?
Returns the parent node, or nil
if the receiver is a root node.
49 50 51 |
# File 'lib/astrolabe/node.rb', line 49 def parent @mutable_attributes[:parent] end |
#root? ⇒ Boolean
Returns whether the receiver is a root node or not.
62 63 64 |
# File 'lib/astrolabe/node.rb', line 62 def root? parent.nil? end |
#sibling_index ⇒ Integer
Returns the index of the receiver node in its siblings.
69 70 71 |
# File 'lib/astrolabe/node.rb', line 69 def sibling_index parent.children.index { |sibling| sibling.equal?(self) } end |