twb 5.1.4 → 5.2.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.
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