rgl 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,151 +1,174 @@
1
- # This file contains the definition of the class RGL::ImplicitGraph which
1
+ # implicit.rb
2
+ #
3
+ # This file contains the definition of the class RGL::ImplicitGraph, which
2
4
  # defines vertex and edge iterators using blocks (which again call blocks).
3
5
  #
4
- # An ImplicitGraph provides a handy way to define graphs on the fly using two
5
- # blocks for the two iterators defining a graph. The directed cyclic graph with
6
- # 5 vertices can be created as follows:
6
+ # An ImplicitGraph provides a handy way to define graphs on the fly, using two
7
+ # blocks for the two iterators defining a graph. A directed cyclic graph,
8
+ # with five vertices can be created as follows:
7
9
  #
8
10
  # g = RGL::ImplicitGraph.new { |g|
9
- # g.vertex_iterator { |b| 0.upto(4,&b) }
10
- # g.adjacent_iterator { |x, b| b.call((x+1)%5) }
11
- # g.directed = true
11
+ # g.vertex_iterator { |b| 0.upto(4,&b) }
12
+ # g.adjacent_iterator { |x, b| b.call((x+1)%5) }
13
+ # g.directed = true
12
14
  # }
15
+ #
13
16
  # g.to_s => "(0-1)(1-2)(2-3)(3-4)(4-0)"
14
17
  #
15
18
  # Other examples are given by the methods vertices_filtered_by and
16
19
  # edges_filtered_by, which can be applied to any graph.
20
+
17
21
  require 'rgl/base'
18
22
 
19
23
  module RGL
24
+
20
25
  class ImplicitGraph
21
- include Graph
22
-
23
- attr_writer :directed
24
-
25
- EMPTY_VERTEX_ITERATOR = proc { |b| }
26
- EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
27
-
28
- # Create a new ImplicitGraph, which is by default empty. The caller should
29
- # configure the with vertex and neighbor iterators. If the graph is directed
30
- # the client should set directed to true. The default value for _directed_
31
- # is false.
32
- def initialize
33
- @directed = false
34
- @vertex_iterator = EMPTY_VERTEX_ITERATOR
35
- @adjacent_iterator = EMPTY_NEIGHBOR_ITERATOR
36
- yield self if block_given? # let client overwrite defaults
37
- end
38
-
39
- # Returns the value of @directed.
40
- def directed?; @directed; end
41
-
42
- def each_vertex (&block) # :nodoc:
43
- @vertex_iterator.call(block)
44
- end
45
-
46
- def each_adjacent (v, &block) # :nodoc:
47
- @adjacent_iterator.call(v,block)
48
- end
49
-
50
- def each_edge (&block) # :nodoc:
51
- if defined? @edge_iterator
52
- @edge_iterator.call(block)
53
- else
54
- super # use default implementation
55
- end
56
- end
57
-
58
- # Sets the vertex_iterator to _block_ which must be a block of one parameter
59
- # which again is the block called by each_vertex.
60
- def vertex_iterator (&block)
61
- @vertex_iterator = block
62
- end
63
-
64
- # Sets the adjacent_iterator to _block_ which must be a block of two
65
- # parameters:
66
- # The first parameter is the vertex the neighbors of which are to be
67
- # traversed. The second is the block which will be called for each neighbor
68
- # of this vertex.
69
- def adjacent_iterator (&block)
70
- @adjacent_iterator = block
71
- end
72
-
73
- # Sets the edge_iterator to _block_ which must be a block of two parameters:
74
- # The first parameter is the source of the edges an the second is the target
75
- # of the edge.
76
- def edge_iterator (&block)
77
- @edge_iterator = block
78
- end
79
- end
26
+
27
+ include Graph
28
+
29
+ attr_writer :directed
30
+
31
+ EMPTY_VERTEX_ITERATOR = proc { |b| }
32
+ EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
33
+
34
+ # Create a new ImplicitGraph, which is empty by default. The caller should
35
+ # configure the graph using vertex and neighbor iterators. If the graph is
36
+ # directed, the client should set _directed_ to true. The default value
37
+ # for _directed_ is false.
38
+
39
+ def initialize
40
+ @directed = false
41
+ @vertex_iterator = EMPTY_VERTEX_ITERATOR
42
+ @adjacent_iterator = EMPTY_NEIGHBOR_ITERATOR
43
+ yield self if block_given? # Let client overwrite defaults.
44
+ end
45
+
46
+ # Returns the value of @directed.
47
+
48
+ def directed?
49
+ @directed
50
+ end
51
+
52
+ def each_vertex (&block) # :nodoc:
53
+ @vertex_iterator.call(block)
54
+ end
55
+
56
+ def each_adjacent (v, &block) # :nodoc:
57
+ @adjacent_iterator.call(v, block)
58
+ end
59
+
60
+ def each_edge (&block) # :nodoc:
61
+ if defined? @edge_iterator
62
+ @edge_iterator.call(block)
63
+ else
64
+ super # use default implementation
65
+ end
66
+ end
67
+
68
+ # Sets the vertex_iterator to _block_,
69
+ # which must be a block of one parameter
70
+ # which again is the block called by each_vertex.
71
+
72
+ def vertex_iterator (&block)
73
+ @vertex_iterator = block
74
+ end
75
+
76
+ # Sets the adjacent_iterator to _block_,
77
+ # which must be a block of two parameters:
78
+ #
79
+ # The first parameter is the vertex the neighbors of which are to be
80
+ # traversed.
81
+ #
82
+ # The second is the block which will be called for each neighbor
83
+ # of this vertex.
84
+
85
+ def adjacent_iterator (&block)
86
+ @adjacent_iterator = block
87
+ end
88
+
89
+ # Sets the edge_iterator to _block_, which must be a block of two
90
+ # parameters: The first parameter is the source of the edges; the
91
+ # second is the target of the edge.
92
+
93
+ def edge_iterator (&block)
94
+ @edge_iterator = block
95
+ end
96
+
97
+ end # class ImplicitGraph
98
+
80
99
 
