Class: MiniGauge::Graph
- Inherits:
-
Object
- Object
- MiniGauge::Graph
- Defined in:
- lib/mini_gauge.rb
Overview
From Railroad, an object to hold our nodes and edges, also to export them on demand
Instance Attribute Summary collapse
-
#description ⇒ Object
Returns the value of attribute description.
-
#edges ⇒ Object
Returns the value of attribute edges.
-
#graph_type ⇒ Object
Returns the value of attribute graph_type.
-
#nodes ⇒ Object
Returns the value of attribute nodes.
-
#show_label ⇒ Object
Returns the value of attribute show_label.
-
#title ⇒ Object
Returns the value of attribute title.
Instance Method Summary collapse
-
#add(opts) ⇒ Object
Add an item to the graph, expects a source node and destination node or a label if there is no destination.
-
#dot_label ⇒ Object
Build diagram label.
-
#format_edge(edge) ⇒ Object
Take an edge (hash) and format it into dot notation.
-
#format_node(node) ⇒ Object
Take a node (hash) and format it into dot notation.
-
#initialize(opts = {}) ⇒ Graph
constructor
A new instance of Graph.
-
#nil_node_definition(opts) ⇒ Object
Returns a node definition for an empty node.
-
#to_dot_notation ⇒ Object
Returns a string representing the DOT graph.
Constructor Details
#initialize(opts = {}) ⇒ Graph
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/mini_gauge.rb', line 90 def initialize(opts = {}) @graph_type = opts[:graph_type] || 'Model' @show_label = opts[:show_label] || true @title = opts[:title] || "#{@graph_type} diagram" @description = opts[:description] || '' @nodes = [] @edges = [] # Designed to work with the other class and instance methods on AR objects # to make adding nodes and edges easier. Allows you to do something like # @graph.nodes << Invoice.first @nodes.instance_eval(%Q( def <<(item) if item.respond_to?(:dot_node_definition) super(item.dot_node_definition) else super(item) end end )) # Makes building graphs easier, allows you to do something like # @graph.edges << {:source => Person.first, :destination => Person.first.organization} @edges.instance_eval(%Q( def <<(item) if item.is_a? Hash if item[:source] && item[:source].respond_to?(:dot_node_name) item[:source] = item[:source].dot_node_name end if item[:destination] && item[:destination].respond_to?(:dot_node_name) item[:destination] = item[:destination].dot_node_name end end super(item) end )) end |
Instance Attribute Details
#description ⇒ Object
Returns the value of attribute description.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def description @description end |
#edges ⇒ Object
Returns the value of attribute edges.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def edges @edges end |
#graph_type ⇒ Object
Returns the value of attribute graph_type.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def graph_type @graph_type end |
#nodes ⇒ Object
Returns the value of attribute nodes.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def nodes @nodes end |
#show_label ⇒ Object
Returns the value of attribute show_label.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def show_label @show_label end |
#title ⇒ Object
Returns the value of attribute title.
88 89 90 |
# File 'lib/mini_gauge.rb', line 88 def title @title end |
Instance Method Details
#add(opts) ⇒ Object
Add an item to the graph, expects a source node and destination node or a label if there is no destination
131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/mini_gauge.rb', line 131 def add(opts) raise ArgumentError.new("Must supply :source and :destination") unless opts.is_a?(Hash) && opts.keys.include?(:source) && opts.keys.include?(:destination) raise ArgumentError.new("Cannot supply a nil :destination without a label") if opts[:destination].nil? && opts[:label].nil? if opts[:destination].nil? node_name = "#{opts[:label].underscore}_#{opts.object_id}" @nodes << self.nil_node_definition(:label => opts[:label], :name => node_name) @edges << {:destination => node_name, :source => opts[:source], :empty_rec => true} else @nodes<<opts[:source] unless @nodes.any?{|x| opts[:source].dot_node_name == x[:name] } @nodes<<opts[:destination] unless @nodes.any?{|x| opts[:destination].dot_node_name == x[:name] } @edges<<opts end end |
#dot_label ⇒ Object
Build diagram label
170 171 172 173 174 175 176 177 178 |
# File 'lib/mini_gauge.rb', line 170 def dot_label return "\t_diagram_info [shape=\"plaintext\", " + "label=\"#{@title} \\l" + "Date: #{Time.now.strftime "%b %d %Y - %H:%M"}\\l" + "Migration version: " + "#{ActiveRecord::Migrator.current_version}\\l" + "Description: #{@description}\\l" + "\\l\", fontsize=14]\n" end |
#format_edge(edge) ⇒ Object
Take an edge (hash) and format it into dot notation
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/mini_gauge.rb', line 190 def format_edge(edge) edge[:options] ||= {} edge[:options][:label] = edge[:label] unless edge[:label].blank? edge[:options].merge!({:style => "dotted", :color => "gray61"}) if edge[:empty_rec] case edge[:type] when 'one-one' edge[:options].merge!({:arrowtail => "odot", :arrowhead => "dot", :dir => "both"}) when 'one-many' edge[:options].merge!({:arrowtail => "crow", :arrowhead => "dot", :dir => "both"}) when 'many-many' edge[:options].merge!({:arrowtail => "crow", :arrowhead => "crow", :dir => "both"}) when 'is-a' edge[:options].merge!({:arrowtail => "onormal", :arrowhead => "none"}) end opts = edge[:options].collect{|k,v| %Q(#{k}="#{v}") }.join(", ") return %Q( "#{edge[:source]}" -> "#{edge[:destination]}" [#{opts}]\n ) end |
#format_node(node) ⇒ Object
Take a node (hash) and format it into dot notation
181 182 183 184 185 186 187 |
# File 'lib/mini_gauge.rb', line 181 def format_node(node) node[:options] ||= {} node[:options][:shape] = "Mrecord" node[:options][:label] = %Q({#{(node[:label] || node[:name])} | #{node[:attributes].join('\l')} \\l} ) opts = node[:options].collect{|k,v| %Q(#{k}="#{v}") }.join(", ") return %Q(\t"#{node[:name]}" [#{opts}]\n) end |
#nil_node_definition(opts) ⇒ Object
Returns a node definition for an empty node
147 148 149 150 151 |
# File 'lib/mini_gauge.rb', line 147 def nil_node_definition(opts) raise ArgumentError.new("Must supply at least :name or :label") unless opts.is_a?(Hash) && (opts.keys.include?(:name) || opts.keys.include?(:label)) {:name => (opts[:name] || opts[:label].underscore), :label => (opts[:label] || opts[:name].humanize.titleize), :attributes => ["none"], :options => {:color => "gray61"}} end |
#to_dot_notation ⇒ Object
Returns a string representing the DOT graph
154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/mini_gauge.rb', line 154 def to_dot_notation header = "digraph #{@graph_type.downcase}_diagram {\n" + "\tgraph[overlap=false, splines=true]\n" header += dot_label if @show_label uniq_nodes = @nodes.inject([]) { |result,h| result << h unless result.include?(h); result } uniq_edges = @edges.inject([]) { |result,h| result << h unless result.include?(h); result } return header + uniq_nodes.map{|node| format_node(node)}.to_s + "\n" + uniq_edges.map{|edge| format_edge(edge)}.to_s + "}\n" end |