twb 4.9.4 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bf5871fe93aaf4afc19f4c4b789d18db29545c43f77c6ae1d2c901dc23cd142
4
- data.tar.gz: e529613db65063341cde12d6393201765f3a53b680e4fbc7fe21707b9ff83681
3
+ metadata.gz: 786d3cb3bde8d6d6db0ee5c4063e998df008b5ca1354ba8fb4fc77c06aa7e10d
4
+ data.tar.gz: f9e73b1494d4d3946749f03e045caf6db221d4750ac12d99a5af037a77ca955a
5
5
  SHA512:
6
- metadata.gz: 7fb310fd663173d925df07488ec1f8d147651ca6588b725f03acaa99e88cfbcc07bb5aed2b797a8e70afd57143466a06ca0857bab0e4bdad99fda42423093652
7
- data.tar.gz: 460b6aee7fe9bf62baa9611a350dc3b7fe671ae18c03b8943431506a43bf0598247e92e784604cf35450bdc1f3dc09c04380ae43ff35c33344877885f16ca191
6
+ metadata.gz: 1ed3f0c9dfd61b8accd948ac10f29382f16c0fc8b15c415c8f5de55ab5a2739b6e7991e82c02ec953fd1507cb27079b59a5a15785da4a44b2fbe57f5e08eb083
7
+ data.tar.gz: 6171c5e6615b4d426690fca14bc92fea5e7325ee143985bd2fd4fd178833c41085a9e0b9f75a219884fdc900ab4d04a56ccd12d69580636e85b30855dd5f7792
@@ -0,0 +1,311 @@
1
+
2
+ # Copyright (C) 2014, 2020 Chris Gerrard
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'nokogiri'
18
+ require 'zip'
19
+
20
+ module Flow
21
+
22
+
23
+ ##
24
+ # A Tableau Prep Flow file.
25
+ #
26
+ class Flow < TabClass
27
+
28
+ attr_reader :name, :dir, :type, :modtime
29
+ attr_reader :version, :build, :platform, :base
30
+ attr_reader :root
31
+ #--
32
+ attr_reader :datasources, :datasource
33
+ attr_reader :datasourceNames, :datasourceUINames, :dataSourceNamesMap
34
+ # attr_reader :orphanDataSources # i.e. not referenced in any Worksheet
35
+ #--
36
+ # attr_reader :dashboards, :storyboards, :worksheets
37
+ # attr_reader :parameters, :actions
38
+ # attr_reader :valid
39
+
40
+ ##
41
+ # Creates a Flow from its file name.
42
+ #
43
+ # == Parameters:
44
+ # flowWithDir
45
+ # The Flow's file name, the Flow can be a TWB or TWBX file.
46
+ #
47
+ def initialize tflWithDir
48
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must be a String, is a #{tflWithDir.class} \n ") unless tflWithDir.is_a? String
49
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must have an extension of .tfl or .tflx \n ") unless tflWithDir.upcase.end_with?(".TFL", ".TFLX")
50
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must must be a file, is a Directory\\Folder \n ") if File.directory?(tflWithDir)
51
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' cannot be found, must be a Tableau Flow file. \n ") unless File.file?(tflWithDir)
52
+ @valid = false
53
+ if File.file?(tflWithDir) then
54
+ @name = File.basename(tflWithDir)
55
+ @dir = File.dirname(File.expand_path(tflWithDir))
56
+ @modtime = File.new(tflWithDir).mtime.strftime("%Y-%m-%d %H:%M:%S")
57
+ case File.extname(tflWithDir).downcase
58
+ when '.tlf' then processTFL(tflWithDir)
59
+ when '.tflx' then processTFLX(flowWithDir)
60
+ end
61
+ end
62
+ end
63
+
64
+ def id
65
+ @id ||= @id = @name.hash
66
+ end
67
+
68
+ def build
69
+ @build ||= loadBuild
70
+ end
71
+
72
+ def release
73
+ @build ||= loadBuild
74
+ end
75
+
76
+ def worksheets
77
+ @worksheets.values
78
+ end
79
+
80
+ def worksheet name
81
+ @worksheets[name]
82
+ end
83
+
84
+ def worksheetNames
85
+ @worksheets.keys
86
+ end
87
+
88
+ def dashboards
89
+ @dashboards.values
90
+ end
91
+
92
+ def dashboardNames
93
+ @dashboards.keys
94
+ end
95
+
96
+ def dashboard name
97
+ @dashboards[name]
98
+ end
99
+
100
+ def actions
101
+ @actions.values
102
+ end
103
+
104
+ def actionNames
105
+ @actions.keys
106
+ end
107
+
108
+ def datasource name
109
+ @dataSourceNamesMap[name]
110
+ end
111
+
112
+ def parameters
113
+ @parameters ||= loadParameters
114
+ end
115
+
116
+ def orphanDataSources
117
+ @orphanDataSources ||= identifyOrphandatasoUrceS
118
+ end
119
+
120
+ def storyboards
121
+ @storyboards.values
122
+ end
123
+
124
+ def storyboardNames
125
+ @storyboards.keys
126
+ end
127
+
128
+ def storyboard name
129
+ @storyboards[name]
130
+ end
131
+
132
+ private
133
+
134
+ def processTFLX(twbxWithDir)
135
+ Zip::File.open(twbxWithDir) do |zip_file|
136
+ twb = zip_file.glob('*.twb').first
137
+ @ndoc = Nokogiri::XML(twb.get_input_stream)
138
+ @type = :twbx
139
+ processDoc
140
+ end
141
+ end
142
+
143
+ def processTFL(twbFile)
144
+ @ndoc = Nokogiri::XML(open(twbFile))
145
+ @type = :twb
146
+ processDoc
147
+ end
148
+
149
+ def processDoc
150
+ @valid = true
151
+ end
152
+
153
+ def loadBuild
154
+ # - earlier Version, need to confirm when source-build began
155
+ # @build = @ndoc.xpath('/flow/comment()').text.gsub(/^[^0-9]+/,'').strip
156
+ @build = if !@ndoc.at_xpath('/flow/@source-build').nil?
157
+ @ndoc.at_xpath('/flow/@source-build').text
158
+ else
159
+ if @ndoc.at_xpath('/flow/comment()').nil?
160
+ 'not found'
161
+ else
162
+ @ndoc.at_xpath('/flow/comment()').text.gsub(/^[^0-9]+/,'').strip
163
+ end
164
+ end
165
+ end
166
+
167
+ def loaddatasources
168
+ # puts "LOAD DATA SOURCES"
169
+ # @dataSourcesNode = @ndoc.at_xpath('//flow/datasources')
170
+ @datasources = Set.new
171
+ @datasourceNames = SortedSet.new
172
+ @datasourceUINames = SortedSet.new
173
+ @dataSourceNamesMap = {}
174
+ datasourceNodes = @ndoc.xpath('//flow/datasources/datasource')
175
+ # puts "DATASOURCENODES : #{@datasourceNodes.length}"
176
+ datasourceNodes.each do |node|
177
+ datasource = Twb::DataSource.new(node,self)
178
+ @datasources << datasource
179
+ @datasourceNames << datasource.name
180
+ @datasourceNames << datasource.uiname
181
+ @datasourceUINames << datasource.uiname
182
+ @dataSourceNamesMap[datasource.name] = datasource
183
+ @dataSourceNamesMap[datasource.uiname] = datasource
184
+ end
185
+ # puts "DATASOURCES : #{@datasources.length}"
186
+ end
187
+
188
+ def loadWorksheets
189
+ @worksheets = {}
190
+ hiddenSheets = []
191
+ @ndoc.xpath('//flow/windows/window[@hidden="true"]').each do |hs|
192
+ hiddenSheets << hs['name']
193
+ end
194
+ sheets = @ndoc.xpath('//flow/worksheets/worksheet' ).to_a
195
+ sheets.each do |node|
196
+ sheet = Twb::Worksheet.new(node, self)
197
+ sheet.hidden = hiddenSheets.include? sheet.name
198
+ @worksheets[sheet.name] = sheet
199
+ end
200
+ end
201
+
202
+ def loadDashboards
203
+ @dashesNode = @ndoc.at_xpath('//flow/dashboards')
204
+ @dashboards = {}
205
+ dashes = @ndoc.xpath('//flow/dashboards/dashboard').to_a
206
+ dashes.each do |node|
207
+ unless node.attr('type') == 'storyboard' then
208
+ dashboard = Twb::Dashboard.new(node, @worksheets)
209
+ @dashboards[dashboard.name] = dashboard
210
+ end
211
+ end
212
+ end
213
+
214
+ def loadStoryboards
215
+ @storyboards = {}
216
+ boards = @ndoc.xpath("//flow/dashboards/dashboard[@type='storyboard']" ).to_a
217
+ boards.each do |node|
218
+ sheet = Twb::Storyboard.new(node)
219
+ @storyboards[sheet.name] = sheet
220
+ end
221
+ end
222
+
223
+ def loadWindows
224
+ @windowsnode = @ndoc.at_xpath("//flow/windows")
225
+ @windows = {}
226
+ windows = @ndoc.xpath("//flow/windows/window[@name]")
227
+ windows.each do |node|
228
+ window = Twb::Window.new(node)
229
+ @windows[window.name] = window
230
+ end
231
+ end
232
+
233
+ def loadActions
234
+ @actions = {}
235
+ actionNodes = @ndoc.xpath("//flow/actions/action")
236
+ actionNodes.each do |anode|
237
+ action = Twb::Action.new(anode, @flownode)
238
+ @actions[action.uiname] = action
239
+ end
240
+ end
241
+
242
+ def identifyOrphandatasoUrceS
243
+ sheetDataSources = Set.new
244
+ @worksheets.values.each do |sheet|
245
+ sheet.datasources.each do |ds|
246
+ sheetDataSources << ds.uiname
247
+ end
248
+ end
249
+ @orphanDataSources = @datasourceUINames - sheetDataSources
250
+ end
251
+
252
+ def writeTwb(name=@name)
253
+ $f = File.open(name,'w')
254
+ if $f
255
+ $f.puts @ndoc
256
+ $f.close
257
+ end
258
+ return name
259
+ end
260
+
261
+ def writeTwbx(name=@name)
262
+ emit "Writing the Workbook, need implementation"
263
+ end
264
+
265
+ # Make sure that the TWB has a <dashboards> node.
266
+ # It's possible for a TWB to have no dashboards, and therefore no <dashboards> node.
267
+ def ensureDashboardsNodeExists
268
+ if @dashesNode.nil?
269
+ @dashesNode = Nokogiri::XML::Node.new "dashboards", @ndoc
270
+ # TODO fix this @dataSourcesNode.add_next_sibling(@dashesNode)
271
+ end
272
+ end
273
+
274
+ def ensureWindowsNodeExists
275
+ if @windowsnode.nil?
276
+ @windowsnode = Nokogiri::XML::Node.new "windows", @ndoc
277
+ # TODO fix this @dataSourcesNode.add_next_sibling(@windowsnode)
278
+ end
279
+ end
280
+
281
+ def getNewDashboardTitle(t)
282
+ title = t
283
+ if @datasources.include?(title)
284
+ inc = 0
285
+ loop do
286
+ inc+=1
287
+ title = t + ' ' + inc.to_s
288
+ if !@datasources.include?(title)
289
+ break
290
+ end
291
+ end
292
+ end
293
+ return title
294
+ end
295
+
296
+ def loadParameters
297
+ @parameters = {}
298
+ paramsDS = ndoc.at_xpath('./flow/datasources/datasource[@name="Parameters"]')
299
+ unless paramsDS.nil?
300
+ paramNodes = paramsDS.xpath('.//column')
301
+ paramNodes.each do |pn|
302
+ parameter = Twb::Parameter.new pn
303
+ @parameters[parameter.name] = parameter
304
+ end
305
+ end
306
+ return @parameters
307
+ end
308
+
309
+ end # class Flow
310
+
311
+ end # module Twb
data/lib/twb.rb CHANGED
@@ -54,6 +54,7 @@ require_relative 'twb/analysis/documentedfieldsmarkdownemitter'
54
54
  require_relative 'twb/analysis/annotatedfieldscsvemitter'