81
100
  module Graph
82
- # ---
83
- # === Graph adaptors
84
- #
85
- # Return a new ImplicitGraph which has as vertices all vertices of the
86
- # receiver which satisfy the predicate _filter_.
87
- #
88
- # The methods provides similar functionaty as the BGL graph adapter
89
- # filtered_graph (see BOOST_DOC/filtered_graph.html).
90
- #
91
- # ==== Example
92
- #
93
- # def complete (n)
94
- # set = n.integer? ? (1..n) : n
95
- # RGL::ImplicitGraph.new { |g|
96
- # g.vertex_iterator { |b| set.each(&b) }
97
- # g.adjacent_iterator { |x, b|
98
- # set.each { |y| b.call(y) unless x == y }
99
- # }
100
- # }
101
- # end
102
- #
103
- # complete(4).to_s => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
104
- # complete(4).vertices_filtered_by {|v| v != 4}.to_s => "(1=2)(1=3)(2=3)"
105
- def vertices_filtered_by (&filter)
106
- implicit_graph {|g|
107
- g.vertex_iterator { |b|
108
- self.each_vertex { |v| b.call(v) if filter.call(v) }
109
- }
110
- g.adjacent_iterator { |v, b|
111
- self.each_adjacent(v) { |u| b.call(u) if filter.call(u) }
112
- }
113
- }
114
- end
115
-
116
- # Return a new ImplicitGraph which has as edges all edges of the receiver
117
- # which satisfy the predicate _filter_ (a block with to parameters).
118
- #
119
- # ==== Example
120
- #
121
- # g = complete(7).edges_filtered_by {|u,v| u+v == 7}
122
- # g.to_s => "(1=6)(2=5)(3=4)"
123
- # g.vertices => [1, 2, 3, 4, 5, 6, 7]
124
- def edges_filtered_by (&filter)
125
- implicit_graph {
126
- |g|
127
- g.adjacent_iterator { |v, b|
128
- self.each_adjacent(v) { |u|
129
- b.call(u) if filter.call(v,u)
130
- }
131
- }
132
- g.edge_iterator { |b|
133
- self.each_edge {|u,v| b.call(u,v) if filter.call(u,v)}
134
- }
135
- }
136
- end
137
-
138
- # Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
139
- # vertices) to the receiver. It is a shortcut also used by
140
- # edges_filtered_by and vertices_filtered_by.
141
- def implicit_graph
142
- result = ImplicitGraph.new {|g|
143
- g.vertex_iterator { |b| self.each_vertex(&b)}
144
- g.adjacent_iterator { |v, b| self.each_adjacent(v,&b)}
145
- g.directed = self.directed?
146
- }
147
- yield result if block_given? # let client overwrite defaults
148
- result
149
- end
150
- end # module Graph
151
- end
101
+
102
+ # ---
103
+ # === Graph adaptors
104
+ #
105
+ # Return a new ImplicitGraph which has as vertices all vertices of the
106
+ # receiver which satisfy the predicate _filter_.
107
+ #
108
+ # The methods provides similar functionaty as the BGL graph adapter
109
+ # filtered_graph (see BOOST_DOC/filtered_graph.html).
110
+ #
111
+ # ==== Example
112
+ #
113
+ # def complete (n)
114
+ # set = n.integer? ? (1..n) : n
115
+ # RGL::ImplicitGraph.new { |g|
116
+ # g.vertex_iterator { |b| set.each(&b) }
117
+ # g.adjacent_iterator { |x, b|
118
+ # set.each { |y| b.call(y) unless x == y }
119
+ # }
120
+ # }
121
+ # end
122
+ #
123
+ # complete(4).to_s => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
124
+ # complete(4).vertices_filtered_by {|v| v != 4}.to_s => "(1=2)(1=3)(2=3)"
125
+
126
+ def vertices_filtered_by (&filter)
127
+ implicit_graph { |g|
128
+ g.vertex_iterator { |b|
129
+ self.each_vertex { |v| b.call(v) if filter.call(v) }
130
+ }
131
+ g.adjacent_iterator { |v, b|
132
+ self.each_adjacent(v) { |u| b.call(u) if filter.call(u) }
133
+ }
134
+ }
135
+ end
136
+
137
+ # Return a new ImplicitGraph which has as edges all edges of the receiver
138
+ # which satisfy the predicate _filter_ (a block with two parameters).
139
+ #
140
+ # ==== Example
141
+ #
142
+ # g = complete(7).edges_filtered_by {|u,v| u+v == 7}
143
+ # g.to_s => "(1=6)(2=5)(3=4)"
144
+ # g.vertices => [1, 2, 3, 4, 5, 6, 7]
145
+
146
+ def edges_filtered_by (&filter)
147
+ implicit_graph { |g|
148
+ g.adjacent_iterator { |v, b|
149
+ self.each_adjacent(v) { |u|
150
+ b.call(u) if filter.call(v, u)
151
+ }
152
+ }
153
+ g.edge_iterator { |b|
154
+ self.each_edge { |u,v| b.call(u, v) if filter.call(u, v) }
155
+ }
156
+ }
157
+ end
158
+
159
+ # Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
160
+ # vertices) to the receiver. It is a shortcut, also used by
161
+ # edges_filtered_by and vertices_filtered_by.
162
+
163
+ def implicit_graph
164
+ result = ImplicitGraph.new { |g|
165
+ g.vertex_iterator { |b| self.each_vertex(&b) }
166
+ g.adjacent_iterator { |v, b| self.each_adjacent(v, &b) }
167
+ g.directed = self.directed?
168
+ }
169
+ yield result if block_given? # let client overwrite defaults
170
+ result
171
+ end
172
+
173
+ end # module Graph
174
+ end # module RGL
@@ -1,54 +1,75 @@
1
+ # mutable.rb
2
+
1
3
  require 'rgl/base'
