twb 4.5.5 → 4.5.7

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/twb/analysis/calculatedfields/calculatedfieldsanalyzer.rb +42 -0
  3. data/lib/twb/analysis/{CalculatedFields → calculatedfields}/csvemitter.rb +0 -0
  4. data/lib/twb/analysis/{CalculatedFields → calculatedfields}/groupfieldsanalyzer.rb +0 -0
  5. data/lib/twb/analysis/{CalculatedFields → calculatedfields}/markdownemitter.rb +0 -0
  6. data/lib/twb/analysis/{DataSources → datasources}/categoricalcolorcodinganalyzer.rb +0 -0
  7. data/lib/twb/analysis/{DataSources → datasources}/datasourcefieldscsvemitter.rb +0 -0
  8. data/lib/twb/analysis/{DataSources → datasources}/datasourceoriginsanalyzer.rb +0 -0
  9. data/lib/twb/analysis/{DataSources/dataSourcesLocationsAnalyzer.rb → datasources/datasourceslocationsanalyzer.rb} +0 -0
  10. data/lib/twb/analysis/{DataSources → datasources}/datasourcetablefieldscsvemitter.rb +0 -0
  11. data/lib/twb/analysis/{DataSources → datasources}/googlesheetdatasourcesanalyzer.rb +0 -0
  12. data/lib/twb/analysis/{DataSources → datasources}/parametersanalyzer.rb +0 -0
  13. data/lib/twb/analysis/{DocumentedFieldsCSVEmitter.rb → documentedfieldscsvemitter.rb} +0 -0
  14. data/lib/twb/analysis/{Sheets/analyzeDashboardSheets.rb → sheets/analyzedashboardsheets.rb} +0 -0
  15. data/lib/twb/analysis/{Sheets → sheets}/dashsheetsanalyzer.rb +0 -0
  16. data/lib/twb/analysis/{Sheets → sheets}/sheetfieldsanalyzer.rb +0 -0
  17. data/lib/twb/analysis/{Sheets → sheets}/sheetfiltersanalyzer.rb +0 -0
  18. data/lib/twb/analysis/{Sheets/sheetfiltersanalyzerA.rb → sheets/sheetfiltersanalyzera.rb} +0 -0
  19. data/lib/twb/analysis/{Sheets → sheets}/sheetsourcesanalyzer.rb +0 -0
  20. data/lib/twb/analysis/{Sheets → sheets}/worksheetdatastructurecsvemitter.rb +0 -0
  21. data/lib/twb/{findDSFields.rb → finddsfields.rb} +0 -0
  22. data/lib/twb/{identifyFields.rb → identifyfields.rb} +0 -0
  23. data/lib/twb/tabtool.rb +12 -10
  24. data/lib/twb/{TwbTest.rb → twbtest.rb} +0 -0
  25. data/lib/twb/util/{ftpPublisher.rb → ftppublisher.rb} +0 -0
  26. data/lib/twb/util/{joinUtilities.rb → joinutilities.rb} +0 -0
  27. data/lib/twb/util/{twbDashesSheetDataDotBuilder.rb → twbdashessheetdatadotbuilder.rb} +0 -0
  28. data/lib/twb/util/{twbDashSheetDataDotRenderer.rb → twbdashsheetdatadotrenderer.rb} +0 -0
  29. data/lib/twb.rb +2 -3
  30. data/t.rb +18 -65
  31. metadata +27 -27
  32. data/lib/twb/analysis/CalculatedFields/calculatedfieldsanalyzer.rb +0 -524
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7049c47a51982f0de1d215e3d2091e559b56346f1e9f1c74b7cbe2464dfcf0c9
4
- data.tar.gz: d7f01f024dea265c8405dc141be50171ac5883d952f38f6128980f949c45cd72
3
+ metadata.gz: 7eb9fb34a75d4869a2ba63a575e532e3fa0c0a9595e454d33574685bd0083ab6
4
+ data.tar.gz: ac54f86e1b09b352dcb6052010ba0486a26860aa74ea294ea8872475a05cd509
5
5
  SHA512:
6
- metadata.gz: 8b56aa09e7dcf6e2d3cfc2e063929066584c5c213dca405d73ccd11862831ce4a69e37e302b8cd41811254bd060e871a4b423b35d0904d84c5cf95a2e87ceaef
7
- data.tar.gz: abfd00faf2f0727ff5839f7662be0a3499fbcd6a315d1670701071720e305eeb68feb9fd4aff9699a9cce7c6410012f43849f94b46cf114bc7f0f0e81828e78d
6
+ metadata.gz: e1d3ee029ca7dc00e9bef48f80fa6b14e52a9ccf5877fa42ae1be1990f8140dc57a819eb84695b580f1564d6cd3e53b76d5a373ad0103feaec138147ac0844e7
7
+ data.tar.gz: 0037410ebe36ae0a2f77f671e7d33d004240b486a2999a8ce118c2876e6665e9d9bd267f14b2fe4bdaee981e1b435d808ff7f7af54cc4b71b2355d2ae03f6ec7
@@ -0,0 +1,42 @@
1
+ # calculatedfieldsanalyzer.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
+ require 'twb'
17
+
18
+ module Twb
19
+ module Analysis
20
+
21
+
22
+ class CalculatedFieldsAnalyzer
23
+
24
+ include TabTool
25
+
26
+ def initialize(**args)
27
+ end
28
+
29
+ def processTWB workbook
30
+ end
31
+
32
+ def metrics
33
+ Array.new
34
+ end
35
+
36
+ #-- private methods begin here, to end of class
37
+
38
+
39
+ end # class
40
+
41
+ end # module Analysis
42
+ end # module Twb
File without changes
File without changes
data/lib/twb/tabtool.rb CHANGED
@@ -112,7 +112,7 @@ module TabTool
112
112
  end