55
55
  require_relative 'twb/analysis/workbooksummaryanalyzer'
56
56
  require_relative 'twb/analysis/calculatedfields/calculatedfieldsanalyzer'
57
+ require_relative 'twb/analysis/calculatedfields/dotanalyzer'
57
58
  require_relative 'twb/analysis/calculatedfields/groupfieldsanalyzer'
58
59
  require_relative 'twb/analysis/calculatedfields/markdownemitter'
59
60
  require_relative 'twb/analysis/calculatedfields/csvemitter'
@@ -73,12 +74,12 @@ require_relative 'twb/analysis/sheets/worksheetsummarizer'
73
74
  require_relative 'twb/analysis/sheets/worksheetdatastructurecsvemitter'
74
75
  require_relative 'twb/analysis/sheets/sheetfiltersanalyzer'
75
76
  require_relative 'twb/analysis/sheets/sheetfieldsanalyzer'
77
+ require_relative 'twb/analysis/sheets/dashboardsummarizer'
76
78
  require_relative 'twb/analysis/sheets/dashsheetsanalyzer'
77
79
  require_relative 'twb/analysis/sheets/sheetsintooltipanalyzer'
78
80
 
79
-
80
81
  # Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
81
82
  #
82
83
  module Twb
83
- VERSION = '4.9.4'
84
+ VERSION = '5.2.1'
84
85
  end
