twb 5.1.4 → 5.2.0

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: f839625abecd6c9b4ad520856fd216678790a2dace5307e62458db4e07b970cd
4
- data.tar.gz: f95701f60e3f4f99525113e723392b1d039b361db9ac63eb2689c58ef4a3a490
3
+ metadata.gz: 7e028806f0ddf3f1a48cda4ae9476f63f9302107cab1116673f1934f96143919
4
+ data.tar.gz: ec93e736c7833c5801cdc5fa7bd9344addd0de495d26d7e7d9af81633abbef52
5
5
  SHA512:
6
- metadata.gz: d59954bb21cc6b232402d0792219df4e0e48ddcf8a664088b58409c7e28b30175f3f3304910459304f2d87639bf1ce5a6f7d9b533b43ed0088bfbb1c4f131c8f
7
- data.tar.gz: c8fa036df0e3e8808f507404f5930a8db20ca19fb7a04251eda1deee7dc1ea09f1e06a811f79539275d2eed9cb473f009239dca5ae1c56c7179f4826ed0201c0
6
+ metadata.gz: 620200b5922bff2813fc62503fcce0faa43a9f3daade99e87e003fe05a856aae102a7a8fef67fe7ddb4e847cdb8a0594fc66eea6377cf46955fd0708995cf8eb
7
+ data.tar.gz: a7db358530ed931716db2221206eae088ce2b82a61a638dca303863c738d88f7283e2b791dba8feefe321cf7478f1f0d44b233b3fdc21958778defdc365ad21d
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'
@@ -80,5 +81,5 @@ require_relative 'twb/analysis/sheets/sheetsintooltipanalyzer'
80
81
  # Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
81
82
  #
82
83
  module Twb
83
- VERSION = '5.1.4'
84
+ VERSION = '5.2.0'
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
@@ -265,46 +265,10 @@ DOTHEADER
265
265
  '', # rf.id,
266
266
  '', #refFieldTable
267
267
  ]
268
-
269
-
270
- # emit " referenced field.name ::'#{rf.name.nil?}' :: '#{rf.name}'"
271
- # emit " referenced field.uiname::'#{rf.uiname}'"
272
- # if @doGraph
273
- # unless rf.uiname.nil?
274
- # properties = {'DataSource' => ds.uiname, 'DataSourceReference' => 'local', :source => rf}
275
- # refFieldNode = Twb::Util::Graphnode.new(name: rf.uiname, id: rf.id, type: rf.type, properties: properties)
276
- # @nodes.add refFieldNode
277
- # fieldFieldEdge = Twb::Util::Graphedge.new(from: calcFieldNode, to: refFieldNode, relationship: 'references')
278
- # @edges.add fieldFieldEdge
279
- # end
280
- # # end
281
- # referencedFields.add rf.id
282
- # refFieldTable = ds.fieldTable(rf.name)
283
- # emit "refFieldTable.nil? : #{refFieldTable.nil?}"
284
- # unless refFieldTable.nil?
285
- # tableID = refFieldTable + ':::' + ds.uiname
286
- # tableName = "||#{refFieldTable}||"
287
- # # if @doGraph
288
- # tableNode = Twb::Util::Graphnode.new(name: tableName, id: tableID, type: :DBTable, properties: properties)
289
- # @nodes.add tableNode
290
- # fieldFieldEdge = Twb::Util::Graphedge.new(from: refFieldNode, to: tableNode, relationship: 'is a field in')
291
- # @edges.add fieldFieldEdge
292
- # # end
293
- # # fldToDsNode = tableNode
294
- # end
295
- # @csvFormulaFields << [
296
- # @referencedFieldsCount += 1,
297
- # @twb.name,
298
- # # @modTime,
299
- # ds.uiname,
300
- # calcField.uiname,
301
- # calculation.formulaFlat,
302
- # calculation.formulaFlatResolved,
303
- # rf.name,
304
- # rf.uiname,
305
- # rf.id,
306
- # refFieldTable
307
- # ]
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
308
272
  end # resolvedFields.each do
