Class: TreeRb::TreeNode

Inherits:
AbsNode show all
Defined in:
lib/tree_rb/core/tree_node.rb

Overview

TreeNode can contains other TreeNode (children) and can contains LeafNode (leaves)

TreeNode @children -1—n-> TreeNode

@leaves   -1---n-> LeafNode
@children_leaves -1---n-> AbsNode  (to preserve insert order)

define dsl to create Tree

Examples:

tree = TreeNode.create do
  node "root" do
    leaf "l1"
    node "sub" do
      leaf "l3"
    end
    node "wo leaves"
  end

Instance Attribute Summary collapse

Attributes inherited from AbsNode

#content, #next, #parent, #prev

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AbsNode

#depth, #path, #path_with_prefix, #prefix_path, #prefix_path=, #root

Constructor Details

#initialize(content, parent = nil) ⇒ TreeNode

Returns a new instance of TreeNode.

Parameters:

  • content (Object)

    of this node

  • parent (Object) (defaults to: nil)

    of this node. If parent is nil, it is a root



126
127
128
129
130
131
132
# File 'lib/tree_rb/core/tree_node.rb', line 126

def initialize(content, parent = nil)
  @leaves              = []
  @children            = []
  @leaves_and_children = []
  super(content)
  parent.add_child(self) if parent
end

Instance Attribute Details

#childrenObject (readonly)

children i.e. other tree node



117
118
119
# File 'lib/tree_rb/core/tree_node.rb', line 117

def children
  @children
end

#leavesObject (readonly)

leaves of this node



114
115
116
# File 'lib/tree_rb/core/tree_node.rb', line 114

def leaves
  @leaves
end

#leaves_and_childrenObject (readonly)

leaves and children to preserve insert order



120
121
122
# File 'lib/tree_rb/core/tree_node.rb', line 120

def leaves_and_children
  @leaves_and_children
end

Class Method Details

.create(class1 = TreeNode, class2 = LeafNode, &block) ⇒ Object

DSL create a root node:

tree = TreeNode.create do
   ...
end

tree = TreeNode.create(LeafDerivedClass) do
   ...
end

tree = TreeNode.create(TreeNodeDerivedClass, LeafDerivedClass) do
  ...
end

Parameters:

  • class1 (Class) (defaults to: TreeNode)

    Subclass of TreeNode default TreeNode

  • class2 (Class) (defaults to: LeafNode)

    Subclass of LeafNode default LeafNode

  • block (Object)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/tree_rb/core/tree_node.rb', line 43

def create(class1 = TreeNode, class2 = LeafNode, &block)
  if class1.ancestors.include?(TreeNode) and class2.ancestors.include?(LeafNode)
    @tree_node_class = class1
    @leaf_node_class = class2
  elsif class1.ancestors.include?(LeafNode) and class2 == LeafNode
    @tree_node_class = self
    @leaf_node_class = class1
  end

  if @tree_node_class.nil? || @leaf_node_class.nil?
    raise "Must be specified classes derived from TreeNode and LeafNode"
  end

  @scope_stack = []
  class_eval(&block)
end

.method_added(s) ⇒ Object



339
340
341
342
343
344
345
# File 'lib/tree_rb/core/tree_node.rb', line 339

def self.method_added(s)
  if s == :to_str
    puts "Warning: you should not override method 'to_str'"
  else
    super
  end
end

Instance Method Details

#accept(visitor) ⇒ Object

Returns the visitor.

Parameters:

  • visitor (Visitor)

Returns:

  • the visitor



257
258
259
260
261
262
263
264
265
266
267
# File 'lib/tree_rb/core/tree_node.rb', line 257

def accept(visitor)
  visitor.enter_node(self)
  @leaves.each do |leaf|
    leaf.accept(visitor)
  end
  @children.each do |child|
    child.accept(visitor)
  end
  visitor.exit_node(self)
  visitor
end

#add_child(tree_node) ⇒ Object

Add a Tree

Parameters:

Returns:

  • self



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/tree_rb/core/tree_node.rb', line 203

def add_child(tree_node)
  return if tree_node.parent == self
  if not tree_node.parent.nil?
    tree_node.remove_from_parent
  else
    tree_node.prefix_path = nil
  end
  tree_node.invalidate
  tree_node.parent = self
  if @children.length > 0
    @children.last.next = tree_node
    tree_node.prev      = @children.last
  else
    tree_node.prev = nil
  end
  tree_node.next = nil
  @children << tree_node
  @leaves_and_children << tree_node
  self