@@ -78,12 +78,12 @@ module Analysis
78
78
  @fieldTables = {}
79
79
 
80
80
 
81
- @@dotHeader = <<DOTHEADER
82
- digraph g {
83
- graph [rankdir="LR" splines=line];
84
- node [shape="box" width="2"];
81
+ # @@dotHeader = <<DOTHEADER
82
+ # digraph g {
83
+ # graph [rankdir="LR" splines=line];
84
+ # node [shape="box" width="2"];
85
85
 
86
- DOTHEADER
86
+ # DOTHEADER
87
87
 
88
88
  def initialize(**args)
89
89
  emit "initialize CalculatedFieldsAnalyzer args #{args}"
@@ -141,7 +141,7 @@ DOTHEADER
141
141
  # end
142
142
  processDataSource ds
143
143
  end
144
- mapTwb
144
+ # mapTwb
145
145
  emitGml
146
146
  @twbCount += 1
147
147
  finis
@@ -195,10 +195,10 @@ DOTHEADER
195
195
  calculatedFields.add calcField.id
196
196
  dsFields[calcField.uiname] = calcField
197
197
  # if @doGraph
198
- calcFieldNode = Twb::Util::Graphnode.new(name: calcField.uiname, id: calcField.id, type: calcField, properties: {:DataSource => ds.uiname})
199
- @nodes.add calcFieldNode
200
- dsFieldEdge = Twb::Util::Graphedge.new(from: dataSourceNode, to: calcFieldNode, relationship: 'contains')
201
- @edges.add dsFieldEdge
198
+ calcFieldNode = Twb::Util::Graphnode.new(name: calcField.uiname, id: calcField.id, type: calcField, properties: {:DataSource => ds.uiname})
199
+ @nodes.add calcFieldNode
200
+ dsFieldEdge = Twb::Util::Graphedge.new(from: dataSourceNode, to: calcFieldNode, relationship: 'contains')
201
+ @edges.add dsFieldEdge
202
202
  # end
203
203
  calculation = calcField.calculation
204
204
  if calculation.has_formula
@@ -249,47 +249,26 @@ DOTHEADER
249
249
  ]
