twb 3.9.7 → 4.3.1

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.
@@ -28,14 +28,15 @@ module Analysis
28
28
  attr_reader :twbname, :twbcount
29
29
 
30
30
  def initialize
31
+ init
31
32
  #-- set up metrics
32
33
  @twbcount = 0
33
34
  @dscount = 0
34
35
  @filecount = 0
35
36
  @sheetcount = 0
36
37
  #--
37
- @funcdoc = {:class=>self.class, :blurb=>'Analyzing Google Sheet Data Sources from Tableau Workbooks.', :description=>nil,}
38
- docFileName = docFile('TWBGoogleSheetDataSources.csv')
38
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Google Sheet Data Sources', :description=>nil,}
39
+ docFileName = docFile('GoogleSheetDataSources.csv')
39
40
  @csv = CSV.open(docFileName, 'w')
40
41
  @csv << ["Workbook",'Data Source','Connection','File Name','Type','Table Name','Field']
41
42
  @docfiles = [{:name=>docFileName,:description=>"CSV File containing the data relating Google Sheet-based Data Sources."}]
@@ -57,9 +58,9 @@ module Analysis
57
58
  conns = ds.node.xpath(".//connection[@class='google-sheets']")
58
59
  if conns.length > 0
59
60
  @relation = ds.node.at_xpath('./connection/relation')
60
- @relName = @relation.attribute('name').text
61
- @relType = @relation.attribute('type').text
62
- @fileName = ds.node.at_xpath('.//named-connection/connection').attribute('filename')
61
+ @relName = @relation.nil? ? 'n/a - no relation in connection' : @relation['name']
62
+ @relType = @relation.nil? ? 'n/a - no relation in connection' : @relation['type']
63
+ @fileName = ds.node.at_xpath('.//named-connection/connection')['filename']
63
64
  @filecount += 1
64
65
  emit "FILENAME: #{@fileName}"
65
66
  tables = ds.node.xpath(".//relation[@type='table']")
@@ -27,12 +27,12 @@ module Analysis
27
27
 
28
28
  def initialize
29
29
  init
30
- @funcdoc = {:class=>self.class, :blurb=>'Analyze Dashboard Sheets from Tableau Workbooks.', :description=>'Identifies the Worksheets present in Dashboards.',}
30
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Dashboard Worksheets', :description=>'Identifies the Worksheets present in Dashboards.',}
31
31
  #--
32
- docFileName = docFile('TwbDashboardSheets.csv')
32
+ docFileName = docFile('DashboardSheets.csv')
33
33
  @dashSheetsCSV = CSV.open(docFileName,'w')
34
- @dashSheetsCSV << ['Workbook','Dashboard','Worksheet','Hidden','Visible']
35
- addDocFile docFileName, "Workbooks, Dashboards, and Worksheets in the Dashboards"
34
+ @dashSheetsCSV << ['Workbook','Workbook Dir','Modified','Dashboard','Worksheet','Hidden','Visible']
35
+ addDocFile docFileName, "Workbooks, Dashboards, and their Worksheets"
36
36
  #--
37
37
  @twbCount = 0
38
38
  @dashCount = 0
@@ -50,6 +50,8 @@ module Analysis
50
50
  def processTWB twb
51
51
  @twb = twb
52
52
  @twbName = @twb.name
53
+ @twbDir = @twb.dir
54
+ @modTime = @twb.modtime
53
55
  emit " -- #{@twbName}"
54
56
  @twbCount += 1
55
57
  parseDashes
@@ -64,7 +66,7 @@ module Analysis
64
66
  dash.worksheets.each do |sheet|
65
67
  @sheetCount += 1
66
68
  emit "SHEET: #{sheet.name}"
67
- @dashSheetsCSV << [@twbName, dash.name, sheet.name, sheet.hidden, sheet.visible ]
69
+ @dashSheetsCSV << [@twbName, @twbDir, @modTime, dash.name, sheet.name, sheet.hidden, sheet.visible ]
68
70
  end
69
71
  end
70
72
  end
@@ -23,20 +23,36 @@ module Analysis
23
23
 
24
24
  include TabTool
25
25
 