113
113
 
114
114
  def docfiles
115
- @docfiles ||= @docfiles = []
115
+ @docfiles ||= @docfiles = {}
116
116
  end
117
117
 
118
118
  def addDocFile file, name, description
@@ -121,15 +121,17 @@ module TabTool
121
121
  end
122
122
 
123
123
  def closeDocFiles
124
- emit true, "Closing doc files"
125
- @docfiles.each do |dfh|
126
- docfile = dfh[:file]
127
- fileName = dfh[:name]
128
- emit " -- #{dfh}"
129
- # system "ls -l '#{fileName}'"
130
- docfile.close unless docfile.nil?
131
- # system "ls -l '#{fileName}'"
132
- # emit true, " -- #{dfh[:name]}"
124
+ emit "Closing doc files"
125
+ unless @docfiles.nil?
126
+ @docfiles.each do |dfh|
127
+ docfile = dfh[:file]
128
+ fileName = dfh[:name]
129
+ emit " -- #{dfh}"
130
+ # system "ls -l '#{fileName}'"
131
+ docfile.close unless docfile.nil?
132
+ # system "ls -l '#{fileName}'"
133
+ # emit true, " -- #{dfh[:name]}"
134
+ end
133
135
  end
134
136
  emit "-----------------"
135
137
  end
File without changes
File without changes
File without changes
data/lib/twb.rb CHANGED
@@ -52,6 +52,7 @@ require_relative 'twb/util/docprep'
52
52
  require_relative 'twb/analysis/documentedfieldsmarkdownemitter'
53
53
  require_relative 'twb/analysis/annotatedfieldscsvemitter'
54
54
  require_relative 'twb/analysis/workbooksummaryanalyzer'
55
+ require_relative 'twb/analysis/calculatedfields/calculatedfieldsanalyzer'
55
56
  require_relative 'twb/analysis/calculatedfields/groupfieldsanalyzer'
56
57
  require_relative 'twb/analysis/calculatedfields/markdownemitter'
57
58
  require_relative 'twb/analysis/calculatedfields/csvemitter'
@@ -66,11 +67,9 @@ require_relative 'twb/analysis/sheets/sheetfiltersanalyzer'
66
67
  require_relative 'twb/analysis/sheets/sheetfieldsanalyzer'
67
68
  require_relative 'twb/analysis/sheets/dashsheetsanalyzer'
68
69
 
69
- # require_relative 'twb/analysis/calculatedfields/calculatedfieldsanalyzer'
70
-
71
70
 
72
71
  # Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
73
72
  #
74
73
  module Twb
75
- VERSION = '4.5.5'
74
+ VERSION = '4.5.7'
76
75
  end
data/t.rb CHANGED
@@ -1,71 +1,24 @@
1
+ system 'cls'
2
+
1
3
  def checkfile fileName
2
- # puts "--"
3
- qfn = "./lib/#{fileName}.rb"
4
- exists = File.exists? qfn
4
+ exists = File.exists? fileName
5
5
  hasCap = !!(fileName =~ /[A-Z]/)
6
- qfn_tmp = "#{qfn.downcase}.tmp"
7
- qfn_lc = qfn.downcase
8
- puts " %-6s %-13s %-s " % [' ' , ' ' , fileName]
9
- puts " %-6s %-7s %-s " % [exists, hasCap, qfn]
10
- puts " %-6s %-7s %-s " % [exists, hasCap, qfn_tmp]
11
- puts " %-6s %-7s %-s " % ['-' , '-' , qfn_lc]
12
- puts " "
13
- File.rename qfn, qfn_tmp
14
- File.rename qfn_tmp, qfn_lc
6
+ isTest = !!(fileName =~ /test/i)
7
+ if hasCap && !isTest
8
+ fn_tmp = "#{fileName}.tmp"
9
+ fn_lc = fileName.downcase
10
+ puts "-- #{fileName}"
11
+ puts " %-6s t? %-6s %-7s %-s " % [' ' , isTest, ' ' , fileName]
12
+ puts " %-6s %-6s %-7s %-s " % [exists, ' ', hasCap, fileName]
13
+ puts " %-6s %-6s %-7s %-s " % [exists, ' ', hasCap, fn_tmp]
14
+ puts " %-6s %-6s %-7s %-s " % ['-' , '-', '-' , fn_lc]
15
+ # File.rename fileName, fn_tmp
16
+ # File.rename fn_tmp, fn_lc
17
+ puts " "
18
+ end
15
19
  end
16
20
 
17
21
 