2
4
 
3
5
  module RGL
6
+
4
7
  # A MutableGraph can be changed via the addition or removal of edges and
5
8
  # vertices.
9
+
6
10
  module MutableGraph
7
- include Graph
8
-
9
- # Add a new vertex _v_ to the graph. If the vertex is already in (using
10
- # eql?) the method does nothing.
11
- def add_vertex(v); raise NotImplementedError; end
12
-
13
- # Inserts the edge (u,v) into the graph.
14
- #
15
- # Note that for undirected graphs, (u,v) is the same edge as (v,u), so after
16
- # a call to the function add_edge(), this implies that edge (u,v) will
17
- # appear in the out-edges of u and (u,v) (or equivalently (v,u)) will appear
18
- # in the out-edges of
19
- # v. Put another way, v will be adjacent to u and u will be adjacent to v.
20
- def add_edge(u, v); raise NotImplementedError; end
21
-
22
- # Add all objects in _a_ to the vertex set.
23
- def add_vertices (*a)
24
- a.each {|v| add_vertex v}
25
- end
26
-
27
- # Add all edges in the _edges_ array to the edge set. Element of the array
28
- # can be both two element arrays or instances of DirectedEdge or
29
- # UnDirectedEdge.
30
- def add_edges (*edges)
31
- edges.each {|edge| add_edge(edge[0],edge[1])}
32
- end
33
-
34
- # Remove u from the vertex set of the graph. All edges who's target is _v_
35
- # are also removed from the edge set of the graph.
36
- #
37
- # Postcondition: num_vertices is one less, _v_ no longer appears in the
38
- # vertex set of the graph and there no edge with source or target _v_.
39
- def remove_vertex(v); raise NotImplementedError; end
40
-
41
- # Remove the edge (u,v) from the graph. If the graph allows parallel edges
42
- # this remove all occurrences of (u,v).
43
- #
44
- # Precondition: u and v are vertices in the graph.
45
- # Postcondition: (u,v) is no longer in the edge set for g.
46
- def remove_edge(u, v); raise NotImplementedError; end
47
-
48
- # Remove all vertices specified by the array a from the graph calling
49
- # remove_vertex.
50
- def remove_vertices (*a)
51
- a.each {|v| remove_vertex v}
52
- end
53
- end
54
- end
11
+
12
+ include Graph
13
+
14
+ # Add a new vertex _v_ to the graph. If the vertex is already in the
15
+ # graph (tested via eql?), the method does nothing.
16
+
17
+ def add_vertex (v)
18
+ raise NotImplementedError
19
+ end
20
+
21
+ # Inserts the edge (u,v) into the graph.
22
+ #
23
+ # Note that for undirected graphs, (u,v) is the same edge as (v,u), so
24
+ # after a call to the function add_edge(), this implies that edge (u,v)
25
+ # will appear in the out-edges of u and (u,v) (or equivalently (v,u))
26
+ # will appear in the out-edges of v. Put another way, v will be adjacent
27
+ # to u and u will be adjacent to v.
28
+
29
+ def add_edge (u, v)
30
+ raise NotImplementedError
31
+ end
32
+
33
+ # Add all objects in _a_ to the vertex set.
34
+
35
+ def add_vertices (*a)
36
+ a.each { |v| add_vertex v }
37
+ end
38
+
39
+ # Add all edges in the _edges_ array to the edge set. Elements of the
40
+ # array can be both two-element arrays or instances of DirectedEdge or
41
+ # UnDirectedEdge.
42
+
43
+ def add_edges (*edges)
44
+ edges.each { |edge| add_edge(edge[0], edge[1]) }
45
+ end
46
+
47
+ # Remove u from the vertex set of the graph. All edges whose target is
48
+ # _v_ are also removed from the edge set of the graph.
49
+ #
50
+ # Postcondition: num_vertices is one less, _v_ no longer appears in the
51
+ # vertex set of the graph, and there no edge with source or target _v_.
52
+
53
+ def remove_vertex (v)
54
+ raise NotImplementedError
55
+ end
56
+
57
+ # Remove the edge (u,v) from the graph. If the graph allows parallel
58
+ # edges, this removes all occurrences of (u,v).
59
+ #
60
+ # Precondition: u and v are vertices in the graph.
61
+ # Postcondition: (u,v) is no longer in the edge set for g.
62
+
63
+ def remove_edge (u, v)
64
+ raise NotImplementedError
65
+ end
66
+
67
+ # Remove all vertices specified by the array a from the graph by calling
68
+ # remove_vertex.
69
+
70
+ def remove_vertices (*a)
71
+ a.each { |v| remove_vertex v }
72
+ end
73
+
74
+ end # module MutableGraph
75
+ end # module RGL
@@ -1,168 +1,216 @@
1
+ # rdot.rb
1
2
  #