26
+ @@fieldTypeCodes = { 'DB ref' => 'Db',
27
+ 'color' => 'Clr',
28
+ 'filter' => 'F',
29
+ 'lod' => 'L',
30
+ 'page' => 'Pg',
31
+ 'path' => 'Pt',
32
+ 'shape' => 'Sh',
33
+ 'size' => 'Sz',
34
+ 'text' => 'Tx',
35
+ 'tooltip' => 'Tt',
36
+ :column => 'Cm',
37
+ :row => 'R',
38
+ }
39
+
40
+
26
41
  attr_accessor :localEmit
27
42
 
28
43
  def initialize
29
44
  init
30
- @funcdoc = {:class=>self.class, :blurb=>'Analyze Sheet Fields from Tableau Workbooks.', :description=>nil,}
45
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Fields', :description=>nil,}
31
46
  #--
32
- docFileName = docFile('TwbWorksheetFields.csv')
47
+ docFileName = docFile('WorksheetFields.csv')
33
48
  @sheetFieldsCSV = CSV.open(docFileName,'w')
34
- @sheetFieldsCSV << ['Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)']
49
+ @sheetFieldsCSV << ['Rec #', 'Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)','Usage','Usage - code']
35
50
  addDocFile docFileName, "Workbooks, Worksheets, and the Sheets' Data Sources and Fields"
36
51
  #--
37
52
  @twbCnt = 0
38
53
  @sheetCnt = 0
39
54
  @fieldsCnt = 0
55
+ @recNum = 0
40
56
  end
41
57
 
42
58
  def metrics
@@ -49,27 +65,57 @@ module Analysis
49
65
 
50
66
  def processTWB twb
51
67
  @twb = twb
52
- emit " -- #{@twb.name}"
68
+ emit " -- twb:: #{@twb.name}"
53
69
  @twbCnt += 1
54
70
  @twbDomainsLoaded = false
55
71
  parseSheets
56
72
  finis
57
73
  end
58
74
 
75
+ private
76
+
59
77
  def parseSheets
60
78
  @worksheets = @twb.worksheets
61
79
  @worksheets.each do |sheet|
80
+ @sheet = sheet.name
62
81
  @sheetCnt += 1
63
- emit "SHEET: #{sheet.name}"
82
+ emit "SHEET: #{@sheet}"
64
83
  showFields sheet unless sheet.datasourceFields.nil?
65
84
  end
66
85
  end
67
86
 
68
87
  def showFields sheet
88
+ showDBFields sheet
89
+ showRCFields sheet.rowFields, :row
90
+ showRCFields sheet.colFields, :column
91
+ showEncodedFields sheet
92
+ showFilterFields sheet
93
+ showPageFields sheet
94
+ end
95
+
96
+ def showPageFields sheet
97
+ sheet.pageFields.each do |pfield|
98
+ ds = @twb.datasource pfield.dataSource
99
+ fuiname = ds.fieldUIName pfield.name
100
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, ds.name, fuiname, pfield.name, 'page', ftc('filter')]
101
+ end
102
+ end
103
+
104
+ def showFilterFields sheet
105
+ filters = sheet.filters
106
+ filters.each do |filter|
107
+ dsName = filter.dataSource.name
108
+ dsUIName = filter.dataSource.uiname
109
+ # puts "Filter field: #{filter.dataSource.name} ui:'#{}'"
110
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, dsUIName, dsName, filter.uiname, filter.name, 'filter', ftc('filter')]
111
+ end
112
+ end
113
+
114
+ def showDBFields sheet
69
115
  fields = sheet.datasourceFields
70
- emit " #FIELDS: #{fields.length}"
116
+ emit "def showDBFields sheet: #{sheet.name} #FIELDS: #{fields.length}"
71
117
  if fields.nil?
72
- @sheetFieldsCSV << [@twb.name, sheet.name, nil, nil, nil, nil]
118
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil]
73
119
  end
74
120
  fields.each do |dsName, dsfields|
75
121
  ds = @twb.datasource dsName
@@ -81,12 +127,48 @@ module Analysis
81
127
  emit " f: #{sheetField}"
82
128
  emit " c: #{sheetField.class}"
83
129
  fuiName = ds.fieldUIName sheetField #Fields[sheetField]
84
- @sheetFieldsCSV << [@twb.name, sheet.name, ds.uiname, dsName, sheetField.uiname, sheetField.name]
130
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, sheetField.uiname, sheetField.name, 'DB ref', ftc('DB ref')]
85
131
  # emit true, " : #{dsFields[field].class}"