18
- checkfile 'twb/tabclass'
19
- checkfile 'twb/tabtool'
20
- checkfile 'twb/dashboard'
21
- checkfile 'twb/datasource'
22
- checkfile 'twb/connection'
23
- checkfile 'twb/docdashboard'
24
- checkfile 'twb/dbfield'
25
- checkfile 'twb/localfield'
26
- checkfile 'twb/metadatafield'
27
- checkfile 'twb/storyboard'
28
- checkfile 'twb/window'
29
- checkfile 'twb/workbook'
30
- checkfile 'twb/worksheet'
31
- checkfile 'twb/parameter'
32
- checkfile 'twb/action'
33
- checkfile 'twb/columnfield'
34
- checkfile 'twb/calculatedfield'
35
- checkfile 'twb/codedfield'
36
- checkfile 'twb/groupfield'
37
- checkfile 'twb/fieldcalculation'
38
- checkfile 'twb/quickfilter'
39
- checkfile 'twb/docdashboardimagevert'
40
- checkfile 'twb/docdashboardwebvert'
41
- checkfile 'twb/util/twbDashSheetDataDotBuilder'
42
- checkfile 'twb/util/dotFileRenderer'
43
- checkfile 'twb/util/htmllistcollapsible'
44
- checkfile 'twb/util/xraydashboards'
45
- checkfile 'twb/util/graph'
46
- checkfile 'twb/util/graphnode'
47
- checkfile 'twb/util/graphedge'
48
- checkfile 'twb/util/graphedges'
49
- checkfile 'twb/util/gml'
50
- checkfile 'twb/util/cypher'
51
- checkfile 'twb/util/cypherpython'
52
- checkfile 'twb/util/fielddomainloader'
53
- checkfile 'twb/util/docprep'
54
- checkfile 'twb/analysis/documentedfieldsmarkdownemitter'
55
- checkfile 'twb/analysis/annotatedfieldscsvemitter'
56
- checkfile 'twb/analysis/WorkbookSummaryAnalyzer'
57
- checkfile 'twb/analysis/calculatedfields/calculatedfieldsanalyzer'
58
- checkfile 'twb/analysis/calculatedfields/groupfieldsanalyzer'
59
- checkfile 'twb/analysis/calculatedfields/markdownemitter'
60
- checkfile 'twb/analysis/calculatedfields/csvemitter'
61
- checkfile 'twb/analysis/datasources/DataSourceFieldsCSVEmitter'
62
- checkfile 'twb/analysis/datasources/DataSourceTableFieldsCSVEmitter'
63
- checkfile 'twb/analysis/datasources/categoricalColorCodingAnalyzer'
64
- checkfile 'twb/analysis/datasources/googlesheetdatasourcesanalyzer'
65
- checkfile 'twb/analysis/datasources/parametersanalyzer'
66
- checkfile 'twb/analysis/datasources/DataSourceOriginsAnalyzer'
67
- checkfile 'twb/analysis/Sheets/WorksheetDataStructureCSVEmitter'
68
- checkfile 'twb/analysis/Sheets/sheetfiltersanalyzer'
69
- checkfile 'twb/analysis/Sheets/sheetfieldsanalyzer'
70
- checkfile 'twb/analysis/Sheets/dashsheetsanalyzer'
22
+ Dir.glob('**/*.rb') { |file| puts file if file =~ /[A-Z]/ }
23
+
71
24
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twb
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.5
4
+ version: 4.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard
@@ -59,29 +59,28 @@ extra_rdoc_files: []
59
59
  files:
60
60
  - lib/t.rb
61
61
  - lib/twb.rb
62
- - lib/twb/TwbTest.rb
63
62
  - lib/twb/action.rb
64
- - lib/twb/analysis/CalculatedFields/calculatedfieldsanalyzer.rb
65
- - lib/twb/analysis/CalculatedFields/csvemitter.rb
66
- - lib/twb/analysis/CalculatedFields/groupfieldsanalyzer.rb
67
- - lib/twb/analysis/CalculatedFields/markdownemitter.rb
68
- - lib/twb/analysis/DataSources/categoricalcolorcodinganalyzer.rb
69
- - lib/twb/analysis/DataSources/dataSourcesLocationsAnalyzer.rb
70
- - lib/twb/analysis/DataSources/datasourcefieldscsvemitter.rb
71
- - lib/twb/analysis/DataSources/datasourceoriginsanalyzer.rb
72
- - lib/twb/analysis/DataSources/datasourcetablefieldscsvemitter.rb
73
- - lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb
74
- - lib/twb/analysis/DataSources/parametersanalyzer.rb
75
- - lib/twb/analysis/DocumentedFieldsCSVEmitter.rb
76
- - lib/twb/analysis/Sheets/analyzeDashboardSheets.rb
77
- - lib/twb/analysis/Sheets/dashsheetsanalyzer.rb
78
- - lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb
79
- - lib/twb/analysis/Sheets/sheetfiltersanalyzer.rb
80
- - lib/twb/analysis/Sheets/sheetfiltersanalyzerA.rb
81
- - lib/twb/analysis/Sheets/sheetsourcesanalyzer.rb
82
- - lib/twb/analysis/Sheets/worksheetdatastructurecsvemitter.rb
83
63
  - lib/twb/analysis/annotatedfieldscsvemitter.rb