2
- # $Id: rdot.rb,v 1.2 2002/11/13 21:53:26 monora Exp $
3
+ # $Id: rdot.rb,v 1.4 2005/03/26 15:06:36 wsdng Exp $
3
4
  #
4
- # This is a modified version of dot.rb from Dave Thomas rdoc project. I renamed
5
- # it to rdot.rb to avoid collision with an installed rdoc/dot.
5
+ # This is a modified version of dot.rb from Dave Thomas's rdoc project. I
6
+ # renamed it to rdot.rb to avoid collision with an installed rdoc/dot.
6
7
  #
7
8
  # It also supports undirected edges.
8
9
 
9
10
  module DOT
10
11
 
11
- # these glogal vars are used to make nice graph source
12
- $tab = ' '
13
- $tab2 = $tab * 2
12
+ # These glogal vars are used to make nice graph source.
13
+
14
+ $tab = ' '
15
+ $tab2 = $tab * 2
14
16
 
15
- # if we don't like 4 spaces, we can change it any time
16
- def change_tab( t )
17
- $tab = t
18
- $tab2 = t * 2
19
- end
17
+ # if we don't like 4 spaces, we can change it any time
18
+
19
+ def change_tab (t)
20
+ $tab = t
21
+ $tab2 = t * 2
22
+ end
20
23
 