250
250
  end
251
251
  #-- collect fields referenced in formula
252
- emit "# Calculated Fields: #{calculation.calcFields.length}"
253
- calculation.calcFields.each do |rf|
254
- emit " referenced field ::'#{rf}'"
255
- emit " referenced field.name ::'#{rf.name.nil?}' :: '#{rf.name}'"
256
- emit " referenced field.uiname::'#{rf.uiname}'"
257
- # if @doGraph
258
- unless rf.uiname.nil?
259
- properties = {'DataSource' => ds.uiname, 'DataSourceReference' => 'local', :source => rf}
260
- refFieldNode = Twb::Util::Graphnode.new(name: rf.uiname, id: rf.id, type: rf.type, properties: properties)
261
- @nodes.add refFieldNode
262
- fieldFieldEdge = Twb::Util::Graphedge.new(from: calcFieldNode, to: refFieldNode, relationship: 'references')
263
- @edges.add fieldFieldEdge
264
- end
265
- # end
266
- referencedFields.add rf.id
267
- refFieldTable = ds.fieldTable(rf.name)
268
- emit "refFieldTable.nil? : #{refFieldTable.nil?}"
269
- unless refFieldTable.nil?
270
- tableID = refFieldTable + ':::' + ds.uiname
271
- tableName = "||#{refFieldTable}||"
272
- # if @doGraph
273
- tableNode = Twb::Util::Graphnode.new(name: tableName, id: tableID, type: :DBTable, properties: properties)
274
- @nodes.add tableNode
275
- fieldFieldEdge = Twb::Util::Graphedge.new(from: refFieldNode, to: tableNode, relationship: 'is a field in')
276
- @edges.add fieldFieldEdge
277
- # end
278
- # fldToDsNode = tableNode
279
- end
252
+ emit "# Calculated Fields: #{calculation.referencedFields.length}"
253
+ calculation.referencedFields.each do |rf|
254
+ emit " referenced field :: %12s %s " % [ rf.dataSourceName, rf.uiname ]
280
255
  @csvFormulaFields << [
281
256
  @referencedFieldsCount += 1,
282
257
  @twb.name,
283
258
  # @modTime,
284
- ds.uiname,
259
+ rf.dataSourceName, # ds.uiname,
285
260
  calcField.uiname,
286
261
  calculation.formulaFlat,
287
262
  calculation.formulaFlatResolved,
288
263
  rf.name,
289
- rf.uiname,
290
- rf.id,
291
- refFieldTable
264
+ rf.uiname, #.uiname,
265
+ '', # rf.id,
266
+ '', #refFieldTable
292
267
  ]