86
132
  end
87
133
  end
88
134
  end
89
135
 
136
+ def showRCFields fields, usage
137
+ emit "def showRCFields #fields: #{fields.length} \t #{fields}"
138
+ if fields.nil?
139
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil]
140
+ else
141
+ fields.each do |cf|
142
+ emit "coded field: #{cf}"
143
+ fldName = cf.name
144
+ dsName = cf.dataSource
145
+ ds = @twb.datasource dsName
146
+ emit "DATASOURCE : #{ds.class} " #{ }" #{ds}"
147
+ fuiName = ds.fieldUIName cf.name
148
+ emit " ds: #{dsName}"
149
+ emit " - #{ds.uiname}"
150
+ emit " : #{ds.class}"
151
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, fldName, usage, ftc(usage)]
152
+ end
153
+ end
154
+ end
155
+
156
+ def showEncodedFields sheet
157
+ unless sheet.encodedFields.nil?
158
+ sheet.encodedFields.each do |type,fields|
159
+ fields.each do |field|
160
+ dsName = field.dataSource
161
+ ds = @twb.datasource dsName
162
+ fuiName = ds.fieldUIName field.name
163
+ @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, field.name, type, ftc(type)]
164
+ end
165
+ end
166
+ end
167
+ end #def showEncodedFields
168
+
169
+ def ftc type # ftc : abbr for fieldTypeCode, for brevity
170
+ @@fieldTypeCodes[type].nil? ? type : @@fieldTypeCodes[type]
171
+ end
90
172
 
91
173
  end #class SheetFieldsAnalyzer
92
174
 
@@ -27,11 +27,11 @@ module Analysis
27
27
 
28
28
  def initialize
29
29
  init
30
- @funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet filters.', :description=>'Documents Quick Filters and the values they employ, if any. Work in progess.',}
30
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Filters', :description=>'Documents Quick Filters and the values they employ, if any. Work in progess.',}
31
31
  #--
32
32
  docFileName = docFile('WorksheetFilters.csv')
33
33
  $sheetFieldsCSV = CSV.open( docFileName ,'w')
34
- $sheetFieldsCSV << ['Workbook','Worksheet','Filter Type','Operation','Data Source','Field','Value','Alias', 'Alias?','Operation Mode','Include Null?']
34
+ $sheetFieldsCSV << ['Workbook','Workbook Dir','Worksheet','Filter Type','Operation','Data Source','Field','Value','Alias', 'Alias?','Operation Mode','Include Null?','Kind']
35
35
  addDocFile docFileName, "Workbooks, Worksheets and the sheets' Quick Filters"
36
36
  #--
37
37
  @sheetCount = 0
@@ -48,6 +48,7 @@ module Analysis
48
48
  def processTWB twb
49
49
  @twb = twb
50
50
  @twbName = @twb.name
51
+ @twbDir = @twb.dir
51
52
  emit " -- #{@twbName}"
52
53
  @twbDomainsLoaded = false
53
54
  parseFilters
@@ -62,14 +63,14 @@ module Analysis
62
63
  filter.emit "-----------------------------\nWORKSHEET:: #{sheet.name}\n-----------------------------"
63
64
  if filter.values.empty?
64
65
  # $sheetFieldsCSV << ['Workbook','Worksheet','Filter Type','Operation' ,'Data Source','Field','Value','Alias', 'Alias?']
65
- $sheetFieldsCSV << [@twbName ,sheet.name, filter.type ,filter.inexclude, filter.dataSource.uiname, filter.uiname,nil,nil,nil,filter.inexMode,filter.includeNull]
66
+ $sheetFieldsCSV << [@twbName, @twbDir, sheet.name, filter.type ,filter.inexclude, filter.dataSource.uiname, filter.uiname,nil,nil,nil,filter.inexMode,filter.includeNull,filter.kind]
66
67
  end
67
68
  filter.values.each do |valueMap|
68
69
  value = valueMap[:value]
69
70
  valias = valueMap[:alias]
70
71
  same = value.eql? valias