21
- # options for node declaration
22
- NODE_OPTS = [
23
- 'bgcolor',
24
- 'color',
25
- 'fontcolor',
26
- 'fontname',
27
- 'fontsize',
28
- 'heigth',
29
- 'width',
30
- 'label',
31
- 'layer',
32
- 'rank',
33
- 'shape',
34
- 'shapefile',
35
- 'style',
36
- ]
24
+ # options for node declaration
25
+
26
+ NODE_OPTS = [
27
+ # attributes due to
28
+ # http://www.graphviz.org/Documentation/dotguide.pdf
29
+ # March, 26, 2005
30
+ 'bottomlabel', # auxiliary label for nodes of shape M*
31
+ 'color', # default: black; node shape color
32
+ 'comment', # any string (format-dependent)
33
+ 'distortion', # default: 0.0; node distortion for shape=polygon
34
+ 'fillcolor', # default: lightgrey/black; node fill color
35
+ 'fixedsize', # default: false; label text has no affect on node size
36
+ 'fontcolor', # default: black; type face color
37
+ 'fontname', # default: Times-Roman; font family
38
+ 'fontsize', #default: 14; point size of label
39
+ 'group', # name of node�s group
40
+ 'height', # default: .5; height in inches
41
+ 'label', # default: node name; any string
42
+ 'layer', # default: overlay range; all, id or id:id
43
+ 'orientation', # dafault: 0.0; node rotation angle
44
+ 'peripheries', # shape-dependent number of node boundaries
45
+ 'regular', # default: false; force polygon to be regular
46
+ 'shape', # default: ellipse; node shape; see Section 2.1 and Appendix E
47
+ 'shapefile', # external EPSF or SVG custom shape file
48
+ 'sides', # default: 4; number of sides for shape=polygon
49
+ 'skew' , # default: 0.0; skewing of node for shape=polygon
50
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
51
+ 'toplabel', # auxiliary label for nodes of shape M*
52
+ 'URL', # URL associated with node (format-dependent)
53
+ 'width', # default: .75; width in inches
54
+ 'z', #default: 0.0; z coordinate for VRML output
55
+
56
+ # maintained for backward compatibility or rdot internal
57
+ 'bgcolor',
58
+ 'rank'
59
+ ]
37
60
 
38
- # options for edge declaration
39
- EDGE_OPTS = [
40
- 'color',
41
- 'decorate',
42
- 'dir',
43
- 'fontcolor',
44
- 'fontname',
45
- 'fontsize',
46
- 'id',
47
- 'label',
48
- 'layer',
49
- 'minlen',
50
- 'style',
51
- 'weight'
52
- ]
61
+ # options for edge declaration
62
+
63
+ EDGE_OPTS = [
64
+ 'arrowhead', # default: normal; style of arrowhead at head end
65
+ 'arrowsize', # default: 1.0; scaling factor for arrowheads
66
+ 'arrowtail', # default: normal; style of arrowhead at tail end
67
+ 'color', # default: black; edge stroke color
68
+ 'comment', # any string (format-dependent)
69
+ 'constraint', # default: true use edge to affect node ranking
70
+ 'decorate', # if set, draws a line connecting labels with their edges
71
+ 'dir', # default: forward; forward, back, both, or none
72
+ 'fontcolor', # default: black type face color
73
+ 'fontname', # default: Times-Roman; font family
74
+ 'fontsize', # default: 14; point size of label
75
+ 'headlabel', # label placed near head of edge
76
+ 'headport', # n,ne,e,se,s,sw,w,nw
77
+ 'headURL', # URL attached to head label if output format is ismap
78
+ 'label', # edge label
79
+ 'labelangle', # default: -25.0; angle in degrees which head or tail label is rotated off edge
80
+ 'labeldistance', # default: 1.0; scaling factor for distance of head or tail label from node
81
+ 'labelfloat', # default: false; lessen constraints on edge label placement
82
+ 'labelfontcolor', # default: black; type face color for head and tail labels
83
+ 'labelfontname', # default: Times-Roman; font family for head and tail labels
84
+ 'labelfontsize', # default: 14 point size for head and tail labels
85
+ 'layer', # default: overlay range; all, id or id:id
86
+ 'lhead', # name of cluster to use as head of edge
87
+ 'ltail', # name of cluster to use as tail of edge
88
+ 'minlen', # default: 1 minimum rank distance between head and tail
89
+ 'samehead', # tag for head node; edge heads with the same tag are merged onto the same port
90
+ 'sametail', # tag for tail node; edge tails with the same tag are merged onto the same port
91
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
92
+ 'taillabel', # label placed near tail of edge
93
+ 'tailport', # n,ne,e,se,s,sw,w,nw
94
+ 'tailURL', # URL attached to tail label if output format is ismap
95
+ 'weight', # default: 1; integer cost of stretching an edge
96
+
97
+ # maintained for backward compatibility or rdot internal
98
+ 'id'
99
+ ]
53
100
 