64
+ - lib/twb/analysis/calculatedfields/calculatedfieldsanalyzer.rb
65
+ - lib/twb/analysis/calculatedfields/csvemitter.rb
66
+ - lib/twb/analysis/calculatedfields/groupfieldsanalyzer.rb
67
+ - lib/twb/analysis/calculatedfields/markdownemitter.rb
68
+ - lib/twb/analysis/datasources/categoricalcolorcodinganalyzer.rb
69
+ - lib/twb/analysis/datasources/datasourcefieldscsvemitter.rb
70
+ - lib/twb/analysis/datasources/datasourceoriginsanalyzer.rb
71
+ - lib/twb/analysis/datasources/datasourceslocationsanalyzer.rb
72
+ - lib/twb/analysis/datasources/datasourcetablefieldscsvemitter.rb
73
+ - lib/twb/analysis/datasources/googlesheetdatasourcesanalyzer.rb
74
+ - lib/twb/analysis/datasources/parametersanalyzer.rb
75
+ - lib/twb/analysis/documentedfieldscsvemitter.rb
84
76
  - lib/twb/analysis/documentedfieldsmarkdownemitter.rb
77
+ - lib/twb/analysis/sheets/analyzedashboardsheets.rb
78
+ - lib/twb/analysis/sheets/dashsheetsanalyzer.rb
79
+ - lib/twb/analysis/sheets/sheetfieldsanalyzer.rb
80
+ - lib/twb/analysis/sheets/sheetfiltersanalyzer.rb
81
+ - lib/twb/analysis/sheets/sheetfiltersanalyzera.rb
82
+ - lib/twb/analysis/sheets/sheetsourcesanalyzer.rb
83
+ - lib/twb/analysis/sheets/worksheetdatastructurecsvemitter.rb
85
84
  - lib/twb/analysis/workbooksummaryanalyzer.rb
86
85
  - lib/twb/calculatedfield.rb
87
86
  - lib/twb/codedfield.rb
@@ -95,14 +94,14 @@ files:
95
94
  - lib/twb/docdashboardwebvert.rb
96
95
  - lib/twb/field.rb
97
96
  - lib/twb/fieldcalculation.rb
98
- - lib/twb/findDSFields.rb
97
+ - lib/twb/finddsfields.rb
99
98
  - lib/twb/graph.rb
100
99
  - lib/twb/graphedges.rb
101
100
  - lib/twb/graphnode.rb
102
101
  - lib/twb/groupfield.rb
103
102
  - lib/twb/hashtohtml.rb
104
103
  - lib/twb/htmllistcollapsible.rb
105
- - lib/twb/identifyFields.rb
104
+ - lib/twb/identifyfields.rb
106
105
  - lib/twb/localfield.rb
107
106
  - lib/twb/mappedfield.rb
108
107
  - lib/twb/metadatafield.rb
@@ -114,12 +113,13 @@ files:
114
113
  - lib/twb/tabtool.rb
115
114
  - lib/twb/there.rb
116
115
  - lib/twb/twbcodedfield.rb
116
+ - lib/twb/twbtest.rb
117
117
  - lib/twb/util/cypher.rb
118
118
  - lib/twb/util/cypherpython.rb
119
119
  - lib/twb/util/docprep.rb
120
120
  - lib/twb/util/dotfilerenderer.rb
121
121
  - lib/twb/util/fielddomainloader.rb
122
- - lib/twb/util/ftpPublisher.rb
122
+ - lib/twb/util/ftppublisher.rb
123
123
  - lib/twb/util/gml.rb
124
124
  - lib/twb/util/gmledge.rb
125
125
  - lib/twb/util/graph.rb
@@ -128,11 +128,11 @@ files:
128
128
  - lib/twb/util/graphnode.rb
129
129
  - lib/twb/util/hashtohtml.rb
130
130
  - lib/twb/util/htmllistcollapsible.rb
131
- - lib/twb/util/joinUtilities.rb
131
+ - lib/twb/util/joinutilities.rb
132
132
  - lib/twb/util/tabgraph.rb
133
- - lib/twb/util/twbDashSheetDataDotRenderer.rb
134
- - lib/twb/util/twbDashesSheetDataDotBuilder.rb
133
+ - lib/twb/util/twbdashessheetdatadotbuilder.rb
135
134
  - lib/twb/util/twbdashsheetdatadotbuilder.rb
135
+ - lib/twb/util/twbdashsheetdatadotrenderer.rb
136
136
  - lib/twb/util/xraydashboards.rb
137
137
  - lib/twb/window.rb
138
138
  - lib/twb/workbook.rb