309
273
  end # if calculation.has_formula
310
274
  end # ds.calculatedFields.each
@@ -345,49 +309,49 @@ DOTHEADER
345
309
  emit "\t formula:: #{calculation.formulaFlat}"
346
310
  end
347
311
 
348
- def mapTwb
349
- twb = @twb.name
350
- rootFields = @twbRootFields
351
- dotStuff = initDot twb
352
- dotFile = dotStuff[:file]
353
- dotFileName = dotStuff[:name]
354
- dotFile.puts "\n // subgraph cluster_1 {"
355
- dotFile.puts " // color= grey;"
356
- dotFile.puts ""
357
- edgesAsStrings = SortedSet.new
358
- # this two step process coalesces the edges into a unique set, avoiding duplicating the dot
359
- # file entries, and can be shrunk when graph edges expose the bits necessary for management by Set
360
- emit "\n========================\nLoading Edges\n========================\n From DC? Referenced? Edge \n %s %s %s" % ['--------', '-----------', '-'*45]
361
- @edges.each do |e|
362
- # don't want to emit edge which is from a Data Connection to a
363
- # Calculated Field which is also referenced by another calculated field
364
- isFromDC = e.from.type == :TwbDataConnection
365
- isRefField = @referencedFields.include?(e.to.id)
366
- edgesAsStrings.add(e.dot) unless isFromDC && isRefField
367
- # emit " ES #{e.dot}"
368
- # emit " ES from #{e.from}"
369
- # emit " ES to #{e.to}"
370
- end
371
- emit "------------------------\n "
372
- edgesAsStrings.each do |es|
373
- dotFile.puts " #{es}"
374
- end
375
- emit "========================\n "
376
- dotFile.puts ""
377
- dotFile.puts " // }"
378
- dotFile.puts "\n\n // 4 NODES --------------------------------------------------------------------"
379
- @nodes.each do |n|
380
- dotFile.puts n.dotLabel
381
- end
382
- dotFile.puts "\n\n // 5--------------------------------------------------------------------"
383
- emitTypes( dotFile )
384
- closeDot( dotFile, twb )
385
- emit "Rendering DOT file - #{twb}"
386
- renderDot(twb,dotFileName,'pdf')
387
- renderDot(twb,dotFileName,'png')
388
- renderDot(twb,dotFileName,'svg')
389
- # emitEdges
390
- 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
391
355
 
392
356
  def cypher twbName
393
357
  if @doGraph
@@ -503,44 +467,44 @@ DOTHEADER
503
467
  dotFile.puts ' }'
504
468
  end
505
469
 
506
- def initDot twb
507
- dotFileName = docFile("#{twb}#{@@processName}.dot")
508
- dotFile = File.open(dotFileName,'w')
509
- dotFile.puts @@dotHeader
510
- return {:file => dotFile, :name => dotFileName}
511
- 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
512
476
 
513
- def closeDot dotFile, twb
514
- dotFile.puts ' '
515
- dotFile.puts '// -------------------------------------------------------------'
516
- dotFile.puts ' '
517
- dotFile.puts ' subgraph cluster_1 {'
518
- # dotFile.puts ' color=white;'
519
- dotFile.puts ' style=invis;'
520
- # dotFile.puts ' border=0;'
521
- dotFile.puts ' node [border=blue];'
522
- dotFile.puts ' '
523
- dotFile.puts ' "" [style=invis]'
524
- dotFile.puts " \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{twb}'\\n#{Time.new.ctime}\" [penwidth=0]"
525
- # dotFile.puts " \"Tableau Tools Workbook Calculated Fields Map\\n#{Time.new.ctime}\" -> \"\" [style=invis]"
526
- dotFile.puts ' '
527
- dotFile.puts ' }'
528
- dotFile.puts ' '
529
- dotFile.puts '}'
530
- dotFile.close
531
- 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
532
496
 