54
- # options for graph declaration
55
- GRAPH_OPTS = [
56
- 'bgcolor',
57
- 'center',
58
- 'clusterrank',
59
- 'color',
60
- 'concentrate',
61
- 'fontcolor',
62
- 'fontname',
63
- 'fontsize',
64
- 'label',
65
- 'layerseq',
66
- 'margin',
67
- 'mclimit',
68
- 'nodesep',
69
- 'nslimit',
70
- 'ordering',
71
- 'orientation',
72
- 'page',
73
- 'rank',
74
- 'rankdir',
75
- 'ranksep',
76
- 'ratio',
77
- 'size'
78
- ]
101
+ # options for graph declaration
102
+
103
+ GRAPH_OPTS = [
104
+ 'bgcolor',
105
+ 'center', 'clusterrank', 'color', 'concentrate',
106
+ 'fontcolor', 'fontname', 'fontsize',
107
+ 'label', 'layerseq',
108
+ 'margin', 'mclimit',
109
+ 'nodesep', 'nslimit',
110
+ 'ordering', 'orientation',
111
+ 'page',
112
+ 'rank', 'rankdir', 'ranksep', 'ratio',
113
+ 'size'
114
+ ]
79
115
 
80
- # a root class for any element in dot notation
81
- class DOTSimpleElement
82
- attr_accessor :name
116
+ # a root class for any element in dot notation
83
117
 
84
- def initialize( params = {} )
85
- @label = params['name'] ? params['name'] : ''
86
- end
118
+ class DOTSimpleElement
87
119
 
88
- def to_s
89
- @name
90
- end
120
+ attr_accessor :name
121
+
122
+ def initialize (params = {})
123
+ @label = params['name'] ? params['name'] : ''
124
+ end
125
+
126
+ def to_s
127
+ @name
91
128
  end
129
+ end
92
130
 
93
- # an element that have options ( node, edge or graph )
94
- class DOTElement < DOTSimpleElement
95
- #attr_reader :parent
96
- attr_accessor :name, :options
97
-
98
- def initialize( params = {}, option_list = [] )
99
- super( params )
100
- @name = params['name'] ? params['name'] : nil
101
- @parent = params['parent'] ? params['parent'] : nil
102
- @options = {}
103
- option_list.each{ |i|
104
- @options[i] = params[i] if params[i]
105
- }
106
- @options['label'] ||= @name if @name != 'node'
107
- end
131
+ # an element that has options ( node, edge, or graph )
132
+
133
+ class DOTElement < DOTSimpleElement
134
+
135
+ # attr_reader :parent
136
+ attr_accessor :name, :options
137
+
138
+ def initialize (params = {}, option_list = [])
139
+ super(params)
140
+ @name = params['name'] ? params['name'] : nil
141
+ @parent = params['parent'] ? params['parent'] : nil
142
+ @options = {}
143
+ option_list.each{ |i|
144
+ @options[i] = params[i] if params[i]
145
+ }
146
+ @options['label'] ||= @name if @name != 'node'
147
+ end
108
148
 