end

#add_leaf(leaf) ⇒ Object

Add a Leaf

Parameters:

Returns:

  • self



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/tree_rb/core/tree_node.rb', line 180

def add_leaf(leaf)
  return if leaf.parent == self
  leaf.remove_from_parent if leaf.parent
  leaf.parent = self
  if @leaves.length > 0
    @leaves.last.next = leaf
    leaf.prev         = @leaves.last
  else
    leaf.prev = nil
  end
  leaf.next = nil
  leaf.invalidate
  @leaves << leaf
  @leaves_and_children << leaf
  self
end

#find(content = nil, &block) ⇒ Object?

Find a node down the hierarchy with content

Parameters:

  • content (Object, Regexp) (defaults to: nil)

    of searched node

Returns:

  • (Object, nil)

    nil if not found



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/tree_rb/core/tree_node.rb', line 229

def find(content = nil, &block)
  if content and block_given?
    raise "TreeNode::find - passed content AND block"
  end

  if content
    if content.class == Regexp
      block = proc { |l| l.content =~ content }
    else
      block = proc { |l| l.content == content }
    end
  end
  return self if block.call(self)

  leaf = @leaves.find { |l| block.call(l) }
  return leaf if leaf

  @children.each do |child|
    node = child.find &block
    return node if node
  end
  nil
end

#invalidateObject

invalidate cached info invalidate propagates form parent to children and leaves



146
147
148
149
150
# File 'lib/tree_rb/core/tree_node.rb', line 146

def invalidate
  super
  @children.each { |c| c.invalidate }
  @leaves.each { |l| l.invalidate }
end

#nr_childrenFixNum

Returns total number of children.

Returns:

  • (FixNum)

    total number of children



170
171
172
# File 'lib/tree_rb/core/tree_node.rb', line 170

def nr_children
  @children.length + @children.inject(0) { |sum, child| sum + child.nr_children }
end

#nr_leavesFixNum

Returns total number of leaves.

Returns:

  • (FixNum)

    total number of leaves



163
164
165
# File 'lib/tree_rb/core/tree_node.rb', line 163

def nr_leaves
  @leaves.length + @children.inject(0) { |sum, child| sum + child.nr_leaves }
end

#nr_nodesFixNum

Returns total number of nodes.

Returns:

  • (FixNum)

    total number of nodes



155
156
157
158
# File 'lib/tree_rb/core/tree_node.rb', line 155

def nr_nodes
  nr = @leaves.length + @children.length
  @children.inject(nr) { |sum, c| sum + c.nr_nodes }
end

#root?Boolean

Test if is a root

Returns:

  • (Boolean)

    true if this node is a root



138
139
140
# File 'lib/tree_rb/core/tree_node.rb', line 138

def root?
  @parent.nil?
end

#to_str(prefix = "", options = { }) ⇒ Object



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/tree_rb/core/tree_node.rb', line 283

def to_str(prefix= "", options = { })
  #TODO: find a more idiomatic mode to assign an array of options

  tty_color        = options[:colorize].nil? ? false : options[:colorize]
  show_indentation = options[:show_indentation].nil? ? true : options[:show_indentation]
  str              = ""

  prepare_color_map if tty_color
  prepare_prefix_map(options)

  # print node itself
  if root?
    unless options[:only_files]
      str << node_content_to_str(content, options)
    end
  else

    if show_indentation
      str << prefix
      if self.next
        str << @prefix[:BRANCH]
      else
        str << @prefix[:LAST_BRANCH]
      end
    end

    unless options[:only_files]
      str << node_content_to_str(content, options)
      if show_indentation
        prefix += self.next ? @prefix[:CONT_1] : @prefix[:CONT_2]
      end
    end
  end

  # print leaves
  @leaves.each do |leaf|

    if show_indentation
      str << prefix
      if !leaf.next.nil? or !@children.empty?
        str << @prefix[:BRANCH]
      else
        str << @prefix[:LAST_BRANCH]
      end
    end

    str << leaf_content_to_str(leaf.content, options)
  end

  # print children
  @children.each do |child|
    str << child.to_str(prefix, options)
  end
  str
end