71
- # puts "RECORDING FILTER VALUES: %-25s -- %-25s same? %s " % [value,valias,same]
72
- $sheetFieldsCSV << [@twbName ,sheet.name, filter.type ,filter.inexclude, filter.dataSource.uiname, filter.uiname, value, valias, same,filter.inexMode,filter.includeNull]
72
+ emit "RECORDING FILTER VALUES: %-35s -- %-25s same? %s " % [value,valias,same]
73
+ $sheetFieldsCSV << [@twbName, @twbDir, sheet.name, filter.type ,filter.inexclude, filter.dataSource.uiname, filter.uiname, value, valias, same,filter.inexMode,filter.includeNull,filter.kind]
73
74
  end
74
75
  end
75
76
  end
@@ -0,0 +1,122 @@
1
+ # sheetfieldsanalyzer.rb Copyright (C) 2018 Chris 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
+ require 'csv'
18
+
19
+ module Twb
20
+ module Analysis
21
+
22
+ class SheetSourcesAnalyzer
23
+
24
+ include TabTool
25
+
26
+ attr_accessor :localEmit
27
+
28
+ def initialize
29
+ init
30
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Fields', :description=>nil,}
31
+ #--
32
+ docFileName = docFile('WorksheetFields.csv')
33
+ @sheetFieldsCSV = CSV.open(docFileName,'w')
34
+ @sheetFieldsCSV << ['Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)','Usage']
35
+ addDocFile docFileName, "Workbooks, Worksheets, and the Sheets' Data Sources and Fields"
36
+ #--
37
+ @twbCnt = 0
38
+ @sheetCnt = 0
39
+ @fieldsCnt = 0
40
+ end
41
+
42
+ def metrics
43
+ {
44
+ '# of Workbooks' => @twbcount,
45
+ '# of Worksheets' => @sheetCnt,
46
+ '# of Worksheet Fields' => @fieldsCnt
47
+ }
48
+ end
49
+
50
+ def processTWB twb
51
+ @twb = twb
52
+ emit " -- twb:: #{@twb.name}"
53
+ @twbCnt += 1
54
+ @twbDomainsLoaded = false
55
+ parseSheets
56
+ finis
57
+ end
58
+
59
+ private
60
+
61
+ def parseSheets
62
+ @worksheets = @twb.worksheets
63
+ @worksheets.each do |sheet|
64
+ @sheet = sheet.name
65
+ @sheetCnt += 1
66
+ emit "SHEET: #{@sheet}"
67
+ showFields sheet unless sheet.datasourceFields.nil?
68
+ end
69
+ end
70
+
71
+ def showFields sheet
72
+ showDBFields sheet
73
+ showRCFields sheet.rowFields, :row
74
+ showRCFields sheet.colFields, :column
75
+ end
76
+
77
+ def showDBFields sheet
78
+ fields = sheet.datasourceFields
79
+ emit "def showDBFields sheet: #{sheet.name} #FIELDS: #{fields.length}"
80
+ if fields.nil?
81
+ @sheetFieldsCSV << [@twb.name, @sheet, nil, nil, nil, nil, nil]
82
+ end
83
+ fields.each do |dsName, dsfields|
84
+ ds = @twb.datasource dsName
85
+ emit " ds: #{dsName}"
86
+ emit " - #{ds.uiname}"
87
+ emit " : #{ds.class}"
88
+ dsfields.each do |sheetField|
89
+ @fieldsCnt += 1
90
+ emit " f: #{sheetField}"
91
+ emit " c: #{sheetField.class}"
92
+ fuiName = ds.fieldUIName sheetField #Fields[sheetField]
93
+ @sheetFieldsCSV << [@twb.name, @sheet, ds.uiname, dsName, sheetField.uiname, sheetField.name, 'DB ref']
94
+ # emit true, " : #{dsFields[field].class}"
95
+ end
96
+ end
97
+ end
98
+
99
+ def showRCFields fields, usage
100
+ emit "def showRCFields #fields: #{fields.length} \t #{fields}"
101
+ if fields.nil?
102
+ @sheetFieldsCSV << [@twb.name, @sheet, nil, nil, nil, nil, nil]
103
+ else
104
+ fields.each do |cf|
105
+ emit "coded field: #{cf}"
106
+ fldName = cf.name
107
+ dsName = cf.dataSource
108
+ ds = @twb.datasource cf.dataSource
109
+ emit "DATASOURCE : #{ds.class} " #{ }" #{ds}"
110
+ fuiName = ds.fieldUIName cf.name
111
+ emit " ds: #{dsName}"
112
+ emit " - #{ds.uiname}"
113
+ emit " : #{ds.class}"
114
+ @sheetFieldsCSV << [@twb.name, @sheet, ds.uiname, dsName, fuiName, fldName, usage]
115
+ end
116
+ end
117
+ end
118
+
119
+ end #class SheetFieldsAnalyzer
120
+
121
+ end # module Analysis
122
+ end # module Twb
@@ -83,6 +83,6 @@ module Twb
83
83
  @fqName <=> other.techCode