109
- def each_option
110
- @options.each{ |i| yield i }
111
- end
112
-
113
- def each_option_pair
114
- @options.each_pair{ |key, val| yield key, val }
115
- end
116
-
117
- #def parent=( thing )
118
- # @parent.delete( self ) if defined?( @parent ) and @parent
119
- # @parent = thing
120
- #end
149
+ def each_option
150
+ @options.each{ |i| yield i }
121
151
  end
152
+
153
+ def each_option_pair
154
+ @options.each_pair{ |key, val| yield key, val }
155
+ end
156
+
157
+ #def parent=( thing )
158
+ # @parent.delete( self ) if defined?( @parent ) and @parent
159
+ # @parent = thing
160
+ #end
161
+
162
+ end
122
163
 
123
164
 
124
- # this is used when we build nodes that have shape=record
125
- # ports don't have options :)
126
- class DOTPort < DOTSimpleElement
127
- attr_accessor :label
165
+ # This is used when we build nodes that have shape=record
166
+ # ports don't have options :)
167
+
168
+ class DOTPort < DOTSimpleElement
169
+
170
+ attr_accessor :label
128
171
 
129
- def initialize( params = {} )
130
- super( params )
131
- @name = params['label'] ? params['label'] : ''
132
- end
133
- def to_s
134
- ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
135
- end
172
+ def initialize (params = {})
173
+ super(params)
174
+ @name = params['label'] ? params['label'] : ''
175
+ end
176
+
177
+ def to_s
178
+ ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
136
179
  end
180
+ end
137
181
 
138
- # node element
139
- class DOTNode < DOTElement
140
- @ports
182
+ # node element
183
+
184
+ class DOTNode < DOTElement
141
185
 
142
- def initialize( params = {}, option_list = NODE_OPTS )
143
- super( params, option_list )
144
- @ports = params['ports'] ? params['ports'] : []
145
- end
186
+ @ports
187
+
188
+ def initialize (params = {}, option_list = NODE_OPTS)
189
+ super(params, option_list)
190
+ @ports = params['ports'] ? params['ports'] : []
191
+ end
146
192
 
147
- def each_port
148
- @ports.each{ |i| yield i }
149
- end
193
+ def each_port
194
+ @ports.each { |i| yield i }
195
+ end
196
+
197
+ def << (thing)
198
+ @ports << thing
199
+ end
150
200
 
151
- def << ( thing )
152
- @ports << thing
153
- end
201
+ def push (thing)
202
+ @ports.push(thing)
203
+ end
154
204
 
155
- def push ( thing )
156
- @ports.push( thing )
157
- end
205
+ def pop
206
+ @ports.pop
207
+ end
158
208
 
159
- def pop
160
- @ports.pop
161
- end
209
+ def to_s (t = '')
162
210
 
163
- def to_s( t = '' )
211
+ # This code is totally incomprehensible; it needs to be replaced!
164
212
 
165
- label = @options['shape'] != 'record' && @ports.length == 0 ?
213
+ label = @options['shape'] != 'record' && @ports.length == 0 ?
166
214
  @options['label'] ?
167
215
  t + $tab + "label = \"#{@options['label']}\"\n" :
168
216
  '' :
@@ -180,85 +228,100 @@ module DOT
180
228
  }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
181
229
  label +
182
230
  t + "]\n"
183
- end
231
+ end
232
+
233
+ end # class DOTNode
234
+
235
+ # A subgraph element is the same to graph, but has another header in dot
236
+ # notation.
237
+
238
+ class DOTSubgraph < DOTElement
239
+
240
+ @nodes
241
+ @dot_string
242
+
243
+ def initialize (params = {}, option_list = GRAPH_OPTS)
244
+ super(params, option_list)
245
+ @nodes = params['nodes'] ? params['nodes'] : []
246
+ @dot_string = 'graph'
184
247
  end
185
248
 
186
- # subgraph element is the same to graph, but has another header in dot
187
- # notation
188
- class DOTSubgraph < DOTElement
189
- @nodes
190
- @dot_string
191
-
192
- def initialize( params = {}, option_list = GRAPH_OPTS )
193
- super( params, option_list )
194
- @nodes = params['nodes'] ? params['nodes'] : []
195
- @dot_string = 'graph'
196
- end
197
-
198
- def each_node
199
- @nodes.each{ |i| yield i }
200
- end
201
-
202
- def << ( thing )
203
- @nodes << thing
204
- end
249
+ def each_node
250
+ @nodes.each{ |i| yield i }
251
+ end
252
+
253
+ def << (thing)
254
+ @nodes << thing
255
+ end
205
256
 