533
497
 
534
- def renderDot twb, dot, format
535
- imageType = '-T' + format
536
- imageFile = './ttdoc/' + twb + @@processName + 'Graph.' + format
537
- imageParam = '-o"' + imageFile + '"'
538
- emit "system #{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
539
- system "#{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
540
- emit " - #{imageFile}"
541
- @imageFiles << imageFile
542
- return imageFile
543
- 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
544
508
 
545
509
  end # class
546
510
 
@@ -0,0 +1,139 @@
1
+ # dotanalyzer.rb - this Ruby script Copyright 2017, 2018 Christopher Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+
17
+ module Twb
18
+ module Analysis
19
+ module CalculatedFields
20
+
21
+ class DotAnalyzer
22
+ include TabTool
23
+
24
+ attr_reader :docFileName
25
+
26
+ @@gvDotLocation = 'C:\\tech\\graphviz\\Graphviz2.38\\bin\\dot.exe'
27
+ @@imageTypes = ['pdf', 'png', 'svg']
28
+
29
+ def initialize(**args)
30
+ @args = args
31
+ init
32
+ @funcdoc = {:class=>self.class, :blurb=>'Create Dot files documenting Calculated Fields', :description=>'Analyze Calculated Fields - create Dot files' }
33
+ @metrics = {}
34
+ @imageFiles = Array.new
35
+ end
36
+
37
+ def processTWB twb
38
+ # twb = File.basename(twb)
39
+ @twb = twb #Twb::Workbook.new twb
40
+ addDocFile @dotFile, @dotFileName, "Dot file of Calculated fields for Workbook '#{@twb.name}'"
41
+ @twb.datasources.each do |ds|
42
+ unless ds.calculatedFields.empty?
43
+ initDotFile ds.uiname
44
+ # @dotFile.puts "\n ## #{ds.uiname} \n "
45
+ # @dotFile.puts "__has #{ds.calculatedFields.length} calculated fields__\n "
46
+ @cfCnt = 0
47
+ calcFields = Set.new
48
+ refFields = Set.new
49
+ edges = Set.new
50
+ ds.calculatedFields.each do |cf|
51
+ @cfCnt += 1
52
+ calcFields << cf.uiname
53
+ edges << " \"#{ds.uiname}\" -> \"#{cf.uiname}\" [tailport=e, headport=w] "
54
+ cf.referencedFields.each do |rf|
55
+ refFields << rf.uiname
56
+ edges << " \"#{cf.uiname}\" -> \"#{rf.uiname}\" [tailport=e, headport=w] "
57
+ end
58
+ end # ds.calculatedFields.each
59
+ # "federated.17h7owt0rsacke17cql8o0w2ittk" -> "New AO Actuals Query in PP+ (AO Variance Data)::vs Prior Year [YTD]"
60
+ # "federated.01s5lca037ted31gxs9sg0t9mnnt" [label="Controls" ]
61
+ edges.each do |edge|
62
+ @dotFile.puts "\t #{edge.strip}"
63
+ end
64
+ @dotFile.puts " "
65
+ allFields = calcFields + refFields
66
+ allFields.each do |f|
67
+ @dotFile.puts "\t \"#{f}\" [label=\"#{f}\"]"
68
+ end
69
+ endPointFields = allFields - calcFields
70
+ rankSame(endPointFields) unless endPointFields.nil? || endPointFields.empty?
71
+ closeDotFile
72
+ @@imageTypes.each do |type|
73
+ renderDot type
74
+ end
75
+ end
76
+ end # twb.datasources.each
77
+ finis
78
+ end # def processTwb twb
79
+
80
+ private
81
+
82
+ def initDotFile dsName
83
+ @dotFileName = './ttdoc/' + @twb.name + '.' + dsName + '.CalculatedFields.dot'
84
+ @dotFile = File.open(@dotFileName,'w')
85
+ # @dotFile.puts @@dotHeader
86
+ @dotFile.puts ' digraph g {'
87
+ @dotFile.puts ' graph [rankdir="LR" splines=line];'
88
+ @dotFile.puts ' node [shape="box" width="2"];'
89
+ @dotFile.puts ' '
90
+ @dotFile.puts ' subgraph cluster_0 {'
91
+ end
92
+
93
+ def closeDotFile
94
+ # @dotFile.puts "\n # counted #{@cfCnt} calculated fields\n "
95
+ # @dotFile.puts "\n }"
96
+ @dotFile.puts ' }'
97
+ @dotFile.puts ' '
98
+ @dotFile.puts '// -------------------------------------------------------------'
99
+ @dotFile.puts ' '
100
+ @dotFile.puts ' subgraph cluster_1 {'
101
+ #@dotFile.puts ' color=white;'
102
+ @dotFile.puts ' style=invis;'
103
+ #@dotFile.puts ' border=0;'
104
+ @dotFile.puts ' node [border=blue];'
105
+ @dotFile.puts ' '
106
+ @dotFile.puts ' "" [style=invis]'
107
+ @dotFile.puts " \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{@twb.name}'\\n#{Time.new.ctime}\" [penwidth=0]"
108
+ #@dotFile.puts " \"Tableau Tools Workbook Calculated Fields Map\\n#{Time.new.ctime}\" -> \"\" [style=invis]"
109
+ @dotFile.puts ' '
110
+ @dotFile.puts ' }'
111
+ @dotFile.puts ' '
112
+ @dotFile.puts '}'
113
+ @dotFile.close
114
+ end
115
+
116
+ def rankSame fields
117
+ @dotFile.puts "\n {rank=same "
118
+ fields.each do |f|
119
+ @dotFile.puts "\t \"#{f}\" "
120
+ end
121
+ @dotFile.puts " } "
122
+ end
123
+
124
+ def renderDot format
125
+ imageType = '-T' + format
126
+ imageFile = @dotFileName + '.Graph.' + format
127
+ imageParam = '-o"' + imageFile + '"'
128
+ emit "system #{@@gvDotLocation} #{imageType} #{imageParam} \"#{@dotFileName}\""
129
+ system "#{@@gvDotLocation} #{imageType} #{imageParam} \"#{@dotFileName}\""
130
+ # emit " - #{imageFile}"
131
+ @imageFiles << imageFile
132
+ return imageFile
133
+ end
134
+
135
+ end # class DotAnalyzer
136
+
137
+ end # nodule CalculatedFields
138
+ end # module Analysis
139
+ end # module Twb
@@ -52,10 +52,10 @@ module CalculatedFields
52
52
  @docFile.puts "#{l.gsub('<<','[').gsub('>>',']')}"
53
53
  end
54
54
  @docFile.puts "```"
55
- if cf.calcFields.length > 0
55
+ if cf.referencedFields.length > 0
56
56
  fieldsRefOrder = []
57
57
  fieldsSortSet = SortedSet.new
58
- cf.calcFields.each do |field|
58
+ cf.referencedFields.each do |field|
59
59
  fieldsRefOrder.push field.uiname
60
60
  fieldsSortSet << field.uiname
61
61
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twb
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.4
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: creek
@@ -64,6 +64,7 @@ files:
64
64
  - lib/twb/analysis/annotatedfieldscsvemitter.rb
65
65
  - lib/twb/analysis/calculatedfields/calculatedfieldsanalyzer.rb
66
66
  - lib/twb/analysis/calculatedfields/csvemitter.rb
67
+ - lib/twb/analysis/calculatedfields/dotanalyzer.rb
67
68
  - lib/twb/analysis/calculatedfields/fieldsaliasesanalyzer.rb
68
69
  - lib/twb/analysis/calculatedfields/groupfieldsanalyzer.rb
69
70
  - lib/twb/analysis/calculatedfields/markdownemitter.rb