Graphiclious 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/README.txt +126 -0
  2. data/Rakefile +28 -0
  3. data/bin/graphiclious +3 -0
  4. data/doc/cloud.jpg +0 -0
  5. data/doc/index.html +32 -0
  6. data/doc/screenshots/default.css +44 -0
  7. data/doc/screenshots/original/blue-style-1.html +37 -0
  8. data/doc/screenshots/original/blue-style-1.jpg +0 -0
  9. data/doc/screenshots/original/cornflower.html +37 -0
  10. data/doc/screenshots/original/cornflower.jpg +0 -0
  11. data/doc/screenshots/original/custom-style.html +37 -0
  12. data/doc/screenshots/original/custom-style.jpg +0 -0
  13. data/doc/screenshots/original/sample-graph.html +37 -0
  14. data/doc/screenshots/original/sample-graph.jpg +0 -0
  15. data/doc/screenshots/original/user-interface.html +37 -0
  16. data/doc/screenshots/original/user-interface.jpg +0 -0
  17. data/doc/screenshots/thumb.html +46 -0
  18. data/doc/screenshots/thumb/t_blue-style-1.jpg +0 -0
  19. data/doc/screenshots/thumb/t_cornflower.jpg +0 -0
  20. data/doc/screenshots/thumb/t_custom-style.jpg +0 -0
  21. data/doc/screenshots/thumb/t_sample-graph.jpg +0 -0
  22. data/doc/screenshots/thumb/t_user-interface.jpg +0 -0
  23. data/doc/style.css +60 -0
  24. data/gemspec.rb +45 -0
  25. data/lib/graphiclious.rb +78 -0
  26. data/lib/graphiclious/delicious2yaml.rb +235 -0
  27. data/lib/graphiclious/dot_attributes.rb +35 -0
  28. data/lib/graphiclious/environment.rb +36 -0
  29. data/lib/graphiclious/gui.rb +260 -0
  30. data/lib/graphiclious/help.rb +22 -0
  31. data/lib/graphiclious/require_fox.rb +12 -0
  32. data/lib/graphiclious/url_graph.rb +135 -0
  33. data/lib/graphiclious/utf8.rb +19 -0
  34. data/lib/graphiclious/version.rb +8 -0
  35. data/lib/graphiclious/yaml-links2html.rb +476 -0
  36. data/options.yaml +7 -0
  37. data/styles/blue-style-1/dot-attributes.yaml +21 -0
  38. data/styles/blue-style-1/extern.gif +0 -0
  39. data/styles/blue-style-1/style.css +128 -0
  40. data/styles/cornflower/cornflower.png +0 -0
  41. data/styles/cornflower/dot-attributes.yaml +21 -0
  42. data/styles/cornflower/extern.gif +0 -0
  43. data/styles/cornflower/h3.gif +0 -0
  44. data/styles/cornflower/menuitem.png +0 -0
  45. data/styles/cornflower/menuselected.png +0 -0
  46. data/styles/cornflower/style.css +149 -0
  47. data/styles/cornflower/tr-edge.png +0 -0
  48. data/test/test_delicious2yaml.rb +97 -0
  49. data/wickie +249 -0
  50. metadata +119 -0
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ #$Id: dot_attributes.rb,v 1.1 2005/04/13 21:16:14 wsdng Exp $
3
+
4
+ class DotAttributes
5
+ attr_accessor(:node_attributes,
6
+ :edge_attributes,
7
+ :graph_attributes)
8
+
9
+ def initialize
10
+ @node_attributes = {
11
+ 'shape' => 'box',
12
+ 'style' => 'filled',
13
+ 'height' => '0.2',
14
+ 'width' => '1',
15
+ #'fixedsize' => 'true',
16
+ 'fontname' => 'Arial',
17
+ 'fontsize' => '10',
18
+ 'fontcolor' => 'blue',
19
+ 'color' => 'orange',
20
+ 'fillcolor' => 'orange'
21
+ }
22
+ @edge_attributes = {}
23
+ @graph_attributes = {
24
+ 'bgcolor' => 'firebrick',
25
+ 'rankdir' => 'LR',
26
+ 'ranksep' => '0.2',
27
+ 'nodesep' => '0.1',
28
+ 'orientation' => 'portrait',
29
+ 'labelloc' => 'top',
30
+ 'label' => 'Tag Relations',
31
+ 'name' => 'UrlGraph'
32
+ }
33
+ end
34
+ end
35
+
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Require this file will set GRAPHICLIOUS_PATH to an appropriate value.
4
+ #
5
+ # The standard method is to find the installed gem and let
6
+ # GRAPHICLIOUS_PATH point to the gem's installation directory.
7
+ #
8
+ # If the gem isn't found, we assume that Graphiclious has been started
9
+ # from within the graphiclious directory itself and therefore set
10
+ # GRAPHICLIOUS_PATH = '.'. (This is often the case during development.)
11
+ #
12
+ # Note that GRAPHICLIOUS_PATH uses the Ruby notation of the path.
13
+ #
14
+ # So, what ist this good for? We need to find the style directories
15
+ # provided with the gem to make those styles availiable without any
16
+ # additional user interaction. We might use the path for finding icons
17
+ # or other user-independent ressource files, too.
18
+
19
+ begin
20
+ require 'rubygems'
21
+ require 'graphiclious/version.rb'
22
+
23
+ # Try to find lib directory of this specific Graphiclious gem version
24
+ def findGraphicliousDirectory
25
+ graphicliousGemDir = "Graphiclious-#{Graphiclious.version}"
26
+ all = Gem::path.collect { |gempath|
27
+ File.join(gempath, 'gems', graphicliousGemDir)
28
+ }.select { |f|
29
+ File.directory?(f)
30
+ }
31
+ all.empty? ? '.' : all.first
32
+ end
33
+ GRAPHICLIOUS_PATH = findGraphicliousDirectory
34
+ rescue LoadError
35
+ GRAPHICLIOUS_PATH = '.'
36
+ end
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env ruby
2
+ #$Id: gui.rb,v 1.18 2006/03/08 20:28:47 wsdng Exp $
3
+
4
+ require 'graphiclious/require_fox'
5
+ require 'graphiclious/delicious2yaml'
6
+ require 'graphiclious/yaml-links2html'
7
+
8
+ class GraphicliousMainWindow < Fox::FXMainWindow
9
+ include Fox
10
+ include Responder
11
+
12
+ def initialize(app, user=nil, password=nil, style=nil)
13
+ super(app, "Graphiclious")
14
+ @user = user
15
+ @password = password
16
+ @style = style
17
+ @stylesFolder = YamlLinksToHtml::STYLES_FOLDER
18
+ @workingDir = Dir.getwd
19
+ initView
20
+ updateUserList
21
+ updateStylesList
22
+ setOptionDelicious(false)
23
+ connect(SEL_CLOSE, method(:onCmdQuit))
24
+ end
25
+
26
+ def newButton(frame, txt)
27
+ b = FXButton.new(frame, txt)
28
+ b.setLayoutHints(LAYOUT_LEFT)
29
+ b.width = 100
30
+ b.height = 24
31
+ b
32
+ end
33
+
34
+ def newCheckBox(frame, txt)
35
+ cbFlags = ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP
36
+ cb = FXCheckButton.new(frame, txt, nil, 0, cbFlags)
37
+ cb.setCheck(true)
38
+ cb
39
+ end
40
+
41
+ def newFrame(frame)
42
+ frame.setFrameStyle(FRAME_NONE)
43
+ frame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X)
44
+ frame
45
+ end
46
+
47
+ def noPaddingForFrame(frame)
48
+ frame.padBottom = 0
49
+ frame.padLeft = 0
50
+ frame.padRight = 0
51
+ frame.padTop = 0
52
+ end
53
+
54
+ def initView
55
+ basicFrame = newFrame(FXVerticalFrame.new(self))
56
+ basicFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_Y)
57
+
58
+ # input user
59
+ userAndPasswordFrame = newFrame(FXMatrix.new(basicFrame, 2, MATRIX_BY_COLUMNS))
60
+ userAndPasswordFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
61
+ FXLabel.new(userAndPasswordFrame, "Working directory:")
62
+ wdFrame = newFrame(FXHorizontalFrame.new(userAndPasswordFrame))
63
+ wdFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
64
+ noPaddingForFrame(wdFrame)
65
+ @workingDirTextField = FXTextField.new(wdFrame,
66
+ 32, nil, 0,
67
+ TEXTFIELD_NORMAL)
68
+ @workingDirTextField.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
69
+ @workingDirTextField.setText(@workingDir)
70
+ wdChooseButton = newButton(wdFrame, '..')
71
+ wdChooseButton.connect(SEL_COMMAND, method(:onChooseWorkingDir))
72
+
73
+ FXLabel.new(userAndPasswordFrame, "Enter User:")
74
+ @userTextField = newCombobox(userAndPasswordFrame, 32,
75
+ 10.size,
76
+ nil, 0, COMBOBOX_INSERT_LAST)
77
+ @userTextField.setFrameStyle(FRAME_SUNKEN|FRAME_THICK)
78
+ @userTextField.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
79
+
80
+ # input password
81
+ FXLabel.new(userAndPasswordFrame, "Password:")
82
+ @passwordTextField = FXTextField.new(userAndPasswordFrame,
83
+ 32, nil, 0,
84
+ TEXTFIELD_NORMAL|TEXTFIELD_PASSWD)
85
+ @passwordTextField.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
86
+ @passwordTextField.setText(@password) if @password
87
+
88
+ # input style
89
+ FXLabel.new(userAndPasswordFrame, "Style:")
90
+ @styleTextField = newCombobox(userAndPasswordFrame, 32,
91
+ 10,
92
+ nil, 0, COMBOBOX_INSERT_LAST)
93
+ @styleTextField.setFrameStyle(FRAME_SUNKEN|FRAME_THICK)
94
+ @styleTextField.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
95
+
96
+ # set actions
97
+
98
+ optionsFrame = newFrame(FXMatrix.new(basicFrame, 2, MATRIX_BY_COLUMNS))
99
+ optionsFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
100
+
101
+ @checkFetch = newCheckBox(optionsFrame, 'Fetch links from del.icio.us')
102
+ fetchFrame = newFrame(FXVerticalFrame.new(optionsFrame))
103
+ noPaddingForFrame(fetchFrame)
104
+ fetchFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
105
+
106
+ @fetchMode = newCombobox(fetchFrame, 10,
107
+ Delicious2Yaml::MODES.size,
108
+ nil, 0, COMBOBOX_STATIC)
109
+ @fetchMode.setFrameStyle(FRAME_SUNKEN|FRAME_THICK)
110
+ modeKeys = Delicious2Yaml::MODES.keys.sort {|m1, m2| m1.to_s <=> m2.to_s}
111
+ modeKeys.each { |m| @fetchMode.appendItem(Delicious2Yaml::MODES[m]) }
112
+ @fetchMode.setText(Delicious2Yaml::MODES[modeKeys.first])
113
+ @fetchMode.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
114
+
115
+ @checkGenerate = newCheckBox(optionsFrame, 'Generate HTML')
116
+ generateFrame = newFrame(FXVerticalFrame.new(optionsFrame))
117
+ noPaddingForFrame(generateFrame)
118
+ generateFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
119
+
120
+ @checkDelicious = newCheckBox(generateFrame, 'Link to del.icio.us')
121
+ @checkBundles = newCheckBox(generateFrame, 'Include bundles')
122
+ @checkGraphViews = newCheckBox(generateFrame, 'Include graph views')
123
+ @checkGraphThumbs = newCheckBox(generateFrame, 'Graph thumbnails')
124
+ includePrivateFrame = newFrame(FXHorizontalFrame.new(generateFrame))
125
+ noPaddingForFrame(includePrivateFrame)
126
+ includePrivateFrame.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
127
+ @checkIncludePrivate = newCheckBox(includePrivateFrame, 'Include private?')
128
+ @checkReallyIncludePrivate = newCheckBox(includePrivateFrame, 'Really?')
129
+ @checkIncludePrivate.setCheck(false)
130
+ @checkReallyIncludePrivate.setCheck(false)
131
+
132
+ # buttons
133
+ buttonFrame = newFrame(FXHorizontalFrame.new(basicFrame))
134
+ buttonFrame.setPackingHints(PACK_UNIFORM_WIDTH)
135
+ okButton = newButton(buttonFrame, 'Ok')
136
+ okButton.connect(SEL_COMMAND, method(:onCmdOk))
137
+ cancelButton = newButton(buttonFrame, 'Cancel')
138
+ cancelButton.connect(SEL_COMMAND, method(:onCmdQuit))
139
+
140
+ @cmdOutput = FXText.new(basicFrame, nil, 0,
141
+ TEXT_READONLY|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
142
+ @cmdOutput.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_Y)
143
+ end
144
+
145
+ def setOptionFetch(bool)
146
+ @checkFetch.setCheck(bool ? true : false)
147
+ end
148
+
149
+ def setOptionGenerate(bool)
150
+ @checkGenerate.setCheck(bool ? true : false)
151
+ end
152
+
153
+ def setOptionDelicious(bool)
154
+ @checkDelicious.setCheck(bool ? true : false)
155
+ end
156
+
157
+ def setOptionBundles(bool)
158
+ @checkBundles.setCheck(bool ? true : false)
159
+ end
160
+
161
+ def setOptionGraphViews(bool)
162
+ @checkGraphViews.setCheck(bool ? true : false)
163
+ end
164
+
165
+ def setOptionGraphThumbs(bool)
166
+ @checkGraphThumbs.setCheck(bool ? true : false)
167
+ end
168
+
169
+ def create
170
+ resize(340, 400)
171
+ place(PLACEMENT_SCREEN)
172
+ super
173
+ show
174
+ end
175
+
176
+ def appendText(txt)
177
+ @cmdOutput.appendText(txt, true)
178
+ @cmdOutput.makePositionVisible(@cmdOutput.text.size)
179
+ @cmdOutput.repaint
180
+ end
181
+
182
+ def updateUserList
183
+ cachedUsers = YamlLinksToHtml.guess_users_within(@workingDir).collect {
184
+ |userDir|
185
+ File.basename(userDir)
186
+ }
187
+ @userTextField
188
+ cachedUsers.each { |m| @userTextField.appendItem(m) }
189
+ @userTextField.setText(@user ? @user : cachedUsers.first)
190
+ end
191
+
192
+ def updateStylesList
193
+ @styleTextField.clearItems
194
+ [@workingDir, @stylesFolder].each do
195
+ |folder|
196
+ YamlLinksToHtml.guess_styles_within(folder).each do
197
+ |styleDir|
198
+ @styleTextField.appendItem(styleDir)
199
+ end
200
+ end
201
+ @styleTextField.setText(@style ? @style : "")
202
+ end
203
+
204
+ def onChooseWorkingDir(sender, sel, ptr)
205
+ newFolder = FXDirDialog.getOpenDirectory(self, "Choose working directory", @workingDir)
206
+ return if newFolder.nil?
207
+ @workingDir = newFolder.gsub(/\\/, File::SEPARATOR)
208
+ @workingDirTextField.setText(@workingDir)
209
+ updateUserList
210
+ updateStylesList
211
+ end
212
+
213
+ def onCmdOk(sender, sel, ptr)
214
+ @user = @userTextField.getText
215
+ @password = @passwordTextField.getText
216
+ @style = @styleTextField.getText
217
+ @workingDir = @workingDirTextField.getText
218
+ mode = Delicious2Yaml::MODES.index(@fetchMode.getText)
219
+ outputBlock = proc { |line| appendText("#{line}\n") }
220
+ appendText("-Start-\n")
221
+ begin
222
+ getApp.beginWaitCursor
223
+ if @checkFetch.checked?
224
+ appendText("-Start import-\n")
225
+ importer = Delicious2Yaml.new(@user, @password)
226
+ importer.set_protocol_block(outputBlock)
227
+ importer.set_working_dir(@workingDir)
228
+ importer.set_mode(mode)
229
+ importer.run
230
+ setOptionFetch(false)
231
+ appendText("-Done import-\n")
232
+ end
233
+ if @checkGenerate.checked?
234
+ appendText("-Start generation-\n")
235
+ exporter = YamlLinksToHtml.new
236
+ exporter.set_protocol_block(outputBlock)
237
+ exporter.set_working_dir(@workingDir)
238
+ exporter.set_user(@user)
239
+ exporter.set_style(@style)
240
+ exporter.link_to_delicious_if_possible = @checkDelicious.checked?
241
+ exporter.use_bundles = @checkBundles.checked?
242
+ exporter.build_graph_thumbs = @checkGraphThumbs.checked?
243
+ exporter.include_graph_views = @checkGraphViews.checked?
244
+ exporter.include_private = @checkIncludePrivate.checked? && @checkReallyIncludePrivate.checked?
245
+ exporter.run
246
+ appendText("-Done generation-\n")
247
+ end
248
+ appendText("-Done-\n")
249
+ rescue StandardError => bang
250
+ appendText("Fatal error: " + bang + "\n-\n")
251
+ ensure
252
+ getApp.endWaitCursor
253
+ end
254
+
255
+ end
256
+
257
+ def onCmdQuit(sender, sel, ptr)
258
+ getApp.exit(0)
259
+ end
260
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby
2
+ #$Id: help.rb,v 1.3 2005/11/26 14:26:21 wsdng Exp $
3
+
4
+ module Graphiclious
5
+ def self.help
6
+ h = String.new
7
+ h <<
8
+ "Commandline options:\n" <<
9
+ "--bundles/-b include bundles\n" <<
10
+ "--delicious/-d prefer links to del.icio.us\n" <<
11
+ "--gui/-g will start a graphical user interface\n" <<
12
+ "--help/-h will display this text\n" <<
13
+ "--noupdate/-l do not connect to del.icio.us\n" <<
14
+ "--nohtml/-o ommit html generation\n" <<
15
+ "--password/-p specify password for given user\n" <<
16
+ "--user/-u specify a del.icio.us user\n" <<
17
+ "--version/-v prints actual version\n" <<
18
+ "Without gui option you'll need to specify user and\n" <<
19
+ "password."
20
+ h
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require_gem 'fxruby', '>= 1.2'
5
+
6
+ def newCombobox(p1, p2, p3, p4, p5, p6)
7
+ box = Fox::FXComboBox.new(p1, p2, p4, p5, p6)
8
+ box.setNumVisible(p3)
9
+ box
10
+ end
11
+
12
+
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+ #$Id: url_graph.rb,v 1.8 2006/03/09 22:57:52 wsdng Exp $
3
+
4
+ begin
5
+ require 'rubygems'
6
+ require_gem 'rgl'
7
+ rescue LoadError
8
+ end
9
+ require 'rgl/adjacency'
10
+ require 'rgl/dot'
11
+ require 'rgl/implicit'
12
+ require 'graphiclious/dot_attributes'
13
+
14
+ # UrlGraph models relations between tags
15
+
16
+ class UrlGraph < RGL::ImplicitGraph
17
+
18
+ attr_accessor(:fixed_dot_attributes, :filter_set)
19
+
20
+ def initialize
21
+ @fixed_dot_attributes = DotAttributes.new
22
+ @wrapped_graph = RGL::AdjacencyGraph.new
23
+ @filter = proc { |v| @filter_set.nil? || @filter_set.include?(v) }
24
+ @filter_set = nil
25
+ super { |g|
26
+ g.vertex_iterator { |b|
27
+ @wrapped_graph.each_vertex { |v| b.call(v) if @filter.call(v) }
28
+ }
29
+ g.adjacent_iterator { |v, b|
30
+ @wrapped_graph.each_adjacent(v) { |u| b.call(u) if @filter.call(u) }
31
+ }
32
+ }
33
+ end
34
+
35
+ def add_vertex(vertex)
36
+ @wrapped_graph.add_vertex(vertex)
37
+ end
38
+
39
+ def add_edge(tag, otherTag)
40
+ @wrapped_graph.add_edge(tag, otherTag)
41
+ end
42
+
43
+ # some characters are not allowed in filenames and need to be replaced
44
+ def self.tag2file(tag)
45
+ # Windows: \/:*?"<>|
46
+ # Linux: ()
47
+ # Call to Graphviz: Space
48
+ tag.gsub(/[\\\/:*?"<>|() ]/, '_')
49
+ end
50
+
51
+ def self.ankor(url, name)
52
+ "<a class=\"extern\" href=\"#{url}\" target=\"_top\">#{name}</a>"
53
+ end
54
+
55
+ def self.intern_ankor(url, name, style=nil)
56
+ link = "<a href=\"#{tag2file(url)}\">#{name}</a>"
57
+ link = "<span class=\"#{style}\">#{link}</span>" unless style.nil?
58
+ link
59
+ end
60
+
61
+ def self.node_url(tag)
62
+ "#{tag2file(tag)}.htm"
63
+ end
64
+
65
+ def self.node_ankor(tag, style=nil)
66
+ intern_ankor(node_url(tag), tag, style)
67
+ end
68
+
69
+ def self.edge_name(tag1, tag2)
70
+ if tag1 <= tag2
71
+ tag1 + '-' + tag2
72
+ else
73
+ tag2 + '-' + tag1
74
+ end
75
+ end
76
+
77
+ def self.edge_url(tag1, tag2)
78
+ node_url(edge_name(tag1, tag2))
79
+ end
80
+
81
+ def self.edge_ankor(tag1, tag2, style=nil)
82
+ intern_ankor(edge_url(tag1, tag2), edge_name(tag1, tag2), style)
83
+ end
84
+
85
+ def fixed_dot_node_attributes
86
+ fixed_dot_attributes.node_attributes
87
+ end
88
+
89
+ def fixed_dot_edge_attributes
90
+ fixed_dot_attributes.edge_attributes
91
+ end
92
+
93
+ def fixed_dot_graph_attributes
94
+ fixed_dot_attributes.graph_attributes
95
+ end
96
+
97
+ def d_quote(string)
98
+ "\"#{string}\""
99
+ end
100
+
101
+ def to_dot_graph(params = {})
102
+ fixed_dot_graph_attributes.each { |k, v|
103
+ params[k] ||= v
104
+ }
105
+ graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
106
+ edge_class = directed? ? DOT::DOTDirectedEdge : DOT::DOTEdge
107
+ dot_node_attributes = fixed_dot_node_attributes.clone
108
+ each_vertex do |v|
109
+ name = v.to_s
110
+ dot_node_attributes['name'] = d_quote(name)
111
+ dot_node_attributes['URL'] = d_quote(UrlGraph.node_url(name))
112
+ dot_node_attributes['label'] = name
113
+ graph << DOT::DOTNode.new(dot_node_attributes)
114
+ end
115
+ dot_edge_attributes = fixed_dot_edge_attributes.clone
116
+ each_edge do |u,v|
117
+ tag1 = u.to_s
118
+ tag2 = v.to_s
119
+ dot_edge_attributes['from'] = d_quote(tag1)
120
+ dot_edge_attributes['to'] = d_quote(tag2)
121
+ dot_edge_attributes['URL'] = d_quote(UrlGraph.edge_url(tag1, tag2))
122
+ graph << edge_class.new(dot_edge_attributes)
123
+ end
124
+ graph
125
+ end
126
+
127
+ # Output the DOT-graph to a file.
128
+
129
+ def print_dotted_on_file(filename = 'graph.dot', params = {})
130
+ File.open(filename, "w") {|f|
131
+ print_dotted_on(params, f)
132
+ }
133
+ end
134
+ end
135
+