206
- def push( thing )
207
- @nodes.push( thing )
208
- end
209
-
210
- def pop
211
- @nodes.pop
212
- end
213
-
214
- def to_s( t = '' )
215
- hdr = t + "#{@dot_string} #{@name} {\n"
216
-
217
- options = @options.to_a.collect{ |name, val|
218
- val && name != 'label' ?
219
- t + $tab + "#{name} = #{val}" :
220
- name ? t + $tab + "#{name} = \"#{val}\"" : nil
221
- }.compact.join( "\n" ) + "\n"
222
-
223
- nodes = @nodes.collect{ |i|
224
- i.to_s( t + $tab )
225
- }.join( "\n" ) + "\n"
226
- hdr + options + nodes + t + "}\n"
227
- end
257
+ def push (thing)
258
+ @nodes.push( thing )
228
259
  end
229
260
 
230
- # this is graph
231
- class DOTDigraph < DOTSubgraph
232
- def initialize( params = {}, option_list = GRAPH_OPTS )
233
- super( params, option_list )
234
- @dot_string = 'digraph'
235
- end
261
+ def pop
262
+ @nodes.pop
236
263
  end
237
264
 
238
- # this is edge
239
- class DOTEdge < DOTElement
240
- attr_accessor :from, :to
241
- def initialize( params = {}, option_list = EDGE_OPTS )
242
- super( params, option_list )
243
- @from = params['from'] ? params['from'] : nil
244
- @to = params['to'] ? params['to'] : nil
245
- end
265
+ def to_s (t = '')
266
+ hdr = t + "#{@dot_string} #{@name} {\n"
267
+
268
+ options = @options.to_a.collect{ |name, val|
269
+ val && name != 'label' ?
270
+ t + $tab + "#{name} = #{val}" :
271
+ name ? t + $tab + "#{name} = \"#{val}\"" : nil
272
+ }.compact.join( "\n" ) + "\n"
273
+
274
+ nodes = @nodes.collect{ |i|
275
+ i.to_s( t + $tab )
276
+ }.join( "\n" ) + "\n"
277
+ hdr + options + nodes + t + "}\n"
278
+ end
279
+
280
+ end # class DOTSubgraph
281
+
282
+ # This is a graph.
283
+
284
+ class DOTDigraph < DOTSubgraph
285
+
286
+ def initialize (params = {}, option_list = GRAPH_OPTS)
287
+ super(params, option_list)
288
+ @dot_string = 'digraph'
289
+ end
290
+
291
+ end # class DOTDigraph
292
+
293
+ # This is an edge.
294
+
295
+ class DOTEdge < DOTElement
296
+
297
+ attr_accessor :from, :to
298
+
299
+ def initialize (params = {}, option_list = EDGE_OPTS)
300
+ super(params, option_list)
301
+ @from = params['from'] ? params['from'] : nil
302
+ @to = params['to'] ? params['to'] : nil
303
+ end
246
304
 
247
- def edge_link; '--'; end
248
- def to_s( t = '' )
249
- t + "#{@from} #{edge_link} #{to} [\n" +
250
- @options.to_a.collect{ |i|
251
- i[1] && i[0] != 'label' ?
252
- t + $tab + "#{i[0]} = #{i[1]}" :
253
- i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
254
- }.compact.join( "\n" ) + "\n" + t + "]\n"
255
- end
305
+ def edge_link
306
+ '--'
256
307
  end
257
-
258
- class DOTDirectedEdge < DOTEdge
259
- def edge_link; '->'; end
260
- end
261
- end
262
308
 
309
+ def to_s (t = '')
310
+ t + "#{@from} #{edge_link} #{to} [\n" +
311
+ @options.to_a.collect{ |i|
312
+ i[1] && i[0] != 'label' ?
313
+ t + $tab + "#{i[0]} = #{i[1]}" :
314
+ i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
315
+ }.compact.join( "\n" ) + "\n" + t + "]\n"
316
+ end
317
+
318
+ end # class DOTEdge
319
+
320
+ class DOTDirectedEdge < DOTEdge
263
321
 
322
+ def edge_link
323
+ '->'
324
+ end
264
325
 
326
+ end # class DOTDirectedEdge
327
+ end # module DOT