84
84
  end
85
85
 
86
- end # class CalculationField
86
+ end # class CodedField
87
87
 
88
88
  end # module Twb
@@ -17,15 +17,117 @@ require 'nokogiri'
17
17
 
18
18
  module Twb
19
19
 
20
- class Connection < TabClass
20
+ class Connection
21
21
 
22
- attr_reader :xmlType
22
+ include TabTool
23
+
24
+ def self.attributeNames
25
+ @@attributeNames ||= [
26
+ 'authentication',
27
+ 'authentication-type',
28
+ 'auto-extract',
29
+ 'channel',
30
+ 'character-set',
31
+ 'class',
32
+ 'cleaning',
33
+ 'compat',
34
+ 'compressed-responses',
35
+ 'compressed-responses-bulk',
36
+ 'compressed-responses-rest',
37
+ 'compressed-responses-soap',
38
+ 'connection-type',
39
+ 'dataRefreshTime',
40
+ 'dbname',
41
+ 'directory',
42
+ 'disable-unicode',
43
+ 'driver',
44
+ 'enum-with-permissions',
45
+ 'expected-driver-version',
46
+ 'filename',
47
+ 'force-character-set',
48
+ 'force-header',
49
+ 'force-separator',
50
+ 'header',
51
+ 'imex',
52
+ 'interpretationMode',
53
+ 'maxfieldlength',
54
+ 'mdwpath',
55
+ 'odbc-connect-string-extras',
56
+ 'odbc-native-protocol',
57
+ 'one-time-sql',
58
+ 'pagesize',
59
+ 'password',
60
+ 'port',
61
+ 'prefer-ind-semantics',
62
+ 'query-band-spec',
63
+ 'REDIRECT_URI',
64
+ 'salesforce-api-version',
65
+ 'schema',
66
+ 'SCOPE',
67
+ 'separator',
68
+ 'server',
69
+ 'server-oauth',
70
+ 'service',
71
+ 'sf-total-requestor-buffer-size-in-mb',
72
+ 'show',
73
+ 'tableau-ri',
74
+ 'tablename',
75
+ 'temporary',
76
+ 'update-time',
77
+ 'updated-database',
78
+ 'use-nonemptycrossjoin',
79
+ 'userLanguage',
80
+ 'username',
81
+ 'validate',
82
+ 'workgroup-auth-mode'
83
+ ]
84
+ end
85
+
86
+ attr_reader :node, :xmlType, :attributes
23
87
 
24
88
  # node: XML element
25
89
  def initialize node
90
+ @node = node
26
91
  @xmlType = node.type
92
+ @path = node.path.gsub(/\[[0-9]+\]/,'')
93
+ @pathNum = /(\d+)/.match(@path)
94
+ @name = nil
95
+ end
96
+
97
+ def processConnection path
98
+ conns = @node.xpath(path)
99
+ conns.each do |connNode|
100
+ connClass = @dsclass
101
+ cpath = conn.path
102
+ connPath = cpath.
103
+ connPNum =
104
+ # puts cpath, connPath
105
+ # puts "CPATH: #{cpath}"
106
+ conn.attributes.each do |name,value|
107
+ # puts "\n\t\t - %-15s -> %-s" % [name, value]
108
+ $csvFile << [ $recCount += 1,
109
+ $twbName, $dir, $build, $version,
110
+ $dsName, $dstype, $dsuiname, connClass,
111
+ connPath, connPNum,
112
+ name, value.value
113
+ ]
114
+ end
115
+ end
116
+ end
117
+
118
+ def attributes
119
+ @attributes ||= loadAttributes
120
+ end
27
121
 
122
+ private
28
123
 
124
+ def loadAttributes
125
+ @attributes = {}
126
+ nodeAttrs = @node.attributes
127
+ @@attributeNames.each do |a|
128
+ @attributes[a] = nodeAttrs[a]
129
+ end
130
+ return @attributes
29
131
  end
30
132
 
31
133
  end # class