268
+ refFieldNode = Twb::Util::Graphnode.new(name: rf.uiname, id: rf.id, type: rf, properties: {:DataSource => ds.uiname})
269
+ @nodes.add refFieldNode
270
+ refFieldEdge = Twb::Util::Graphedge.new(from: calcFieldNode, to: refFieldNode , relationship: 'references')
271
+ @edges.add refFieldEdge
293
272
  end # resolvedFields.each do
294
273
  end # if calculation.has_formula
295
274
  end # ds.calculatedFields.each
@@ -298,8 +277,8 @@ DOTHEADER
298
277
  @referencedFields.merge referencedFields
299
278
  @twbRootFields.merge dsRootFields
300
279
  if @doGraph
301
- cypher @twb.name
302
- cypherPy @twb.name
280
+ # cypher @twb.name
281
+ # cypherPy @twb.name
303
282
  end
304
283
  emit "#######################"
305
284
  #--
@@ -330,49 +309,49 @@ DOTHEADER
330
309
  emit "\t formula:: #{calculation.formulaFlat}"
331
310
  end
332
311
 
333
- def mapTwb
334
- twb = @twb.name
335
- rootFields = @twbRootFields
336
- dotStuff = initDot twb
337
- dotFile = dotStuff[:file]
338
- dotFileName = dotStuff[:name]
339
- dotFile.puts "\n // subgraph cluster_1 {"
340
- dotFile.puts " // color= grey;"
341
- dotFile.puts ""
342
- edgesAsStrings = SortedSet.new
343
- # this two step process coalesces the edges into a unique set, avoiding duplicating the dot
344
- # file entries, and can be shrunk when graph edges expose the bits necessary for management by Set
345
- emit "\n========================\nLoading Edges\n========================\n From DC? Referenced? Edge \n %s %s %s" % ['--------', '-----------', '-'*45]
346
- @edges.each do |e|
347
- # don't want to emit edge which is from a Data Connection to a
348
- # Calculated Field which is also referenced by another calculated field
349
- isFromDC = e.from.type == :TwbDataConnection
350
- isRefField = @referencedFields.include?(e.to.id)
351
- edgesAsStrings.add(e.dot) unless isFromDC && isRefField
352
- # emit " ES #{e.dot}"
353
- # emit " ES from #{e.from}"
354
- # emit " ES to #{e.to}"
355
- end
356
- emit "------------------------\n "
357
- edgesAsStrings.each do |es|
358
- dotFile.puts " #{es}"
359
- end
360
- emit "========================\n "
361
- dotFile.puts ""
362
- dotFile.puts " // }"
363
- dotFile.puts "\n\n // 4 NODES --------------------------------------------------------------------"
364
- @nodes.each do |n|
365
- dotFile.puts n.dotLabel
366
- end
367
- dotFile.puts "\n\n // 5--------------------------------------------------------------------"
368
- emitTypes( dotFile )
369
- closeDot( dotFile, twb )
370
- emit "Rendering DOT file - #{twb}"
371
- renderDot(twb,dotFileName,'pdf')
372
- renderDot(twb,dotFileName,'png')
373
- renderDot(twb,dotFileName,'svg')
374
- # emitEdges
375
- end
312
+ # def mapTwb
313
+ # twb = @twb.name
314
+ # rootFields = @twbRootFields
315
+ # dotStuff = initDot twb
316
+ # dotFile = dotStuff[:file]
317
+ # dotFileName = dotStuff[:name]
318
+ # dotFile.puts "\n // subgraph cluster_1 {"
319
+ # dotFile.puts " // color= grey;"
320
+ # dotFile.puts ""
321
+ # edgesAsStrings = SortedSet.new
322
+ # # this two step process coalesces the edges into a unique set, avoiding duplicating the dot
323
+ # # file entries, and can be shrunk when graph edges expose the bits necessary for management by Set
324
+ # emit "\n========================\nLoading Edges\n========================\n From DC? Referenced? Edge \n %s %s %s" % ['--------', '-----------', '-'*45]
325
+ # @edges.each do |e|
326
+ # # don't want to emit edge which is from a Data Connection to a
327
+ # # Calculated Field which is also referenced by another calculated field
328
+ # isFromDC = e.from.type == :TwbDataConnection
329
+ # isRefField = @referencedFields.include?(e.to.id)
330
+ # edgesAsStrings.add(e.dot) unless isFromDC && isRefField
331
+ # # emit " ES #{e.dot}"
332
+ # # emit " ES from #{e.from}"
333
+ # # emit " ES to #{e.to}"
334
+ # end
335
+ # emit "------------------------\n "
336
+ # edgesAsStrings.each do |es|
337
+ # dotFile.puts " #{es}"
338
+ # end
339
+ # emit "========================\n "
340
+ # dotFile.puts ""
341
+ # dotFile.puts " // }"
342
+ # dotFile.puts "\n\n // 4 NODES --------------------------------------------------------------------"
343
+ # @nodes.each do |n|
344
+ # dotFile.puts n.dotLabel
345
+ # end
346
+ # dotFile.puts "\n\n // 5--------------------------------------------------------------------"
347
+ # emitTypes( dotFile )
348
+ # closeDot( dotFile, twb )
349
+ # emit "Rendering DOT file - #{twb}"
350
+ # renderDot(twb,dotFileName,'pdf')
351
+ # renderDot(twb,dotFileName,'png')
352
+ # renderDot(twb,dotFileName,'svg')
353
+ # # emitEdges
354
+ # end
376
355
 