@@ -1,524 +0,0 @@
1
- # calculatedfieldsanalyzer.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
- # require 'nokogiri'
17
- # require 'twb'
18
- # require 'set'
19
- require 'csv'
20
-
21
- module Twb
22
- module Analysis
23
-
24
- class CalculatedFieldsAnalyzer
25
-
26
- include TabTool
27
- include Graph
28
-
29
- attr_reader :calculatedFieldsCount, :referencedFieldsCount, :metrics
30
- attr_accessor :ttdocdir
31
-
32
- @@ttlogfile = 'CalculatedFieldsAnalyzer.ttlog'
33
- @@gvDotLocation = 'C:\\tech\\graphviz\\Graphviz2.38\\bin\\dot.exe'
34
- @@processName = '.CalculatedFields'
35
-
36
- @@calcFieldsCSVFileName = 'CalculatedFields.csv'
37
- @@calcFieldsCSVFileHeader = ['Record #',
38
- 'Workbook',
39
- 'Workbook Modified',
40
- 'Data Source', 'Data Source Caption', 'Data Source Name (tech)',
41
- 'Field Name', 'Field Caption', 'Field Name (tech)',
42
- 'Data Source + Field Name (tech)',
43
- 'Data Type', 'Role', 'Type',
44
- 'Class',
45
- 'Scope Isolation',
46
- 'Formula Length',
47
- 'Formula',
48
- 'Formula (tech)',
49
- 'Formula Comments',
50
- 'Formula LOD?'
51
- ]
52
-
53
- @@calcLinesCSVFileName = 'CalculatedFieldsFormulaLines.csv'
54
- @@calcLinesCSVFileHeader = ['Record #',
55
- 'Workbook',
56
- 'Workbook Modified',
57
- 'Data Source', 'Data Source Caption', 'Data Source Name (tech)',
58
- 'Field Name', 'Field Caption', 'Field Name (tech)',
59
- 'Formula', 'Formula Line #', 'Formula Line'
60
- ]
61
-
62
- @@formFieldsCSVFileName = 'CalculatedFieldsReferenced.csv'
63
- @@formFieldsCSVFileHeader = ['Record #',
64
- 'Workbook',
65
- 'Workbook Modified',
66
- 'Data Source',
67
- 'Field - Calculated',
68
- 'Formula (tech)',
69
- 'Formula',
70
- 'Field - Referenced (tech)',
71
- 'Field - Referenced',
72
- 'Data Source + Field - Referenced',
73
- 'Table'
74
- ]
75
-
76
- @techUINames = {}
77
- @fieldTables = {}
78
-
79
-
80
- @@dotHeader = <<DOTHEADER
81
- digraph g {
82
- graph [rankdir="LR" splines=line];
83
- node [shape="box" width="2"];
84
-
85
- DOTHEADER
86
-
87
- def initialize(**args)
88
- @args = args
89
- @recordDir = !@args.nil? && @args[:recordDir] == true
90
- @ttdocdir = @args[:ttdocdir]
91
- @csvAdd = @args[:csvMode] == :add
92
- @csvMode = @csvAdd ? 'a' : 'w'
93
- init
94
- @funcdoc = {:class=>self.class, :blurb=>'Analyze Calculated Fields', :description=>'Calculated fields can be complex, this tool provides robust coverage.',}
95
- #-- CSV records collectors
96
- @csvCalculatedFields = Array.new
97
- @csvFormulaFields = Array.new
98
- @csvFormulaLines = Array.new
99
- #-- Counters setup --
100
- @twbCount = 0
101
- @dataSourcesCount = 0
102
- @calculatedFieldsCount = 0
103
- @referencedFieldsCount = 0
104
- #--
105
- @referencedFields = SortedSet.new
106
- #--
107
- twbdirLabel = @recordDir.nil? ? nil : 'Workbook Dir'
108
- @csvCF = initCSV(@@calcFieldsCSVFileName, 'Calculated fields and their formulas.', @@calcFieldsCSVFileHeader )
109
- @csvCFLs = initCSV(@@calcLinesCSVFileName, "Calculated fields and their formulas' individual lines.", @@calcLinesCSVFileHeader )
110
- @csvFF = initCSV(@@formFieldsCSVFileName, 'Calculated fields and the fields their formulas reference.', @@formFieldsCSVFileHeader )
111
- # TODO migrate addition of 'Workbook Dir' to CSV header to TabTool
112
- #--
113
- @localEmit = false
114
- @imageFiles = Array.new
115
- #--
116
- @doGraph = config(:dograph)
117
- end
118
-
119
- def processTWB workbook
120
- @twb = workbook.is_a?(String) ? Twb::Workbook.new(workbook) : workbook
121
- throw Exception unless @twb.is_a? Twb::Workbook
122
- emit "- Workbook: #{workbook}"
123
- emit " version: #{@twb.version}"
124
- @twbDir = @twb.dir #File.dirname(File.expand_path(workbook))
125
- @modTime = @twb.modtime
126
- @edges = Set.new
127
- #-- processing
128
- dss = @twb.datasources
129
- # puts " # data sources: #{dss.length}"
130
- @twbRootFields = Set.new
131
- @twbFields = Hash.new { |h,k| h[k] = [] }
132
- @nodes = Set.new
133
- dss.each do |ds|
134
- @dataSourcesCount += 1
135
- # puts "\t\t - #{ds.uiname} \t\t #{ds.calculatedFields.length}"
136
- next if ds.Parameters? # don't process the Parameters data source - Parameters' fields aren't Calculated fields for our purposes
137
- # dataSourceNode = Twb::Util::Graphnode.new(name: ds.uiname, id: ds.id, type: ds, properties: {workbook: workbook})
138
- # @nodes.add dataSourceNode
139
- # ds.calculatedFields.each do |calcField|
140
- # end
141
- processDataSource ds
142
- end
143
- mapTwb
144
- emitGml
145
- @twbCount += 1
146
- finis
147
- end
148
-
149
- def metrics
150
- @metrics ||= loadMetrics
151
- end
152
-
153
- def loadMetrics
154
- @metrics = {
155
- '# of Workbooks' => @twbCount,
156
- '# of Data Sources' => @dataSourcesCount,
157
- '# of Calculated Fields' => @calculatedFieldsCount,
158
- '# of Referenced Fields' => @referencedFieldsCount,
159
- }
160
- end
161
-
162
- #-- private methods begin here, to end of class
163
-
164
- private
165
-
166
- def emitGml
167
- gml = Twb::Util::GML.new
168
- gml.fileName = @twb.name
169
- gml.nodes = @nodes
170
- gml.edges = @edges
171
- gml.render
172
- end
173
-
174
- def processDataSource ds
175
- emit "======= DATA SOURCE: #{ds.uiname} ====== "
176
- dsNodes = Set.new
177
- dsEdges = Set.new
178
- dsFields = {}
179
- @twbFields[ds.uiname] = dsFields
180
- calculatedFields = SortedSet.new
181
- fieldFormulaLines = Array.new
182
- referencedFields = SortedSet.new
183
- # if @doGraph
184
- dataSourceNode = Twb::Util::Graphnode.new(name: ds.uiname, id: ds.id, type: ds, properties: {workbook: @twb.name})
185
- @nodes.add dataSourceNode
186
- # end
187
- #-- process Calculatred Fields
188
- ds.calculatedFields.each do |calcField|
189
- emit "Calculated Field: #{calcField}"
190
- calculatedFields.add calcField.id
191
- dsFields[calcField.uiname] = calcField
192
- # if @doGraph
193
- calcFieldNode = Twb::Util::Graphnode.new(name: calcField.uiname, id: calcField.id, type: calcField, properties: {:DataSource => ds.uiname})
194
- @nodes.add calcFieldNode
195
- dsFieldEdge = Twb::Util::Graphedge.new(from: dataSourceNode, to: calcFieldNode, relationship: 'contains')
196
- @edges.add dsFieldEdge
197
- # end
198
- calculation = calcField.calculation
199
- if calculation.has_formula
200
- #-- collect field formulas as single lines
201
- @csvCalculatedFields.push [
202
- @calculatedFieldsCount += 1,
203
- @twb.name,
204
- @modTime,
205
- ds.uiname,
206
- ds.caption,
207
- ds.name,
208
- calcField.uiname,
209
- calcField.caption,
210
- calcField.name,
211
- ds.name + '::' + calcField.name,
212
- calcField.datatype,
213
- calcField.role,
214
- calcField.type,
215
- calculation.class,
216
- calculation.scopeIsolation,
217
- calculation.formulaFlat.length,
218
- calculation.formulaFlatResolved,
219
- calculation.formulaFlat,
220
- calculation.comments,
221
- calculation.is_lod
222
- ]
223
- #-- collect individual formula lines
224
- flnum = 0
225
- emit "@@ calcField.uiname: #{calcField.uiname}"
226
- calculation.formulaResolvedLines.each do |fl|
227
- emit "@@ resolved line:: => '#{fl}'"
228
- fieldFormulaLines << [ @calculatedFieldsCount, # 'Calc Field #',
229
- @twb.name, # 'Workbook',
230
- @modTime,
231
- ds.uiname, # 'Data Source',
232
- ds.caption, # 'Data Source Caption',
233
- ds.name, # 'Data Source Name (tech)',
234
- calcField.uiname, # 'Field Name',
235
- calcField.caption, # 'Field Caption',
236
- calcField.name, # 'Field Name (tech)',
237
- calcField.calculation.formulaFlatResolved, # 'Formula'
238
- flnum += 1, # 'Formula Line #',
239
- fl.start_with?(" ") ? "'#{fl}" : fl # 'Formula Line' - THIS IS A STUPID HACK NEEDED BECAUSE TABLEAU STRIPS LEADING BLANKS FROM CSV VALUES
240
- ]
241
- end
242
- #-- collect fields referenced in formula
243
- emit "# Calculated Fields: #{calculation.calcFields.length}"
244
- calculation.calcFields.each do |rf|
245
- emit " referenced field ::'#{rf}'"
246
- emit " referenced field.name ::'#{rf.name.nil?}' :: '#{rf.name}'"
247
- emit " referenced field.uiname::'#{rf.uiname}'"
248
- # if @doGraph
249
- unless rf.uiname.nil?
250
- properties = {'DataSource' => ds.uiname, 'DataSourceReference' => 'local', :source => rf}
251
- refFieldNode = Twb::Util::Graphnode.new(name: rf.uiname, id: rf.id, type: rf.type, properties: properties)
252
- @nodes.add refFieldNode
253
- fieldFieldEdge = Twb::Util::Graphedge.new(from: calcFieldNode, to: refFieldNode, relationship: 'references')
254
- @edges.add fieldFieldEdge
255
- end
256
- # end
257
- referencedFields.add rf.id
258
- refFieldTable = ds.fieldTable(rf.name)
259
- emit "refFieldTable.nil? : #{refFieldTable.nil?}"
260
- unless refFieldTable.nil?
261
- tableID = refFieldTable + ':::' + ds.uiname
262
- tableName = "||#{refFieldTable}||"
263
- # if @doGraph
264
- tableNode = Twb::Util::Graphnode.new(name: tableName, id: tableID, type: :DBTable, properties: properties)
265
- @nodes.add tableNode
266
- fieldFieldEdge = Twb::Util::Graphedge.new(from: refFieldNode, to: tableNode, relationship: 'is a field in')
267
- @edges.add fieldFieldEdge
268
- # end
269
- # fldToDsNode = tableNode
270
- end
271
- @csvFormulaFields << [
272
- @referencedFieldsCount += 1,
273
- @twb.name,
274
- @modTime,
275
- ds.uiname,
276
- calcField.uiname,
277
- calculation.formulaFlat,
278
- calculation.formulaFlatResolved,
279
- rf.name,
280
- rf.uiname,
281
- rf.id,
282
- refFieldTable
283
- ]
284
- end # resolvedFields.each do
285
- end # if calculation.has_formula
286
- end # ds.calculatedFields.each
287
-
288
- dsRootFields = calculatedFields - referencedFields
289
- @referencedFields.merge referencedFields
290
- @twbRootFields.merge dsRootFields
291
- if @doGraph
292
- cypher @twb.name
293
- cypherPy @twb.name
294
- end
295
- emit "#######################"
296
- #--
297
- #-- record calculated fields
298
- twbDirCSV = @recordDir.nil? ? nil : @twbDir
299
- emit "@@ record calculated fields ds: #{ds.uiname}"
300
- @csvCalculatedFields.each do |r|
301
- @csvCF << r
302
- end
303
- #-- record individual formula lines
304
- emit "@@ individual formula lines ds: #{ds.uiname}"
305
- fieldFormulaLines.each do |ffl|
306
- @csvCFLs << ffl
307
- end
308
- #-- record formula-referenced fields
309
- emit "@@ formula-referenced fields ds: #{ds.uiname}"
310
- @csvFormulaFields.each do |r|
311
- @csvFF << r
312
- end
313
- #--
314
- return @imageFiles
315
- end # def processDataSource
316
-
317
- def emitCalcfield calcField
318
- emit "\t FIELD cap :: #{calcField.caption} "
319
- emit "\t tname:: #{calcField.name}"
320
- emit "\t uiname:: #{calcField.uiname}"
321
- emit "\t formula:: #{calculation.formulaFlat}"
322
- end
323
-
324
- def mapTwb
325
- twb = @twb.name
326
- rootFields = @twbRootFields
327
- dotStuff = initDot twb
328
- dotFile = dotStuff[:file]
329
- dotFileName = dotStuff[:name]
330
- dotFile.puts "\n // subgraph cluster_1 {"
331
- dotFile.puts " // color= grey;"
332
- dotFile.puts ""
333
- edgesAsStrings = SortedSet.new
334
- # this two step process coalesces the edges into a unique set, avoiding duplicating the dot
335
- # file entries, and can be shrunk when graph edges expose the bits necessary for management by Set
336
- emit "\n========================\nLoading Edges\n========================\n From DC? Referenced? Edge \n %s %s %s" % ['--------', '-----------', '-'*45]
337
- @edges.each do |e|
338
- # don't want to emit edge which is from a Data Connection to a
339
- # Calculated Field which is also referenced by another calculated field
340
- isFromDC = e.from.type == :TwbDataConnection
341
- isRefField = @referencedFields.include?(e.to.id)
342
- edgesAsStrings.add(e.dot) unless isFromDC && isRefField
343
- # emit " ES #{e.dot}"
344
- # emit " ES from #{e.from}"
345
- # emit " ES to #{e.to}"
346
- end
347
- emit "------------------------\n "
348
- edgesAsStrings.each do |es|
349
- dotFile.puts " #{es}"
350
- end
351
- emit "========================\n "
352
- dotFile.puts ""
353
- dotFile.puts " // }"
354
- dotFile.puts "\n\n // 4 NODES --------------------------------------------------------------------"
355
- @nodes.each do |n|
356
- dotFile.puts n.dotLabel
357
- end
358
- dotFile.puts "\n\n // 5--------------------------------------------------------------------"
359
- emitTypes( dotFile )
360
- closeDot( dotFile, twb )
361
- emit "Rendering DOT file - #{twb}"
362
- renderDot(twb,dotFileName,'pdf')
363
- renderDot(twb,dotFileName,'png')
364
- renderDot(twb,dotFileName,'svg')
365
- # emitEdges
366
- end
367
-
368
- def cypher twbName
369
- if @doGraph
370
- cypher = Twb::Util::Cypher.new
371
- cypher.fileName = "#{twbName}.calcFields"
372
- cypher.nodes = @nodes
373
- cypher.edges = @edges
374
- cypher.render
375
- end
376
- end
377
-
378
- def cypherPy twbName
379
- if @doGraph
380
- cypher = Twb::Util::CypherPython.new
381
- cypher.fileName = "#{twbName}.calcFields"
382
- cypher.nodes = @nodes
383
- cypher.edges = @edges
384
- cypher.render
385
- end
386
- end
387
-
388
- # def graphEdges twb
389
- # # graphFile = File.new(twb + '.cypher', 'w')
390
- # # # graphFile.puts "OKEY DOKE, graphing away"
391
- # # cypherCode = Set.new
392
- # # @edges.each do |edge|
393
- # # cypherCode.add edge.from.cypherCreate
394
- # # cypherCode.add edge.to.cypherCreate
395
- # # cypherCode.add edge.cypherCreate
396
- # # end
397
- # # cypherCode.each do |cc|
398
- # # graphFile.puts cc
399
- # # end
400
- # # graphFile.puts "\nreturn *"
401
- # # graphFile.close unless graphFile.nil?
402
- # # @imageFiles << File.basename(graphFile)
403
- # end
404
-
405
- def emitEdges
406
- emit " %-15s %s" % ['type', 'Edge']
407
- emit " %-15s %s" % ['-'*15, '-'*35]
408
- @edges.each do |edge|
409
- emit " %-15s %s" % [edge.from.type, edge.from]
410
- emit " %-15s %s" % [edge.to.type, edge.to]
411
- emit "\n "
412
- end
413
- end
414
-
415
- def emitTypes dotFile
416
- typedNodes = {}
417
- dotFile.puts "\n\n // 2--------------------------------------------------------------------"
418
- @edges.each do |edge|
419
- emit " EDGE :: #{edge}"
420
- loadNodeType typedNodes, edge.from
421
- loadNodeType typedNodes, edge.to
422
- end
423
- typedNodes.each do |type, nodes|
424
- # emit "+++++++++ typedNodes of '#{type}'' "
425
- # nodes.each do |node|
426
- # emit " -n- #{node}"
427
- # end
428
- rankSame(dotFile, type, nodes) unless type.eql? 'CalculatedField' # == :CalculatedField
429
- end
430
- # labelTypes dotFile, edges
431
- end
432
-
433
- def loadNodeType set, node
434
- type = node.type
435
- set[type] = Set.new unless set.include? type
436
- set[type].add node
437
- end
438
-
439
- @@unrankedTypes = ['CalculationField']
440
- def rankSame dotFile, type, nodes
441
- return if @@unrankedTypes.include? type.to_s
442
- @lines = SortedSet.new
443
- nodes.each do |node|
444
- @lines << node.id
445
- end
446
- dotFile.puts "\n // '#{type}' --------------------------------------------------------------------"
447
- dotFile.puts "\n {rank=same "
448
- @lines.each do |line|
449
- dotFile.puts " \"#{line}\""
450
- end
451
- dotFile.puts " }"
452
- end
453
-
454
- def rankRootFields dotFile, dsRootFields
455
- dotFile.puts "\n // Unreferenced (root) Calculated Fields -----------------------------------------"
456
- dotFile.puts "\n {rank=same "
457
- dsRootFields.each do |rf|
458
- emit "ROOT FIELD: #{rf.class} :: #{rf}"
459
- dotFile.puts " \"#{rf}\""
460
- end
461
- dotFile.puts " }"
462
- end
463
-
464
- def labelTypes dotFile
465
- fromTos = Set.new
466
- @edges.each do |edge|
467
- # fromTos.add "\"Alien Data Source\" -> \"Alien Data Source\""
468
- fromTos.add "\"#{edge.from.type}\""
469
- fromTos.add "\"#{edge.to.type}\""
470
- end
471
- return if fromTos.empty?
472
- dotFile.puts "\n // 3--------------------------------------------------------------------"
473
- dotFile.puts ' subgraph cluster_0 {'
474
- dotFile.puts ' color=white;'
475
- dotFile.puts ' node [shape="box3d" style="filled" ];'
476
- fromTos.each do |ft|
477
- dotFile.puts " #{ft}"
478
- end
479
- dotFile.puts ' }'
480
- end
481
-
482
- def initDot twb
483
- dotFileName = docFile("#{twb}#{@@processName}.dot")
484
- dotFile = File.open(dotFileName,'w')
485
- dotFile.puts @@dotHeader
486
- return {:file => dotFile, :name => dotFileName}
487
- end
488
-
489
- def closeDot dotFile, twb
490
- dotFile.puts ' '
491
- dotFile.puts '// -------------------------------------------------------------'
492
- dotFile.puts ' '
493
- dotFile.puts ' subgraph cluster_1 {'
494
- # dotFile.puts ' color=white;'
495
- dotFile.puts ' style=invis;'
496
- # dotFile.puts ' border=0;'
497
- dotFile.puts ' node [border=blue];'
498
- dotFile.puts ' '
499
- dotFile.puts ' "" [style=invis]'
500
- dotFile.puts " \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{twb}'\\n#{Time.new.ctime}\" [penwidth=0]"
501
- # dotFile.puts " \"Tableau Tools Workbook Calculated Fields Map\\n#{Time.new.ctime}\" -> \"\" [style=invis]"
502
- dotFile.puts ' '
503
- dotFile.puts ' }'
504
- dotFile.puts ' '
505
- dotFile.puts '}'
506
- dotFile.close
507
- end
508
-
509
-
510
- def renderDot twb, dot, format
511
- imageType = '-T' + format
512
- imageFile = './ttdoc/' + twb + @@processName + 'Graph.' + format
513
- imageParam = '-o"' + imageFile + '"'
514
- emit "system #{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
515
- system "#{@@gvDotLocation} #{imageType} #{imageParam} \"#{dot}\""
516
- emit " - #{imageFile}"
517
- @imageFiles << imageFile
518
- return imageFile
519
- end
520
-
521
- end # class
522
-
523
- end # module Analysis
524
- end # module Twb