Class: Hirb::Helpers::Tree

Inherits:
Object
  • Object
show all
Defined in:
lib/hirb/helpers/tree.rb

Overview

Base tree class which given an array of nodes produces different types of trees. The types of trees currently are:

  • basic:

    0
      1
        2
        3
      4
    
  • directory:

    0
    |-- 1
    |   |-- 2
    |   `-- 3
    `-- 4
    
  • number:

    1. 0
      1. 1
        1. 2
        2. 3
      2. 4
    

Tree nodes can be given as an array of arrays or an array of hashes. To render the above basic tree with an array of hashes:

Hirb::Helpers::Tree.render([{:value=>0, :level=>0}, {:value=>1, :level=>1}, {:value=>2, :level=>2}, 
  {:value=>3, :level=>2}, {:value=>4, :level=>1}])

Note from the hash keys that :level refers to the depth of the tree while :value refers to the text displayed for a node.

To render the above basic tree with an array of arrays:

Hirb::Helpers::Tree.render([[0,0], [1,1], [2,2], [2,3], [1,4]])

Note that the each array pair consists of the level and the value for the node.

Direct Known Subclasses

ParentChildTree

Defined Under Namespace

Classes: Node, ParentlessNodeError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_nodes, options = {}) ⇒ Tree

Returns a new instance of Tree.



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/hirb/helpers/tree.rb', line 57

def initialize(input_nodes, options={})
  @options = options
  @type = options[:type] || :basic
  if input_nodes[0].is_a?(Array)
    @nodes = input_nodes.map {|e| Node.new(:level=>e[0], :value=>e[1]) }
  else
    @nodes = input_nodes.map {|e| Node.new(e)}
  end
  @nodes.each_with_index {|e,i| e.merge!(:tree=>self, :index=>i)}
  @nodes.each {|e| e[:value] = e[:value].to_s }
  validate_nodes if options[:validate]
  self
end

Instance Attribute Details

#nodesObject

:stopdoc:



55
56
57
# File 'lib/hirb/helpers/tree.rb', line 55

def nodes
  @nodes
end

Class Method Details

.render(nodes, options = {}) ⇒ Object

Main method which renders a tree.

Options:

:type

Type of tree. Either :basic, :directory or :number. Default is :basic.

:validate

Boolean to validate tree. Checks to see if all nodes have parents. Raises ParentlessNodeError if an invalid node is found. Default is false.

:indent

Number of spaces to indent between levels for basic + number trees. Default is 4.

:limit

Limits the level or depth of a tree that is displayed. Root node is level 0.

:description

Displays brief description about tree ie how many nodes it has.

:multi_line_nodes

Handles multi-lined nodes by indenting their newlines. Default is false.

Examples:
   Hirb::Helpers::Tree.render([[0, 'root'], [1, 'child']], :type=>:directory)


49
50
51
# File 'lib/hirb/helpers/tree.rb', line 49

def render(nodes, options={})
  new(nodes, options).render
end

Instance Method Details

#mark_last_nodes_per_levelObject

walks tree accumulating last nodes per unique parent+level



130
131
132
133
134
135
136
# File 'lib/hirb/helpers/tree.rb', line 130

def mark_last_nodes_per_level
  @nodes.each {|e| e.delete(:last_node)}
  last_node_hash = @nodes.inject({}) {|h,e|
    h["#{(e.parent ||{})[:index]}.#{e[:level]}"] = e; h
  }
  last_node_hash.values.uniq.each {|e| e[:last_node] = true}
end

#renderObject



71
72
73
74
75
# File 'lib/hirb/helpers/tree.rb', line 71

def render
  body = render_tree
  body += render_description if @options[:description]
  body
end

#render_basicObject



119
120
121
# File 'lib/hirb/helpers/tree.rb', line 119

def render_basic
  render_nodes {|e| @indent * e[:level] }
end

#render_descriptionObject



77
78
79
# File 'lib/hirb/helpers/tree.rb', line 77

def render_description
  "\n\n#{@nodes.length} #{@nodes.length == 1 ? 'node' : 'nodes'} in tree"
end

#render_directoryObject



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/hirb/helpers/tree.rb', line 96

def render_directory
  mark_last_nodes_per_level
  render_nodes {|e|
    value = ''
    unless e.root?
      value << e.render_parent_characters
      value << (e[:last_node] ? "`-- " : "|-- ")
    end
    value
  }
end

#render_nodesObject



91
92
93
94
# File 'lib/hirb/helpers/tree.rb', line 91

def render_nodes
  value_indent = @options[:multi_line_nodes] ? @indent : nil
  @nodes.map {|e| yield(e) + e.value(value_indent) }.join("\n")
end

#render_numberObject



108
109
110
111
112
113
114
115
116
117
# File 'lib/hirb/helpers/tree.rb', line 108

def render_number
  counter = {}
  @nodes.each {|e|
    parent_level_key = "#{(e.parent ||{})[:index]}.#{e[:level]}"
    counter[parent_level_key] ||= 0
    counter[parent_level_key] += 1
    e[:pre_value] = "#{counter[parent_level_key]}. "
  }
  render_nodes {|e| @indent * e[:level] + e[:pre_value] }
end

#render_treeObject



81
82
83
84
85
86
87
88
89
# File 'lib/hirb/helpers/tree.rb', line 81

def render_tree
  @indent = ' ' * (@options[:indent] || 4 )
  @nodes = @nodes.select {|e| e[:level] <= @options[:limit] } if @options[:limit]
  case @type.to_s
  when 'directory' then render_directory
  when 'number'    then render_number
  else render_basic
  end
end

#validate_nodesObject



123
124
125
126
127
# File 'lib/hirb/helpers/tree.rb', line 123

def validate_nodes
  @nodes.each do |e|
    raise ParentlessNodeError if (e[:level] > e.previous[:level]) && (e[:level] - e.previous[:level]) > 1
  end
end