377
356
  def cypher twbName
378
357
  if @doGraph
@@ -488,44 +467,44 @@ DOTHEADER
488
467
  dotFile.puts ' }'
489
468
  end
490
469
 
491
- def initDot twb
492
- dotFileName = docFile("#{twb}#{@@processName}.dot")
493
- dotFile = File.open(dotFileName,'w')
494
- dotFile.puts @@dotHeader
495
- return {:file => dotFile, :name => dotFileName}
496
- end
470
+ # def initDot twb
471
+ # dotFileName = docFile("#{twb}#{@@processName}.dot")
472
+ # dotFile = File.open(dotFileName,'w')
473
+ # dotFile.puts @@dotHeader
474
+ # return {:file => dotFile, :name => dotFileName}
475
+ # end
497
476
 
498
- def closeDot dotFile, twb
499
- dotFile.puts ' '
500
- dotFile.puts '// -------------------------------------------------------------'
501
- dotFile.puts ' '
502
- dotFile.puts ' subgraph cluster_1 {'
503
- # dotFile.puts ' color=white;'
504
- dotFile.puts ' style=invis;'
505
- # dotFile.puts ' border=0;'
506
- dotFile.puts ' node [border=blue];'
507
- dotFile.puts ' '
508
- dotFile.puts ' "" [style=invis]'
509
- dotFile.puts " \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{twb}'\\n#{Time.new.ctime}\" [penwidth=0]"
510
- # dotFile.puts " \"Tableau Tools Workbook Calculated Fields Map\\n#{Time.new.ctime}\" -> \"\" [style=invis]"
511
- dotFile.puts ' '
512
- dotFile.puts ' }'
513
- dotFile.puts ' '
514
- dotFile.puts '}'
515
- dotFile.close
516
- end
477
+ # def closeDot dotFile, twb
478
+ # dotFile.puts ' '
479
+ # dotFile.puts '// -------------------------------------------------------------'
480
+ # dotFile.puts ' '
481
+ # dotFile.puts ' subgraph cluster_1 {'
482
+ # # dotFile.puts ' color=white;'
483
+ # dotFile.puts ' style=invis;'
484
+ # # dotFile.puts ' border=0;'
485
+ # dotFile.puts ' node [border=blue];'
486
+ # dotFile.puts ' '
487
+ # dotFile.puts ' "" [style=invis]'
488
+ # dotFile.puts " \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{twb}'\\n#{Time.new.ctime}\" [penwidth=0]"
489
+ # # dotFile.puts " \"Tableau Tools Workbook Calculated Fields Map\\n#{Time.new.ctime}\" -> \"\" [style=invis]"
490
+ # dotFile.puts ' '
491
+ # dotFile.puts ' }'
492
+ # dotFile.puts ' '
493
+ # dotFile.puts '}'
494
+ # dotFile.close
495
+ # end
517
496
 
518
497
 
519
- def renderDot twb, dot, format
520
- imageType = '-T' + format
521
- imageFile = './ttdoc/' + twb + @@processName + 'Graph.' + format
522
- imageParam = '-o"' + imageFile + '"'
523
- emit "system #{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
524
- system "#{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
525
- emit " - #{imageFile}"
526
- @imageFiles << imageFile
527
- return imageFile
528
- end
498
+ # def renderDot twb, dot, format
499
+ # imageType = '-T' + format
500
+ # imageFile = './ttdoc/' + twb + @@processName + 'Graph.' + format
501
+ # imageParam = '-o"' + imageFile + '"'
502
+ # emit "system #{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
503
+ # system "#{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
504
+ # emit " - #{imageFile}"
505
+ # @imageFiles << imageFile
506
+ # return imageFile
507
+ # end
529
508
 
530
509
  end # class
531
510