dotr 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/dotr.rb +145 -0
  2. data/test/dotr_test.rb +111 -0
  3. metadata +46 -0
@@ -0,0 +1,145 @@
1
+ module DotR
2
+ # This class represents a directed graph that can be rendered to a graphics
3
+ # image using its #diagram method.
4
+ #
5
+ # Example:
6
+ # d = DotR::Digraph.new do |g|
7
+ # g.node('node1') do |n|
8
+ # n.label = "MyLabel"
9
+ # n.fontsize="8"
10
+ # end
11
+ # g.node('node2', :label => 'SecondNode') do |n|
12
+ # n.connection('node1', :label => 'relates to')
13
+ # end
14
+ # end
15
+ # File.open('diagram.png', 'w') { |f| f.write(d.diagram(:png)) }
16
+ class Digraph
17
+ attr_accessor :name
18
+ # Create a new Digraph. If a block is provided it will be called with
19
+ # the graph as a parameter.
20
+ def initialize(name="diagram", &block)
21
+ @name = name
22
+ @nodes = []
23
+ yield self if block
24
+ end
25
+
26
+ # Create a Node in the graph with a given name. If a block is provided
27
+ # it will be called with the node as a parameter, for convenient adding of
28
+ # connections or specification of style attributes.
29
+ def node(name, style={}, &block)
30
+ @nodes << Node.new(name, style, &block)
31
+ end
32
+
33
+ # Create a connection in the graph between two nodes with the given names.
34
+ # If a block is provided # it will be called with the connection as a parameter,
35
+ # for convenient specification of styles.
36
+ #
37
+ # Nodes with the given names are implicitly created if they have not
38
+ # been explicitly added. See Node#connection
39
+ def connection(from_node_name, to_node_name, style={}, &block)
40
+ node(from_node_name) do |n|
41
+ n.connection(to_node_name, style, &block)
42
+ end
43
+ end
44
+
45
+ # Returns the dot input script equivalent of this digraph
46
+ def to_s
47
+ script = []
48
+ render_to(script)
49
+ script.flatten.join("\n") + "\n"
50
+ end
51
+
52
+ # Render the diagram to a graphic image, returning the raw image data as
53
+ # a string.
54
+ #
55
+ # Possible values for +format+ include +:svg+, +:png+, +:ps+, +:gif+
56
+ def diagram(format=:png)
57
+ Tempfile.open("diag") do |input|
58
+ input.write(self.to_s)
59
+ input.flush
60
+ return IO.popen("dot -T#{format} #{input.path}") { |dot| dot.read }
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def render_to(output_lines)
67
+ output_lines << "digraph \"#{name}\" {"
68
+ @nodes.each { |node| node.render_to(output_lines) }
69
+ output_lines << '}'
70
+ end
71
+
72
+ end
73
+
74
+ private
75
+
76
+ module Styled # :nodoc:
77
+ def method_missing(method, *args)
78
+ return super unless /^(\w+)=$/ =~ method.to_s && args.size == 1
79
+ style_attrs()[$1.to_sym] = args.first
80
+ end
81
+
82
+ def style
83
+ return '' if style_attrs.empty?
84
+ " [" + style_attrs.keys.sort_by { |k| k.to_s }.map { |k| "#{k}=\"#{style_attrs[k]}\"" }.join(',') + "]"
85
+ end
86
+
87
+ private
88
+
89
+ def style_attrs
90
+ @style_attrs ||= {}
91
+ end
92
+ end
93
+
94
+ # Represents a node in a digraph. Instances of this class are created by calling
95
+ # Digraph#node.
96
+ #
97
+ # Specify styles on this object by setting instance attributes.
98
+ # Possible attributes include 'label' and 'shape'; the attribute names and
99
+ # possible values correspond to the style attributes described in the 'dot' manual.
100
+ class Node
101
+ include Styled
102
+ attr_reader :name
103
+
104
+ def initialize(name, style={}, &block) #:nodoc:
105
+ @name = name
106
+ @connections = []
107
+ self.label = name
108
+ style_attrs.update(style)
109
+ yield self if block
110
+ end
111
+
112
+ def connection(other_node_name, style={}, &block)
113
+ @connections << Connection.new(self.name, other_node_name, style, &block)
114
+ end
115
+
116
+ def render_to(output_lines) #:nodoc:
117
+ output_lines << "\"#{self.name}\"" + style + ";"
118
+ @connections.each { |c| c.render_to(output_lines) }
119
+ end
120
+ end
121
+
122
+ # Represents a connection between two nodes in a digraph.
123
+ # Instances of this class are created by calling Digraph#connection or
124
+ # Node#connection.
125
+ #
126
+ # Specify styles on this object by setting instance attributes.
127
+ # Possible attributes include 'label' and 'shape'; the attribute names and
128
+ # possible values correspond to the style attributes described in the 'dot' manual.
129
+ class Connection
130
+ include Styled
131
+ attr_reader :from_name, :to_name
132
+
133
+ def initialize(from_name, to_name, style={}, &block) #:nodoc:
134
+ @from_name = from_name
135
+ @to_name = to_name
136
+ style_attrs.update(style)
137
+ yield self if block
138
+ end
139
+
140
+ def render_to(output_lines) # :nodoc:
141
+ output_lines << "\"#{from_name}\" -> \"#{to_name}\"" + style + ";"
142
+ end
143
+ end
144
+ end
145
+
@@ -0,0 +1,111 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
2
+
3
+ require 'test/unit'
4
+ require 'dotr'
5
+
6
+ class DotRDigraphTest < Test::Unit::TestCase
7
+
8
+ def test_empty_digraph
9
+ d = DotR::Digraph.new('myname')
10
+ assert_digraph_equals <<-END, d
11
+ digraph "myname" {
12
+ }
13
+ END
14
+ end
15
+
16
+ def test_single_node
17
+ d = DotR::Digraph.new do |graph|
18
+ graph.node('somenode')
19
+ end
20
+ assert_digraph_equals <<-END, d
21
+ digraph "diagram" {
22
+ "somenode" [label="somenode"];
23
+ }
24
+ END
25
+ end
26
+
27
+ def test_connection_with_node
28
+ d = DotR::Digraph.new do |graph|
29
+ graph.node 'somenode' do |node|
30
+ node.connection('someothernode')
31
+ end
32
+ end
33
+ assert_digraph_equals <<-END, d
34
+ digraph "diagram" {
35
+ "somenode" [label="somenode"];
36
+ "somenode" -> "someothernode";
37
+ }
38
+ END
39
+ end
40
+
41
+ def test_connection_without_node
42
+ d = DotR::Digraph.new do |graph|
43
+ graph.connection('somenode', 'someothernode')
44
+ end
45
+ assert_digraph_equals <<-END, d
46
+ digraph "diagram" {
47
+ "somenode" [label="somenode"];
48
+ "somenode" -> "someothernode";
49
+ }
50
+ END
51
+ end
52
+
53
+ def test_can_style_nodes_with_block
54
+ d = DotR::Digraph.new do |graph|
55
+ graph.node('somenode') do |node|
56
+ node.label = "MyLabel"
57
+ node.fontsize="8"
58
+ end
59
+ end
60
+ assert_digraph_equals <<-END, d
61
+ digraph "diagram" {
62
+ "somenode" [fontsize="8",label="MyLabel"];
63
+ }
64
+ END
65
+ end
66
+
67
+ def test_can_style_connections_with_block
68
+ d = DotR::Digraph.new do |graph|
69
+ graph.connection('somenode', 'someothernode') do |node|
70
+ node.label = "MyLabel"
71
+ node.fontsize="8"
72
+ end
73
+ end
74
+ assert_digraph_equals <<-END, d
75
+ digraph "diagram" {
76
+ "somenode" [label="somenode"];
77
+ "somenode" -> "someothernode" [fontsize="8",label="MyLabel"];
78
+ }
79
+ END
80
+ end
81
+
82
+ def test_can_style_nodes_with_hash
83
+ d = DotR::Digraph.new do |graph|
84
+ graph.node('somenode', :label => "MyLabel", :fontsize => 8)
85
+ end
86
+ assert_digraph_equals <<-END, d
87
+ digraph "diagram" {
88
+ "somenode" [fontsize="8",label="MyLabel"];
89
+ }
90
+ END
91
+ end
92
+
93
+ def test_can_style_connections_with_hash
94
+ d = DotR::Digraph.new do |graph|
95
+ graph.connection('somenode', 'someothernode', :label => "MyLabel", :fontsize => 8)
96
+ end
97
+ assert_digraph_equals <<-END, d
98
+ digraph "diagram" {
99
+ "somenode" [label="somenode"];
100
+ "somenode" -> "someothernode" [fontsize="8",label="MyLabel"];
101
+ }
102
+ END
103
+ end
104
+
105
+ private
106
+
107
+ def assert_digraph_equals expected, digraph
108
+ assert_equal(expected.strip.gsub(/^\s+/, ''), digraph.to_s.strip)
109
+ end
110
+
111
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: dotr
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2006-07-14 00:00:00 +02:00
8
+ summary: Produce directed graph images using the 'dot' utility.
9
+ require_paths:
10
+ - lib
11
+ email:
12
+ homepage:
13
+ rubyforge_project:
14
+ description: ""
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors: []
29
+
30
+ files:
31
+ - lib/dotr.rb
32
+ - test/dotr_test.rb
33
+ test_files: []
34
+
35
+ rdoc_options: []
36
+
37
+ extra_rdoc_files: []
38
+
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ requirements:
44
+ - none
45
+ dependencies: []
46
+