twb 3.7.2 → 3.7.5
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 +4 -4
- data/lib/twb.rb +1 -1
- data/lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb +36 -82
- data/lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb +2 -2
- data/lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb +10 -3
- data/lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb +1 -3
- data/lib/twb/tabtool.rb +78 -7
- data/lib/twb/util/graph.rb +4 -6
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 183bcd3f582a9939faf1544d4b4ecfda0cd36f0a
|
4
|
+
data.tar.gz: 3daae7542ce46541dd310e6f27d717530db9ac95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa968978835cf31847e3446bc02107662b00e3213e4d1345104ace41b6cddd3d2c6d7756bd6ec4ae9a6bcae22acb4904e53771658b210d1847852558f29d43f8
|
7
|
+
data.tar.gz: c19335e986bbbf10166e96b97bb2e0064091fe2e71af00bbc0bc17c4e87b01fa51eefc019ea19e3e23149efaf341d2d95484ffdd06aa19b7e9122713439e639a
|
data/lib/twb.rb
CHANGED
@@ -21,9 +21,10 @@ require 'csv'
|
|
21
21
|
module Twb
|
22
22
|
module Analysis
|
23
23
|
|
24
|
-
class CalculatedFieldsAnalyzer < Twb::Util::Graph
|
24
|
+
class CalculatedFieldsAnalyzer # < Twb::Util::Graph
|
25
25
|
|
26
26
|
include TabTool
|
27
|
+
include Graph
|
27
28
|
|
28
29
|
attr_reader :calculatedFieldsCount, :formulaFieldsCount, :dataFiles
|
29
30
|
attr_accessor :ttdocdir
|
@@ -81,12 +82,7 @@ module Analysis
|
|
81
82
|
DOTHEADER
|
82
83
|
|
83
84
|
def initialize
|
84
|
-
|
85
|
-
@ttdocdir = 'ttdoc'
|
86
|
-
# logfile = docFile(@@ttlogfile)
|
87
|
-
# @logger = Logger.new(logfile)
|
88
|
-
# @logger.level = Logger::DEBUG
|
89
|
-
emit ' Initializing CalculatedFieldsAnalyzer'
|
85
|
+
@funcdoc = {:class=>self.class, :blurb=>'Analyzing Calculated Fields from Tableau Workbooks.', :description=>'Calculated fields can be complex, this tool provides robust coverage.',}
|
90
86
|
#-- CSV records collectors
|
91
87
|
@csvCalculatedFields = []
|
92
88
|
@csvFormulaFields = []
|
@@ -98,43 +94,12 @@ DOTHEADER
|
|
98
94
|
#--
|
99
95
|
@referencedFields = SortedSet.new
|
100
96
|
#--
|
101
|
-
|
102
|
-
@
|
103
|
-
@
|
104
|
-
# @csvCF.close
|
105
|
-
#--
|
106
|
-
emit "init CSV #{@@calcLinesCSVFileName}"
|
107
|
-
@csvCFLs = File.open(docFile(@@calcLinesCSVFileName), 'w')
|
108
|
-
@csvCFLs.puts @@calcLinesCSVFileHeader.to_csv
|
109
|
-
# @csvCFLs.close
|
110
|
-
#--
|
111
|
-
emit "init CSV #{@@formFieldsCSVFileName}"
|
112
|
-
@csvFF = File.open(docFile(@@formFieldsCSVFileName), 'w')
|
113
|
-
@csvFF.puts @@formFieldsCSVFileHeader.to_csv
|
114
|
-
# @csvFF.close
|
115
|
-
#--
|
116
|
-
@dataFiles = { @@calcFieldsCSVFileName => 'Calculated Fields & their Formulas',
|
117
|
-
@@calcLinesCSVFileName => 'Calculated Fields & individual Formula Lines',
|
118
|
-
@@formFieldsCSVFileName => 'Fields referenced in Formulas'
|
119
|
-
}
|
97
|
+
@csvCF = initCSV(@@calcFieldsCSVFileName, 'Calculated fields and their formulas.', @@calcFieldsCSVFileHeader)
|
98
|
+
@csvCFLs = initCSV(@@calcLinesCSVFileName, "Calculated fields and their formulas' individual lines.", @@calcLinesCSVFileHeader)
|
99
|
+
@csvFF = initCSV(@@formFieldsCSVFileName, 'Calculated fields and the fields their formulas reference.', @@formFieldsCSVFileHeader)
|
120
100
|
#--
|
121
101
|
@localEmit = false
|
122
|
-
@imageFiles
|
123
|
-
end
|
124
|
-
|
125
|
-
def initDocDir
|
126
|
-
return if $ttdocdir.nil?
|
127
|
-
return if ''.eql? $ttdocdir
|
128
|
-
return if Dir.exists?($ttdocdir)
|
129
|
-
if File.exists? $ttdocdir
|
130
|
-
$ttdocdir = nil
|
131
|
-
return
|
132
|
-
end
|
133
|
-
Dir.mkdir $ttdocdir
|
134
|
-
end
|
135
|
-
|
136
|
-
def docFile name
|
137
|
-
@ttdocdir.nil? ? name : "#{@ttdocdir}\\#{name}"
|
102
|
+
@imageFiles = []
|
138
103
|
end
|
139
104
|
|
140
105
|
def processTWB workbook
|
@@ -221,19 +186,19 @@ DOTHEADER
|
|
221
186
|
emit "@@ FL: #{calcField.uiname}"
|
222
187
|
calculation.formulaResolvedLines.each do |fl|
|
223
188
|
emit "@@ FL: => '#{fl}'"
|
224
|
-
fieldFormulaLines
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
189
|
+
fieldFormulaLines << [ @calculatedFieldsCount, # 'Calc Field #',
|
190
|
+
@twb.name, # 'Workbook',
|
191
|
+
@twbDir, # 'Workbook Dir',
|
192
|
+
ds.uiname, # 'Data Source',
|
193
|
+
ds.caption, # 'Data Source Caption',
|
194
|
+
ds.name, # 'Data Source Name (tech)',
|
195
|
+
calcField.uiname, # 'Field Name',
|
196
|
+
calcField.caption, # 'Field Caption',
|
197
|
+
calcField.name, # 'Field Name (tech)',
|
198
|
+
calcField.calculation.formulaFlatResolved, # 'Formula'
|
199
|
+
flnum += 1, # 'Formula Line #',
|
200
|
+
fl.start_with?(" ") ? "'#{fl}" : fl # 'Formula Line' - THIS IS A STUPID HACK NEEDED BECAUSE TABLEAU STRIPS LEADING BLANKS FROM CSV VALUES
|
201
|
+
]
|
237
202
|
end
|
238
203
|
#-- collect fields referenced in formula
|
239
204
|
calculation.calcFields.each do |rf|
|
@@ -256,19 +221,19 @@ DOTHEADER
|
|
256
221
|
@edges.add fieldFieldEdge
|
257
222
|
# fldToDsNode = tableNode
|
258
223
|
end
|
259
|
-
@csvFormulaFields
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
224
|
+
@csvFormulaFields << [
|
225
|
+
@formulaFieldsCount += 1,
|
226
|
+
@twb.name,
|
227
|
+
@twbDir,
|
228
|
+
ds.uiname,
|
229
|
+
calcField.uiname,
|
230
|
+
calculation.formulaFlat,
|
231
|
+
calculation.formulaResolved,
|
232
|
+
rf.name,
|
233
|
+
rf.uiname,
|
234
|
+
rf.id,
|
235
|
+
refFieldTable
|
236
|
+
]
|
272
237
|
end # resolvedFields.each do
|
273
238
|
end # if calculation.has_formula
|
274
239
|
end # ds.calculatedFields.each
|
@@ -280,35 +245,24 @@ DOTHEADER
|
|
280
245
|
cypherPy @twb.name
|
281
246
|
emit "#######################"
|
282
247
|
#-- record calculated fields
|
283
|
-
# @csvCF = File.open(docFile(@@calcFieldsCSVFileName), 'a')
|
284
|
-
# @csvCF.puts @@calcFieldsCSVFileHeader.to_csv
|
285
248
|
emit "@@ record calculated fields ds: #{ds.uiname}"
|
286
|
-
# @csvCF.open('a')
|
287
249
|
@csvCalculatedFields.each do |r|
|
288
|
-
@csvCF
|
250
|
+
@csvCF << r
|
289
251
|
end
|
290
252
|
#-- record individual formula lines
|
291
|
-
# @csvCFLs = File.open(docFile(@@calcLinesCSVFileName), 'a')
|
292
|
-
# @csvCFLs.puts @@calcLinesCSVFileHeader.to_csv
|
293
253
|
emit "@@ individual formula lines ds: #{ds.uiname}"
|
294
254
|
fieldFormulaLines.each do |ffl|
|
295
|
-
|
296
|
-
emit "@@@@ FFLB: #{ffl.to_csv}"
|
297
|
-
emit "@@@@ FFLc: "
|
298
|
-
@csvCFLs.puts ffl.to_csv
|
255
|
+
@csvCFLs << ffl
|
299
256
|
end
|
300
257
|
#-- record formula-referenced fields
|
301
|
-
# @csvFF = File.open(docFile(@@formFieldsCSVFileName), 'a')
|
302
|
-
# @csvFF.puts @@formFieldsCSVFileHeader.to_csv
|
303
258
|
emit "@@ formula-referenced fields ds: #{ds.uiname}"
|
304
259
|
@csvFormulaFields.each do |r|
|
305
|
-
@csvFF
|
260
|
+
@csvFF << r
|
306
261
|
end
|
307
262
|
#--
|
308
263
|
return @imageFiles
|
309
264
|
end # def processDataSource
|
310
265
|
|
311
|
-
|
312
266
|
def emitCalcfield calcField
|
313
267
|
emit "\t FIELD cap :: #{calcField.caption} "
|
314
268
|
emit "\t tname:: #{calcField.name}"
|
@@ -32,13 +32,13 @@ module CalculatedFields
|
|
32
32
|
@twb = twb #Twb::Workbook.new twb
|
33
33
|
@docFileName = './ttdoc/' + @twb.name + '.CalculatedFields.md'
|
34
34
|
@docFile = File.open(@docFileName,'w')
|
35
|
-
@docFile.puts "
|
35
|
+
@docFile.puts "# #{twb.name}"
|
36
36
|
dsNames = @twb.datasourceUINames
|
37
37
|
@docFile.puts "#{dsNames.length} Data Sources"
|
38
38
|
|
39
39
|
|
40
40
|
@twb.datasources.each do |ds|
|
41
|
-
@docFile.puts "
|
41
|
+
@docFile.puts "## #{ds.uiname}"
|
42
42
|
@docFile.puts "__has #{ds.calculatedFields.length} calculated fields__\n "
|
43
43
|
cnt = 0
|
44
44
|
ds.calculatedFields.each do |cf|
|
@@ -28,14 +28,21 @@ module Analysis
|
|
28
28
|
attr_reader :twbname, :twbcount
|
29
29
|
|
30
30
|
def initialize
|
31
|
+
#-- set up metrics
|
31
32
|
@twbcount = 0
|
32
|
-
@
|
33
|
-
@
|
33
|
+
@dscount = 0
|
34
|
+
@sheetcount = 0
|
35
|
+
@metrics = {
|
36
|
+
'# of Workbooks' => @twbcount ,
|
37
|
+
'# of Worksheets' => @dscount ,
|
38
|
+
'# of Worksheets' => @sheetcount
|
39
|
+
}
|
40
|
+
#--
|
34
41
|
@funcdoc = {:class=>self.class, :blurb=>'Analyzing Google Sheet Data Sources from Tableau Workbooks.', :description=>nil,}
|
35
42
|
docFileName = docFile('TWBGoogleSheetDataSources.csv')
|
36
43
|
@csv = CSV.open(docFileName, 'w')
|
37
44
|
@csv << ["Workbook",'Data Source','Connection','File Name','Type','Table Name','Field']
|
38
|
-
@docfiles = [{:name=>docFileName,:
|
45
|
+
@docfiles = [{:name=>docFileName,:description=>"CSV File containing the data relating Google Sheet-based Data Sources."}]
|
39
46
|
end
|
40
47
|
|
41
48
|
def processTWB twb
|
@@ -15,7 +15,6 @@
|
|
15
15
|
|
16
16
|
require 'twb'
|
17
17
|
require 'csv'
|
18
|
-
require 'set'
|
19
18
|
|
20
19
|
module Twb
|
21
20
|
module Analysis
|
@@ -34,7 +33,7 @@ module Analysis
|
|
34
33
|
docFileName = docFile('TWBWorksheetFields.csv')
|
35
34
|
@sheetFieldsCSV = CSV.open(docFileName,'w')
|
36
35
|
@sheetFieldsCSV << ['Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)']
|
37
|
-
|
36
|
+
addDocFile docFileName, "CSV File containing the data relating Workbooks,Worksheets, and the sheets' Data Sources and Fields"
|
38
37
|
end
|
39
38
|
|
40
39
|
def processTWB twb
|
@@ -45,7 +44,6 @@ module Analysis
|
|
45
44
|
parseSheets
|
46
45
|
end
|
47
46
|
|
48
|
-
|
49
47
|
def parseSheets
|
50
48
|
@worksheets = @twb.worksheets
|
51
49
|
@worksheets.each do |sheet|
|
data/lib/twb/tabtool.rb
CHANGED
@@ -17,29 +17,75 @@ require 'logger'
|
|
17
17
|
|
18
18
|
module TabTool
|
19
19
|
|
20
|
-
attr_accessor :ttdocdir, :logger,
|
21
|
-
attr_reader :funcdoc, :docfiles
|
20
|
+
attr_accessor :ttdocdir, :logger, :loglevel, :logfilename
|
21
|
+
attr_reader :funcdoc, :docfiles, :metrics
|
22
22
|
|
23
23
|
TTDOCDIR = './ttdoc'
|
24
24
|
|
25
25
|
@funcdoc = {:class=>nil, :blurb=>nil, :description=>nil,}
|
26
|
-
@docfiles = {}
|
26
|
+
@docfiles = [] # should be of form [{:name=>'docFileName',:description=>'doc file description'}]
|
27
27
|
|
28
28
|
@ttdocdir = './ttdoc'
|
29
29
|
@logfilename = 'TabTools.ttlog'
|
30
30
|
@loglevel = Logger::DEBUG
|
31
31
|
@localEmit = false
|
32
|
+
@docDirSet = false
|
32
33
|
|
33
34
|
def funcdoc
|
34
35
|
@funcdoc.nil? ? {:class=>'n/a', :blurb=>'generic TabTool blurb', :description=>'A useful Tableau Tool.'} : @funcdoc
|
35
36
|
end
|
36
37
|
|
37
38
|
def docFile name
|
38
|
-
|
39
|
-
|
39
|
+
initDocDir unless @docDirSet
|
40
|
+
@docDir.nil? ? name : "#{@docDir}/#{name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def docfiles
|
44
|
+
@docfiles ||= @docfiles = []
|
45
|
+
end
|
46
|
+
|
47
|
+
def addDocFile name, description
|
48
|
+
@docfiles = [] if @docfiles.nil?
|
49
|
+
@docfiles << {:name=>name,:description=>description}
|
50
|
+
end
|
51
|
+
|
52
|
+
def docFileMaxNameLen
|
53
|
+
maxlen = 0
|
54
|
+
docfiles.each do |f|
|
55
|
+
nameLen = f[:name].class == String ? [maxlen, f[:name].length].max : 0
|
56
|
+
maxlen = nameLen.nil? ? maxlen : [maxlen,nameLen].max
|
57
|
+
end
|
58
|
+
return maxlen
|
59
|
+
end
|
60
|
+
|
61
|
+
def docfilesdoc
|
62
|
+
lines = SortedSet.new
|
63
|
+
unless @docfiles.nil? || @docfiles.empty?
|
64
|
+
nameLen = docFileMaxNameLen
|
65
|
+
docfiles.each do |dfi|
|
66
|
+
lines << " - %-#{nameLen}s %-s " % [ dfi[:name], dfi[:description] ]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
docLines = lines.empty? ? [] : [' ','For documentation and generated data see the following:',' ']
|
70
|
+
lines.each do |l|
|
71
|
+
docLines << l
|
72
|
+
end
|
73
|
+
return docLines
|
74
|
+
end
|
75
|
+
|
76
|
+
def initCSV(fileName, desc=nil, header=nil)
|
77
|
+
# puts 'initCSV'
|
78
|
+
# puts " @docDirSet: #{@docDirSet} "
|
79
|
+
csvName = docFile(fileName)
|
80
|
+
emit "init CSV #{csvName}"
|
81
|
+
csvFile = CSV.open(csvName, 'w')
|
82
|
+
csvFile << header unless header.nil?
|
83
|
+
addDocFile csvName,desc
|
84
|
+
return csvFile
|
40
85
|
end
|
41
86
|
|
42
87
|
def emit(local=@localEmit, stuff)
|
88
|
+
initDocDir if @docDirSet.nil? || !@docDirSet
|
43
89
|
initLogger if @logger.nil?
|
44
90
|
if stuff.is_a? String then
|
45
91
|
lines = stuff.split(/\n/)
|
@@ -54,10 +100,35 @@ module TabTool
|
|
54
100
|
end
|
55
101
|
|
56
102
|
def initLogger
|
57
|
-
|
58
|
-
|
103
|
+
initDocDir unless @docDirSet
|
104
|
+
initDocDir
|
105
|
+
logFileName = docFile("#{self.class.to_s.split('::').last}.ttlog")
|
106
|
+
@logger = Logger.new(logFileName)
|
59
107
|
@logger.level = Logger::DEBUG
|
60
108
|
end
|
61
109
|
|
110
|
+
def initDocDir
|
111
|
+
# puts 'initDocDir - begin'
|
112
|
+
# puts " @docDirSet: #{@docDirSet} "
|
113
|
+
# puts " TTDOCDIR : #{TTDOCDIR} "
|
114
|
+
# puts " $ttdocdir : #{$ttdocdir} "
|
115
|
+
# puts " @docDir : #{@docDir} "
|
116
|
+
return if @docDirSet
|
117
|
+
return if TTDOCDIR.nil? && $ttdocdir.nil?
|
118
|
+
return if ''.eql?($ttdocdir) && ''.eql?(TTDOCDIR)
|
119
|
+
@docDir = $ttdocdir.nil? ? TTDOCDIR : $ttdocdir
|
120
|
+
return if Dir.exists?(@docDir)
|
121
|
+
if File.exists? @docDir
|
122
|
+
@docDir = nil
|
123
|
+
return
|
124
|
+
end
|
125
|
+
Dir.mkdir @docDir
|
126
|
+
@docDirSet = true
|
127
|
+
# puts " @docDirSet: #{@docDirSet} "
|
128
|
+
# puts " @docDir : #{@docDir} "
|
129
|
+
# puts 'initDocDir - end'
|
130
|
+
end
|
131
|
+
|
132
|
+
|
62
133
|
end # module TabTool
|
63
134
|
|
data/lib/twb/util/graph.rb
CHANGED
@@ -13,18 +13,16 @@
|
|
13
13
|
# You should have received a copy of the GNU General Public License
|
14
14
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
15
|
|
16
|
-
module
|
17
|
-
module Util
|
16
|
+
module Graph
|
18
17
|
|
19
|
-
class Graph
|
20
18
|
attr_accessor :nodes, :edges
|
19
|
+
|
21
20
|
def nodes
|
22
21
|
@nodes ||= @nodes = []
|
23
22
|
end
|
23
|
+
|
24
24
|
def edges
|
25
25
|
@edges ||= @edges = []
|
26
26
|
end
|
27
|
-
end
|
28
27
|
|
29
|
-
end # module
|
30
|
-
end # module Twb
|
28
|
+
end # module Graph
|