ruby-graphviz 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -10,6 +10,118 @@ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Gregoire Lejeune
10
10
 
11
11
  Interface to the GraphViz graphing tool
12
12
 
13
+ == CHANGELOG
14
+
15
+ === 0.9.11 :
16
+ * TODO: GraphViz::Parser support block
17
+
18
+ === 0.9.10 :
19
+ * Move ChangeLog in README
20
+ * Add GraphViz::FamilyTree (alpha). See examples/sample33.rb
21
+ * Major bugs corrections in GraphViz::Parser
22
+ * Issue #10 : Anonymous graph (see Subgraphs and Clusters at http://www.graphviz.org/doc/info/lang.html). See examples/sample34.rb
23
+ * GraphViz#add_graph can now take a block parameter. See example/sample34.rb
24
+ * Add GraphViz.digraph and GraphViz.graph (same as GraphViz.new( ..., :type => "digraph" ) and GraphViz.new( ..., :type => "graph" )). See examples/sample35.rb
25
+ * Add GraphViz#subgraph. See examples/sample35.rb
26
+ * GraphViz::Parser support anonymous graph
27
+ * Add lage node example. See examples/sample36.rb
28
+
29
+ === 0.9.9 :
30
+ * Add graph as an accessor to allow you to set global graph attributs (like edge and node)
31
+ * Add each_node, each_edge, each_graph (thanks to @metellius) and graph_count
32
+ * Issue #9 (partial) - Solution : by default, a node will have his label set with the node ID)
33
+
34
+ === 0.9.8 :
35
+ * Update graph and node posibility to set properties (see sample28.rb)
36
+ * Issue #7: Path option is never being used to find the executable
37
+ * Adding classes to check if the attributes are in the correct type
38
+ * Issue #8: dots in href are escaped with backslash, which corrupts the URL (see sample29.rb)
39
+ * Add posibility to use external libraries (see sample30.rb)
40
+ * Add options -u and -s to ruby2gv
41
+ * Add gem2gv
42
+
43
+ === 0.9.7 :
44
+ * Issue #2: Small bug correction in escape_path_containing_blanks (by Andreas Ronge)
45
+ * Issue #4: New find_executable (by reactive)
46
+ * Issue #3: Tempfiles created in current working directory only in Windows
47
+ * Issue #6: Respect "none" format in output options hash and respect String output-filename when the "none" format is selected. See examples/sample27.rb (by Dave Burt)
48
+
49
+ === 0.9.6 :
50
+ * jRuby support (by obruening)
51
+ * Issue #1 : STDOUT in binmode
52
+
53
+ === 0.9.5 :
54
+ * Remove 'mkmf' dependency
55
+ * GraphViz::Edge#[] modification
56
+ * Small correction to escape the dot ('.') character (by Miguel Cabrera)
57
+
58
+ === 0.9.4 :
59
+ * Escape nodes and edges attributs
60
+ * GraphViz::escape corrections (by Dave Burt)
61
+ * Add :errors option to set level of message suppression (default : suppress warning messages)
62
+
63
+ === 0.9.3 :
64
+ * Minor bug correction for Windows
65
+ * Use Open3.popen3 if installed, else use IO.popen (by Dave Burt)
66
+ * Add '-', '>' and '>>' has aliases of '<<' to create an edge.
67
+
68
+ === 0.9.2 :
69
+ * Escape nodes (by Dave Burt)
70
+ * Handle errors from graphviz command (by Dave Burt)
71
+ * Output as string (if String class is passed as file i.e. output(:pdf => String)) (by Dave Burt)
72
+
73
+ === 0.9.1 :
74
+ * Bugs corrections
75
+ * Add the ability to create edge like that : node1 << node2 << node3 ...
76
+ * Complete README
77
+ * Add a DOT parser. This parser has a lot of limitations. So don't use it in a production context !
78
+ * :output and :file options are deprecated, please use :<format> => :<file>
79
+ * You can now specify multiple outputs via :<format> => :<file> (see sample 22).
80
+
81
+ === 0.9.0 :
82
+ * Add fdp example (sample 15)
83
+ * Add edge between cluster and node and cluster and cluster support
84
+ * GraphViz.add_node now support array (sample 16)
85
+ * Bug correction in GraphViz.output (sample 19)
86
+ * Add GraphViz#default to set default options (:use, :path and :output)
87
+ * Add possibility to set node or edge attribut via :
88
+ node.<attribut>=<value> or node.<attribut>( <value> )
89
+ adge.<attribut>=<value> or adge.<attribut>( <value> )
90
+ * Add GraphViz::Edge.set and GraphViz::Node.set
91
+ * Add sample 20
92
+ * Add GraphViz.node_count and GraphViz.edge_count by Daniel Cadenas Nión
93
+
94
+ === 0.8.2 :
95
+ * Update Node, Edge and Graph Attributes (see http://www.graphviz.org/doc/info/attrs.html)
96
+ * Bugs corrections
97
+
98
+ === 0.8.1 :
99
+ * Documentation
100
+
101
+ === 0.8.0 :
102
+ * Add all the features of the current graphviz version
103
+
104
+ === 0.7.0 :
105
+ * Add option "path" to output
106
+
107
+ === 0.6.0 :
108
+ * Add undirected graph support
109
+
110
+ === 0.5.0 :
111
+ * Preserve the original order of creation of nodes and edges
112
+
113
+ === 0.4.0 :
114
+ * Add HTML-Labels
115
+
116
+ === 0.3.0 :
117
+ * Bugs corrections
118
+
119
+ === 0.2.0 :
120
+ * Pure ruby
121
+
122
+ === 0.1.0 :
123
+ * Initial version
124
+
13
125
  == SYNOPSIS
14
126
 
15
127
  A basic example
@@ -0,0 +1,28 @@
1
+ digraph G {
2
+ graph [truecolor=true, bgcolor=transparent];
3
+ rankdir="LR";
4
+ subgraph {
5
+ rank = same;
6
+ mygraph [label = "# mygraph.dot\ldigraph G {\l Hello -> World;\l}\l", shape = note, fontname = "Courier", fontsize=10];
7
+ image [image = "./hello.png", label = "", shape = note];
8
+ }
9
+ subgraph {
10
+ rank = same;
11
+ mysite [label = "\nexample.com\n ", shape = "component", fontname = "Arial"];
12
+ dotgraph [label = "\ndotgraph.net\n ", shape = "component", fontname = "Arial"];
13
+ }
14
+ subgraph cluster_0 {
15
+ label = "my_page.html";
16
+ fontname = "Courier";
17
+ fontsize = 10;
18
+ color = black;
19
+ zeimage [image = "./hello.png", label = "", shape = note]
20
+ }
21
+
22
+ mygraph -> mysite [color = blue];
23
+ dotgraph -> image [color = red];
24
+ dotgraph -> mysite [color = red];
25
+ mysite -> dotgraph [color = blue];
26
+ image -> dotgraph [color = red];
27
+ mysite -> zeimage [color = red];
28
+ }
@@ -0,0 +1,6 @@
1
+ digraph G {
2
+ subgraph { rank = same; "node1"; "node2"; }
3
+ subgraph { rank = same; "nodeA"; "nodeB"; }
4
+ node1 -> nodeA;
5
+ node2 -> nodeB;
6
+ }
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../../lib" );
4
+ require "graphviz"
5
+
6
+ Dir.glob( "*.dot" ) { |f|
7
+ print "#{f} : "
8
+ begin
9
+ puts GraphViz.parse(f)
10
+ rescue => e
11
+ puts "Error #{e.message}"
12
+ end
13
+ }
Binary file
@@ -69,6 +69,8 @@
69
69
  @ruby sample31.rb
70
70
  @echo "sample32.rb"
71
71
  @ruby sample32.rb
72
+ @echo "sample33.rb"
73
+ @ruby sample33.rb
72
74
 
73
75
 
74
76
  @echo "shapes.rb"
@@ -82,6 +84,9 @@
82
84
  @pwd
83
85
  @echo "dot/hello_test.rb"
84
86
  @ruby hello_test.rb
87
+ @echo "dot/test_parse.rb"
88
+ @ruby test_parse.rb
89
+
85
90
  @cd ..
86
91
 
87
92
  @cd graphviz.org
data/examples/maketest.sh CHANGED
@@ -71,6 +71,8 @@ echo "sample31.rb"
71
71
  ruby sample31.rb
72
72
  echo "sample32.rb"
73
73
  ruby sample32.rb
74
+ echo "sample33.rb"
75
+ ruby sample33.rb
74
76
 
75
77
  echo "shapes.rb"
76
78
  ruby shapes.rb
@@ -83,6 +85,8 @@ cd dot
83
85
  pwd
84
86
  echo "dot/hello_test.rb"
85
87
  ruby hello_test.rb
88
+ echo "dot/test_parse.rb"
89
+ ruby test_parse.rb
86
90
  cd ..
87
91
 
88
92
  cd graphviz.org
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ puts GraphViz::new( "G" ) { |graph|
7
+ graph.node[:shape] = "ellipse"
8
+ graph.node[:color] = "black"
9
+
10
+ graph[:color] = "black"
11
+
12
+ graph.cluster0( ) do |cluster|
13
+ cluster[:label] = "process #1"
14
+ cluster[:style] = "filled"
15
+ cluster[:color] = "lightgrey"
16
+
17
+ cluster.a0 :style => "filled", :color => "white"
18
+ cluster.a1 :style => "filled", :color => "white"
19
+ cluster.a2 :style => "filled", :color => "white"
20
+ cluster.a3 :style => "filled", :color => "white"
21
+
22
+ cluster.a0 << cluster.a1
23
+ cluster.a1 << cluster.a2
24
+ cluster.a2 << cluster.a3
25
+ end
26
+
27
+ graph.cluster1( :label => "process #2" ) do |cluster|
28
+ cluster.b0 :style => "filled", :color => "blue"
29
+ cluster.b1 :style => "filled", :color => "blue"
30
+ cluster.b2 :style => "filled", :color => "blue"
31
+ cluster.b3 :style => "filled", :color => "blue"
32
+
33
+ cluster.b0 << cluster.b1
34
+ cluster.b1 << cluster.b2
35
+ cluster.b2 << cluster.b3
36
+ end
37
+
38
+ graph.start :shape => "Mdiamond"
39
+ graph.endn :shape => "Msquare", :label => "end"
40
+
41
+ graph.start << graph.cluster0.a0
42
+ graph.start << graph.cluster1.b0
43
+ graph.cluster0.a1 << graph.cluster1.b3
44
+ graph.cluster1.b2 << graph.cluster0.a3
45
+ graph.cluster0.a3 << graph.cluster0.a0
46
+ graph.cluster0.a3 << graph.endn
47
+ graph.cluster1.b3 << graph.endn
48
+ }.output( :path => '/usr/local/bin/', :none => String )
@@ -0,0 +1,43 @@
1
+ $:.unshift( "../lib" );
2
+ require 'graphviz/family_tree'
3
+
4
+ tree = GraphViz::FamilyTree.new do
5
+ generation do
6
+ abraham.is_a_man( "Abraham" )
7
+ mona.is_a_woman( "Mona" )
8
+
9
+ abraham.is_maried_with mona
10
+
11
+ clancy.is_a_man( "Clancy" )
12
+ jackeline.is_a_woman( "Jackeline" )
13
+
14
+ clancy.is_maried_with jackeline
15
+ end
16
+
17
+ generation do
18
+ herb.is_a_man( "Herb" )
19
+ homer.is_a_man( "Homer" )
20
+
21
+ marge.is_a_woman( "Marge" )
22
+ patty.is_a_woman( "Patty" )
23
+ selma.is_a_woman( "Selma" )
24
+
25
+ homer.is_maried_with marge
26
+ end
27
+
28
+ couple( abraham, mona ).kids( herb, homer )
29
+ couple( clancy, jackeline ).kids( marge, patty, selma )
30
+
31
+ generation do
32
+ bart.is_a_boy( "Bart" )
33
+ lisa.is_a_girl( "Lisa" )
34
+ maggie.is_a_girl( "Maggie" )
35
+ ling.is_a_boy( "Ling" )
36
+ end
37
+
38
+ couple( homer, marge ).kids( bart, lisa, maggie )
39
+
40
+ ling.kids( selma )
41
+ end
42
+
43
+ puts tree.graph.save( :none => String )
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" )
4
+ require "graphviz"
5
+
6
+ GraphViz.new(:G) { |g|
7
+ g[:color] = "black"
8
+
9
+ g.one :label => "1"
10
+
11
+ # This is an anonymous graph
12
+ c = g.add_graph( :rank => "same" ) { |c|
13
+ c.two :label => "2"
14
+ c.three :label => "3"
15
+ c.two << c.three
16
+ }
17
+
18
+ # And this is not!
19
+ k = g.add_graph( "Hello" ) { |k|
20
+ k.four :label => "4"
21
+ k.five :label => "5"
22
+ k.four << k.five
23
+ }
24
+
25
+ g.one << c.two
26
+ g.one << c.three
27
+ c.two << k.four
28
+ c.three << k.five
29
+ }.output( :canon => String )
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" )
4
+ require "graphviz"
5
+
6
+ GraphViz.digraph( :G ) { |g|
7
+ g[:truecolor => true, :bgcolor => "transparent", :rankdir => "LR"]
8
+ g.node[:label => "\N"]
9
+
10
+ c1 = g.subgraph { |c|
11
+ c[:rank => "same"]
12
+ c.mygraph[
13
+ :label => '# mygraph.dot\ldigraph G {\l Hello -> World\l}\l',
14
+ :shape => "note",
15
+ :fontname => "Courier",
16
+ :fontsize => 10
17
+ ]
18
+ c.image[ :label => "", :shape => "note", :image => "./hello.png"]
19
+ }
20
+
21
+ c2 = g.subgraph { |c|
22
+ c[:rank => "same"]
23
+ c.mysite[:label => "\nexample.com\n ", :shape => "component", :fontname => "Arial"]
24
+ c.dotgraph[:label => "\ndotgraph.net\n ", :shape => "component", :fontname => "Arial"]
25
+ }
26
+
27
+ g.cluster_0 { |c|
28
+ c[
29
+ :label => "my_page.html",
30
+ :fontname => "Courier",
31
+ :fontsize => 10,
32
+ :color => "black"
33
+ ]
34
+ c.zeimage[:label => "", :shape => "note", :image => "./hello.png"]
35
+ }
36
+
37
+ (c1.mygraph << c2.mysite)[:color => "blue"]
38
+ (c2.dotgraph << c1.image)[:color => "red"]
39
+ (c2.dotgraph << c2.mysite)[:color => "red"]
40
+ (c2.mysite << c2.dotgraph)[:color => "blue"]
41
+ (c1.image << c2.dotgraph)[:color => "red"]
42
+ (c2.mysite << g.cluster_0.zeimage)[:color => "red"]
43
+ }.output( :png => "#{$0}.png" )
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" )
4
+ require "graphviz"
5
+
6
+ GraphViz.graph( :G ) { |g|
7
+ last_line = []
8
+ node_number = 0
9
+
10
+ 100.times do |j|
11
+ # New_Line
12
+ new_line = []
13
+ c = g.subgraph( :rank => "same" )
14
+
15
+ 100.times do |i|
16
+ current_node = c.add_node( "N#{node_number}", :shape => "point", :label => "" )
17
+ last_node = new_line[-1]
18
+ unless last_node.nil?
19
+ c.add_edge( last_node, current_node )
20
+ end
21
+ new_line << current_node
22
+ top_first_node = last_line.shift
23
+ unless top_first_node.nil?
24
+ g.add_edge( top_first_node, current_node )
25
+ top_second_node = last_line.shift
26
+ unless top_second_node.nil?
27
+ g.add_edge( top_second_node, current_node )
28
+ last_line.unshift( top_second_node )
29
+ end
30
+ end
31
+ node_number = node_number + 1
32
+ end
33
+ last_line = new_line
34
+ end
35
+ }.output( :png => "#{$0}.png" )
@@ -0,0 +1,46 @@
1
+ $:.unshift( "../lib" );
2
+ require 'graphviz/family_tree'
3
+
4
+ tree = GraphViz::FamilyTree.new do
5
+ generation do
6
+ benoist.is_a_man( "Benoist" )
7
+ nathalie.is_a_woman( "Nathalie" )
8
+
9
+ benoist.is_maried_with nathalie
10
+
11
+ michel.is_a_man( "Michel" )
12
+ brigitte.is_a_woman( "Brigitte" )
13
+
14
+ michel.is_maried_with brigitte
15
+ end
16
+
17
+ generation do
18
+ charlotte.is_a_woman( "Charlotte" )
19
+ amelie.is_a_woman( "Amelie" )
20
+ clement.is_a_man( "Clement" )
21
+ gregoire.is_a_man( "Gregoire" )
22
+
23
+ muriel.is_a_woman( "Muriel" )
24
+ gilles.is_a_man( "Gilles" )
25
+
26
+ gregoire.is_maried_with muriel
27
+ end
28
+
29
+ couple( michel, brigitte ).kids( muriel, gilles )
30
+ couple( benoist, nathalie ).kids( charlotte, amelie, clement, gregoire )
31
+
32
+ generation do
33
+ arthur.is_a_boy( "Arthur" )
34
+ colyne.is_a_girl( "Colyne" )
35
+ benedict.is_a_boy( "Benedict" )
36
+ maia.is_a_girl( "Maia" )
37
+ enaitz.is_a_boy( "Enaitz" )
38
+ milo.is_a_boy( "Milo" )
39
+ end
40
+
41
+ gregoire.kids( arthur, colyne, benedict )
42
+ couple( gregoire, muriel ).kids( maia )
43
+ muriel.kids( enaitz, milo )
44
+ end
45
+
46
+ tree.graph.save( :png => "#{$0}.png" )
@@ -0,0 +1,69 @@
1
+ digraph FamilyTree {
2
+ subgraph Generation0 {
3
+ rank = "same";
4
+ abraham [label = "Abraham", shape = "box", color = "blue"];
5
+ mona [label = "Mona", shape = "box", color = "pink"];
6
+ abrahamAndmona [shape = "point"];
7
+ abraham -> abrahamAndmona [dir = "none"]
8
+ abrahamAndmona -> mona [dir = "none"]
9
+ clancy [label = "Clancy", shape = "box", color = "blue"];
10
+ jackeline [label = "Jackeline", shape = "box", color = "pink"];
11
+ clancyAndjackeline [shape = "point"];
12
+ clancy -> clancyAndjackeline [dir = "none"]
13
+ clancyAndjackeline -> jackeline [dir = "none"]
14
+ }
15
+ subgraph Generation1 {
16
+ rank = "same";
17
+ herb [label = "Herb", shape = "box", color = "blue"];
18
+ homer [label = "Homer", shape = "box", color = "blue"];
19
+ homerAndmarge [shape = "point"];
20
+ marge [label = "Marge", shape = "box", color = "pink"];
21
+ patty [label = "Patty", shape = "box", color = "pink"];
22
+ selma [label = "Selma", shape = "box", color = "pink"];
23
+ homer -> homerAndmarge [dir = "none"]
24
+ homerAndmarge -> marge [dir = "none"]
25
+ }
26
+ subgraph abrahamAndmonaKids {
27
+ rank = "same";
28
+ herbKid [label = "herbKid", shape = "point"];
29
+ abrahamAndmonaKids [label = "abrahamAndmonaKids", shape = "point"];
30
+ herbKid -> abrahamAndmonaKids [dir = "none"]
31
+ homerKid [label = "homerKid", shape = "point"];
32
+ abrahamAndmonaKids -> homerKid [dir = "none"]
33
+ }
34
+ herbKid -> herb [dir = "none"]
35
+ abrahamAndmona -> abrahamAndmonaKids [dir = "none"]
36
+ homerKid -> homer [dir = "none"]
37
+ subgraph clancyAndjackelineKids {
38
+ rank = "same";
39
+ margeKid [label = "margeKid", shape = "point"];
40
+ pattyKid [label = "pattyKid", shape = "point"];
41
+ margeKid -> pattyKid [dir = "none"]
42
+ selmaKid [label = "selmaKid", shape = "point"];
43
+ pattyKid -> selmaKid [dir = "none"]
44
+ }
45
+ margeKid -> marge [dir = "none"]
46
+ pattyKid -> patty [dir = "none"]
47
+ clancyAndjackeline -> pattyKid [dir = "none"]
48
+ selmaKid -> selma [dir = "none"]
49
+ subgraph Generation2 {
50
+ rank = "same";
51
+ bart [label = "Bart", shape = "box", color = "blue"];
52
+ lisa [label = "Lisa", shape = "box", color = "pink"];
53
+ maggie [label = "Maggie", shape = "box", color = "pink"];
54
+ ling [label = "Ling", shape = "box", color = "blue"];
55
+ }
56
+ subgraph homerAndmargeKids {
57
+ rank = "same";
58
+ bartKid [label = "bartKid", shape = "point"];
59
+ lisaKid [label = "lisaKid", shape = "point"];
60
+ bartKid -> lisaKid [dir = "none"]
61
+ maggieKid [label = "maggieKid", shape = "point"];
62
+ lisaKid -> maggieKid [dir = "none"]
63
+ }
64
+ bartKid -> bart [dir = "none"]
65
+ lisaKid -> lisa [dir = "none"]
66
+ homerAndmarge -> lisaKid [dir = "none"]
67
+ maggieKid -> maggie [dir = "none"]
68
+ ling -> selma [dir = "none"]
69
+ }
@@ -40,7 +40,7 @@
40
40
  # C => cluster
41
41
  #
42
42
  module Constants
43
- RGV_VERSION = "0.9.9"
43
+ RGV_VERSION = "0.9.10"
44
44
 
45
45
  ## Const: Output formats
46
46
  FORMATS = [
@@ -242,7 +242,7 @@ module Constants
242
242
  "shapefile" => { :usedBy => "N", :type => :EscString },
243
243
  "showboxes" => { :usedBy => "ENG", :type => :EscString },
244
244
  "sides" => { :usedBy => "N", :type => :EscString },
245
- "size" => { :usedBy => "G", :type => :EscString },
245
+ "size" => { :usedBy => "NG", :type => :EscString },
246
246
  "skew" => { :usedBy => "N", :type => :EscString },
247
247
  "smoothing" => { :usedBy => "G", :type => :EscString },
248
248
  "sortv" => { :usedBy => "GCN", :type => :EscString },
@@ -0,0 +1,20 @@
1
+ class String
2
+ def self.random(size)
3
+ s = ""
4
+ d = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
5
+ size.times {
6
+ s << d[rand(d.size)]
7
+ }
8
+ return s
9
+ end
10
+ end
11
+
12
+ # From : http://www.geekmade.co.uk/2008/09/ruby-tip-normalizing-hash-keys-as-symbols/
13
+ class Hash
14
+ def symbolize_keys
15
+ inject({}) do |options, (key, value)|
16
+ options[(key.to_sym rescue key) || key] = value
17
+ options
18
+ end
19
+ end
20
+ end
@@ -44,9 +44,17 @@ grammar Dot
44
44
  end
45
45
 
46
46
  rule subgraph
47
+ named_subgraph / anonymous_subgraph
48
+ end
49
+
50
+ rule named_subgraph
47
51
  space "subgraph" blank name:string space cluster:cluster space <GraphViz::Parser::Subgraph>
48
52
  end
49
53
 
54
+ rule anonymous_subgraph
55
+ space "subgraph" space cluster:cluster space <GraphViz::Parser::AnonymousSubgraph>
56
+ end
57
+
50
58
  rule options
51
59
  "[" space (name blank "=" blank string comma space)* name blank "=" blank string space "]" <GraphViz::Parser::Options>
52
60
  end
@@ -0,0 +1,52 @@
1
+ class GraphViz
2
+ class FamilyTree
3
+ class Couple
4
+ def initialize( g, n )
5
+ @graph = g
6
+ @node = n
7
+ end
8
+
9
+ def node
10
+ @node
11
+ end
12
+
13
+ def kids( *z )
14
+ if z.size == 1
15
+ @graph.add_edge( @node, z[0].node, "dir" => "none" )
16
+ else
17
+ cluster = @graph.add_graph( "#{@node.name}Kids" )
18
+ cluster["rank"] = "same"
19
+
20
+ last = nil
21
+ count = 0
22
+ add = (z.size-1)%2 * z.size/2 + (z.size-1)%2
23
+ link = (z.size/2)+1
24
+
25
+ z.each do |person|
26
+ count = count + 1
27
+ if count == add
28
+ middle = cluster.add_node( "#{@node.name}Kids", "shape" => "point" )
29
+ @graph.add_edge( @node, middle, "dir" => "none" )
30
+ unless last.nil?
31
+ cluster.add_edge( last, middle, "dir" => "none" )
32
+ end
33
+ last = middle
34
+ end
35
+
36
+ kid = cluster.add_node( "#{person.node.name}Kid", "shape" => "point" )
37
+ @graph.add_edge( kid, person.node, "dir" => "none" )
38
+
39
+ if add == 0 and count == link
40
+ @graph.add_edge( @node, kid, "dir" => "none" )
41
+ end
42
+
43
+ unless last.nil?
44
+ cluster.add_edge( last, kid, "dir" => "none" )
45
+ end
46
+ last = kid
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,25 @@
1
+ class GraphViz
2
+ class FamilyTree
3
+ class Generation
4
+ def initialize( graph, persons, tree, gen_number )
5
+ @graph = graph
6
+ @persons = persons
7
+ @cluster = @graph.add_graph( "Generation#{gen_number}" )
8
+ @cluster["rank"] = "same"
9
+ @tree = tree
10
+ end
11
+
12
+ def persons
13
+ @persons
14
+ end
15
+
16
+ def make( &block )
17
+ instance_eval(&block) if block
18
+ end
19
+
20
+ def method_missing(sym, *args, &block)
21
+ persons[sym.to_s] ||= GraphViz::FamilyTree::Person.new( @graph, @cluster, @tree, sym.to_s )
22
+ end
23
+ end
24
+ end
25
+ end