twb 4.6.3 → 4.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29ec473a3ccc02db6111d652d70245be94d4dc3f70b949efddfa2bf34ab992d1
4
- data.tar.gz: ffc10036c2e17663a6626cdb7cbc525da061971321c11ed09939e87cbe8f3000
3
+ metadata.gz: 9ba8a4bcf6b220aaf9d3b94a91a903ec055a1637d7d78c063a58a5def3027844
4
+ data.tar.gz: a7f76a9e0fb057cf7aee2c38c82b974e0a59575eb955bd41636e79a38a251f65
5
5
  SHA512:
6
- metadata.gz: f1078e523985681ed1ce0a209cec2c5826733c3147f8c418d576b8844e58df9adf87eed923289047f8fac037d212b4adffdd3f6316fa93f4e172c6119b86c0ce
7
- data.tar.gz: 325066960bf31e5fc0b0cc90bbad7affc5128481e864e388408b78cf1e534b515f629eddc87e89478bdc309be2a29e5731342cec8c7b83526629ef41baad6990
6
+ metadata.gz: 685229ff4ae9181176c42fb85cf9900e64823fa2cbcf4a8ef49a48b0ebbfa96ecf491e27e88c545478a2e4ccad0ba314f648baa28406964032d39e3daefe0904
7
+ data.tar.gz: 86eb832a11d3bb87a66835f29d5eb312477f55421e007dea39c8178568573d39f0ff5d529ab22dfbfe53128b6a1b1145948b5f92bd785cc780b57c3df76d7137
data/lib/twb.rb CHANGED
@@ -57,6 +57,7 @@ require_relative 'twb/analysis/calculatedfields/groupfieldsanalyzer'
57
57
  require_relative 'twb/analysis/calculatedfields/markdownemitter'
58
58
  require_relative 'twb/analysis/calculatedfields/csvemitter'
59
59
  # require_relative 'twb/analysis/datasources/datasourcefieldscsvemitter'
60
+ require_relative 'twb/analysis/datasources/datasourcesenumerator.rb'
60
61
  require_relative 'twb/analysis/datasources/datasourcefieldsanalyzer'
61
62
  require_relative 'twb/analysis/datasources/datasourcetablefieldscsvemitter'
62
63
  require_relative 'twb/analysis/datasources/categoricalcolorcodinganalyzer'
@@ -67,10 +68,11 @@ require_relative 'twb/analysis/sheets/worksheetdatastructurecsvemitter'
67
68
  require_relative 'twb/analysis/sheets/sheetfiltersanalyzer'
68
69
  require_relative 'twb/analysis/sheets/sheetfieldsanalyzer'
69
70
  require_relative 'twb/analysis/sheets/dashsheetsanalyzer'
71
+ require_relative 'twb/analysis/sheets/sheetsintooltipanalyzer'
70
72
 
71
73
 
72
74
  # Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
73
75
  #
74
76
  module Twb
75
- VERSION = '4.6.3'
77
+ VERSION = '4.7.1'
76
78
  end
@@ -43,7 +43,8 @@ module Analysis
43
43
  'Data Type', 'Role', 'Type',
44
44
  'Class',
45
45
  'Scope Isolation',
46
- 'Formula Length',
46
+ 'Formula # Chars',
47
+ 'Formula # Lines',
47
48
  'Formula',
48
49
  'Formula (tech)',
49
50
  'Formula Comments',
@@ -51,7 +52,7 @@ module Analysis
51
52
  ]
52
53
 
53
54
  @@calcLinesCSVFileName = 'CalculatedFieldsFormulaLines.csv'
54
- @@calcLinesCSVFileHeader = ['Record #',
55
+ @@calcLinesCSVFileHeader = ['Calc Field #',
55
56
  'Workbook',
56
57
  # 'Workbook Modified',
57
58
  'Data Source', 'Data Source Caption', 'Data Source Name (tech)',
@@ -94,9 +95,8 @@ DOTHEADER
94
95
  init
95
96
  @funcdoc = {:class=>self.class, :blurb=>'Analyze Calculated Fields', :description=>'Calculated fields can be complex, this tool provides robust coverage.',}
96
97
  #-- CSV records collectors
97
- @csvCalculatedFields = Array.new
98
- @csvFormulaFields = Array.new
99
- @csvFormulaLines = Array.new
98
+ @csvFormulaFields = Set.new
99
+ @csvFormulaLines = Set.new
100
100
  #-- Counters setup --
101
101
  @twbCount = 0
102
102
  @dataSourcesCount = 0
@@ -153,7 +153,6 @@ DOTHEADER
153
153
 
154
154
  def loadMetrics
155
155
  @metrics = {
156
- '# of Workbooks' => @twbCount,
157
156
  '# of Data Sources' => @dataSourcesCount,
158
157
  '# of Calculated Fields' => @calculatedFieldsCount,
159
158
  '# of Referenced Fields' => @referencedFieldsCount,
@@ -166,7 +165,7 @@ DOTHEADER
166
165
 
167
166
  def emitGml
168
167
  gml = Twb::Util::GML.new
169
- gml.fileName = @twb.name
168
+ gml.fileName = "#{@twb.name}.calculatedFields"
170
169
  gml.nodes = @nodes
171
170
  gml.edges = @edges
172
171
  gmlFile = gml.render # resets gml.fileName in preparing it for output
@@ -182,6 +181,8 @@ DOTHEADER
182
181
  calculatedFields = SortedSet.new
183
182
  fieldFormulaLines = Array.new
184
183
  referencedFields = SortedSet.new
184
+ @csvCalculatedFields = Set.new
185
+
185
186
  # if @doGraph
186
187
  dataSourceNode = Twb::Util::Graphnode.new(name: ds.uiname, id: ds.id, type: ds, properties: {workbook: @twb.name})
187
188
  @nodes.add dataSourceNode
@@ -200,28 +201,32 @@ DOTHEADER
200
201
  calculation = calcField.calculation
201
202
  if calculation.has_formula
202
203
  #-- collect field formulas as single lines
203
- @csvCalculatedFields.push [
204
- @calculatedFieldsCount += 1,
205
- @twb.name,
206
- # @modTime,
207
- ds.uiname,
208
- ds.caption,
209
- ds.name,
210
- calcField.uiname,
211
- calcField.caption,
212
- calcField.name,
213
- ds.name + '::' + calcField.name,
214
- calcField.datatype,
215
- calcField.role,
216
- calcField.type,
217
- calculation.class,
218
- calculation.scopeIsolation,
219
- calculation.formulaFlat.length,
220
- calculation.formulaFlatResolved,
221
- calculation.formulaFlat,
222
- calculation.comments,
223
- calculation.is_lod
224
- ]
204
+ csvRec = [
205
+ @calculatedFieldsCount += 1,
206
+ @twb.name,
207
+ # @modTime,
208
+ ds.uiname,
209
+ ds.caption,
210
+ ds.name,
211
+ calcField.uiname,
212
+ calcField.caption,
213
+ calcField.name,
214
+ ds.name + '::' + calcField.name,
215
+ calcField.datatype,
216
+ calcField.role,
217
+ calcField.type,
218
+ calculation.class,
219
+ calculation.scopeIsolation,
220
+ calculation.formulaFlat.length,
221
+ calculation.formulaLinesCount,
222
+ calculation.formulaFlatResolved,
223
+ calculation.formulaFlat.strip,
224
+ calculation.comments,
225
+ calculation.is_lod
226
+ ]
227
+ # puts csvRec.to_s
228
+ # puts "incl? #{@csvCalculatedFields.include?(csvRec)}"
229
+ @csvCalculatedFields << csvRec
225
230
  #-- collect individual formula lines
226
231
  flnum = 0
227
232
  emit "@@ calcField.uiname: #{calcField.uiname}"
@@ -42,7 +42,7 @@ module Analysis
42
42
 
43
43
  def metrics
44
44
  {
45
- '# of Workbooks' => @twbCount,
45
+ # '# of Workbooks' => @twbCount,
46
46
  '# of Data Sources' => @dsCount,
47
47
  '# of Group Fields' => @gfCount,
48
48
  '# of Group Field Members' => @gfmCount
@@ -41,7 +41,7 @@ module Analysis
41
41
 
42
42
  def metrics
43
43
  {
44
- '# of Workbooks' => @twbcount,
44
+ # '# of Workbooks' => @twbcount,
45
45
  '# of data sources' => @dscnt,
46
46
  '# of Worksheet Fields' => @fieldsCnt
47
47
  }
@@ -49,6 +49,7 @@ module DataSources
49
49
  'Workbook',
50
50
  'Data Source',
51
51
  'Field',
52
+ 'Field - tech',
52
53
  'Field - source',
53
54
  'Field - class',
54
55
  'Field - path',
@@ -56,21 +57,31 @@ module DataSources
56
57
  'Property - Value'
57
58
  ]
58
59
 
59
- # @@techFileType = 'TwbDataSourceFieldsTech'
60
- # @@techFileName = @@techFileType + '.csv'
61
- # @@techHeader = ['Field #',
62
- # 'Workbook',
63
- # 'Workbook Dir',
64
- # 'Data Source',
65
- # 'Field',
66
- # 'Field Type',
67
- # 'Property - Name',
68
- # 'Property - Value'
69
- # ]
60
+ @@colsFileType = 'DataSourceFields'
61
+ @@colsFileName = @@colsFileType + '.csv'
62
+ @@colsHeader = [
63
+ 'Field #',
64
+ 'Workbook',
65
+ 'Data Source',
66
+ 'Field - tech',
67
+ 'Caption',
68
+ 'Field',
69
+ 'Alias',
70
+ 'Datatype',
71
+ 'Datatype-customized',
72
+ 'Default Format',
73
+ 'Param-domain-type',
74
+ 'Role',
75
+ 'Type',
76
+ 'Calculated?',
77
+ 'Value',
78
+ 'Hidden',
79
+ 'Path'
80
+ ]
70
81
 
71
82
  def initialize(**args)
83
+ emit "DataSourceFieldsAnalyzer initialize(**args) args: #{args}"
72
84
  @args = args
73
- # puts "@args: #{@args}"
74
85
  @recordDir = !@args.nil? && @args[:recordDir] == true
75
86
  @ttdocdir = @args[:ttdocdir]
76
87
  @csvAdd = args[:csvMode] == :add
@@ -78,36 +89,28 @@ module DataSources
78
89
  init
79
90
  @funcdoc = {:class=>self.class, :blurb=>'Analyze Data Source Fields', :description=>'Documents Data Source fields, with (some) technical information.',}
80
91
  #--
81
- docFileName = docFile(@@fullFileName)
82
- @csvFile = CSV.open( docFileName,@csvMode)
92
+ detailsFileName = docFile(@@fullFileName)
93
+ @csvFile = CSV.open( detailsFileName,@csvMode )
94
+ #--
95
+ colsFileName = docFile(@@colsFileName)
96
+ @colsFile = CSV.open( colsFileName, @csvMode )
97
+
98
+ #--
83
99
  unless @csvAdd
84
100
  if @recordDir
85
101
  @csvFile << @@fullHeader + ['Workbook Dir']
102
+ @colsFile << @@colsHeader + ['Workbook Dir']
86
103
  else
87
104
  @csvFile << @@fullHeader
105
+ @colsFile << @@colsHeader
88
106
  end
89
107
  end
90
- addDocFile @csvFile, docFileName, "Workbooks, Data Sources, and Fields."
108
+ addDocFile @csvFile, detailsFileName, "Workbooks, Data Sources, and Fields' details (technical use)."
109
+ addDocFile @colsFile, colsFileName, "Workbooks, Data Sources, and Column Fields."
91
110
  #--
92
- # --
93
111
  @dsCount = 0
94
112
  @recNum = 0
95
- end
96
-
97
- def initializeX
98
- # @csvFile = CSV.open(@@csvFileName,'w')
99
- # @csvFile << @@csvHeader
100
- # @csvRecords = Set.new
101
- # puts "Opened: #{!@csvFile.nil?} - #{@@csvFileName}"
102
- # --
103
- @csvFileFull = CSV.open(@@fullFileName,'w')
104
- @csvFileFull << @@fullHeader
105
- puts "Opened: #{!@csvFileFull.nil?} - #{@@fullFileName} "
106
- # --
107
- # @csvFileTech = CSV.open(@@techFileName,'w')
108
- # @csvFileTech << @@techHeader
109
- # puts "Opened: #{!@csvFileTech.nil?} - #{@@techFileName}"
110
- # --
113
+ @colFldNum = 0
111
114
  end
112
115
 
113
116
  def self.csvHeader
@@ -126,12 +129,15 @@ module DataSources
126
129
  @twb = nil
127
130
  @twb = twb if twb.instance_of? Twb::Workbook
128
131
  @twb = Twb::Workbook.new(twb) if twb.instance_of? String
132
+ @twbName = @twb.name
133
+ @twbDir = @twb.dir
129
134
  raise ArgumentError.new("ERROR in Workbok processing: '#{twb}' must be a Workbook (class) or the name of a Workbook (String), is a #{twb.class} \n ") unless @twb.is_a? Twb::Workbook
130
135
  # --
131
136
  dss = @twb.datasources
132
137
  @fieldCnt = 0
133
138
  dss.each do |ds|
134
139
  @dsname = ds.uiname
140
+ processColumnFields ds
135
141
  # puts "\n -- #{ds.uiname} "
136
142
  # tables = Set.new
137
143
  # fields = {}
@@ -178,6 +184,44 @@ module DataSources
178
184
  end
179
185
  end # def processTwb twb
180
186
 
187
+ def processColumnFields ds
188
+ deepFields = {}
189
+ recordedFields = {}
190
+ ds.columnFields.each do |field|
191
+ if field.pathbare.eql? '/workbook/datasources/datasource/column'
192
+ recordColField field
193
+ recordedFields[field.name] = field
194
+ # print '.'
195
+ else
196
+ deepFields[field.name] = field
197
+ # print '-'
198
+ end
199
+ end
200
+ deepFields.each do |name,field|
201
+ unless recordedFields.has_key? name
202
+ recordColField(field)
203
+ recordedFields[field.name] = field
204
+ # print ':'
205
+ end
206
+ end
207
+ end
208
+
209
+ # @@colsHeader = ['Field #',
210
+ # 'Workbook',
211
+ # 'Data Source',
212
+ # 'Field - tech',
213
+ # 'caption',
214
+ # 'uiname',
215
+ # 'alias',
216
+ # 'datatype',
217
+ # 'datatype-customized',
218
+ # 'default-format',
219
+ # 'param-domain-type',
220
+ # 'role',
221
+ # 'type',
222
+ # 'value'
223
+ # ]
224
+
181
225
  def metrics
182
226
  {
183
227
  '# of Data Sources' => @dsCount,
@@ -185,8 +229,47 @@ module DataSources
185
229
  }
186
230
  end
187
231
 
232
+
233
+
188
234
  private
189
235
 
236
+ # def recordCSV record
237
+ # numberedRec = [@recNum+=1] + record
238
+ # if @recordDir
239
+ # @csvFile << numberedRec.push(@twb.dir)
240
+ # else
241
+ # @csvFile << numberedRec
242
+ # end
243
+ # end
244
+
245
+ def recordColField field
246
+ numberedRec = [
247
+ @colFldNum +=1,
248
+ @twbName,
249
+ @dsname,
250
+ field.name,
251
+ field.caption,
252
+ field.uiname,
253
+ field.alias,
254
+ field.dataType,
255
+ field.datatypeCustomized,
256
+ field.defaultFormat,
257
+ field.paramDomainType,
258
+ field.role,
259
+ field.type,
260
+ !field.calcField.nil?,
261
+ field.value,
262
+ field.hidden,
263
+ field.pathbare
264
+ ]
265
+ #--
266
+ if @recordDir
267
+ @colsFile << numberedRec.push(@twb.dir)
268
+ else
269
+ @colsFile << numberedRec
270
+ end
271
+ end
272
+
190
273
  def recordFieldFull field, source
191
274
  # print field.properties.nil? ? '-' : ":#{field.properties.length}"
192
275
  # puts field.properties
@@ -198,13 +281,14 @@ module DataSources
198
281
  # @twb.dir,
199
282
  @dsname,
200
283
  field.uiname,
284
+ field.name,
201
285
  source,
202
286
  field.class,
203
287
  field.node.path.to_s.gsub(/[0-9]/,'').gsub('[]',''),
204
288
  name,
205
289
  value
206
290
  ]
207
- csvRec << @twb.dir if @recordDir
291
+ csvRec << @twb.dir if @recordDir
208
292
  @csvFile << csvRec
209
293
  end
210
294
  end
@@ -51,7 +51,7 @@ module Analysis
51
51
 
52
52
  def metrics
53
53
  {
54
- '# of Workbooks' => @twbcount,
54
+ # '# of Workbooks' => @twbcount,
55
55
  '# of Data Sources' => @dsCnt,
56
56
  }
57
57
  end
@@ -0,0 +1,103 @@
1
+ # WorksheetFields.rb Copyright (C) 2017, 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
+ module DataSources
22
+
23
+
24
+ class DataSourcesEnumerator
25
+
26
+ include TabTool
27
+
28
+ attr_accessor :localEmit
29
+
30
+ def initialize(**args)
31
+ @args = args
32
+ @recordDir = !@args.nil? && @args[:recordDir] == true
33
+ @ttdocdir = @args[:ttdocdir]
34
+ @csvAdd = args[:csvMode] == :add
35
+ @csvMode = @csvAdd ? 'a' : 'w'
36
+ init
37
+ @funcdoc = {:class=>self.class, :blurb=>"Enumerate Workbooks' Data Sources", :description=>'Documents Data Sources, recoring their names.',}
38
+ #--
39
+ docFileName = docFile('DataSources.csv')
40
+ @sheetFieldsCSV = CSV.open( docFileName,@csvMode)
41
+ unless @csvAdd
42
+ if @recordDir
43
+ @sheetFieldsCSV << ['Rec #','Workbook','Data Source','Data Source (tech)','Class','Extract?','# Connections','# Fields','Published?', '# Tables', '# Aliases', '# Groups', 'Workbook Dir']
44
+ else
45
+ @sheetFieldsCSV << ['Rec #','Workbook','Data Source','Data Source (tech)','Class','Extract?','# Connections','# Fields','Published?', '# Tables', '# Aliases', '# Groups']
46
+ end
47
+ end
48
+ addDocFile @sheetFieldsCSV, docFileName, "Workbooks and the Data Sources they contain."
49
+ #--
50
+ @dsCount = 0
51
+ @recNum = 0
52
+ end
53
+
54
+ def metrics
55
+ {
56
+ '# of Data Sources' => @dsCount,
57
+ }
58
+ end
59
+
60
+ def processTWB twb
61
+ @twb = twb
62
+ @twbName = @twb.name
63
+ @twbDir = @twb.dir
64
+ emit " -- #{@twbName}"
65
+ parseDataSources
66
+ end
67
+
68
+ def parseDataSources
69
+ @dataSources = @twb.datasources
70
+ @dataSources.each do |ds|
71
+ @dsCount += 1
72
+ recordCSV [ @twbName,
73
+ ds.uiname,
74
+ ds.name,
75
+ ds.dsclass,
76
+ ds.isExtract,
77
+ ds.connections.length,
78
+ ds.allFields.length,
79
+ ds.isPublished,
80
+ ds.tables.length,
81
+ ds.aliases.length,
82
+ ds.groups.length
83
+ ]
84
+ # [@twbName, @modTime, sheet.name, filter.type, filter.inexclude, filter.dataSource.uiname, filter.uiname, nil, nil, nil, filter.inexMode, filter.includeNull, filter.kind]
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def recordCSV record
91
+ numberedRec = [@recNum+=1] + record
92
+ if @recordDir
93
+ @sheetFieldsCSV << numberedRec.push(@twbDir)
94
+ else
95
+ @sheetFieldsCSV << numberedRec
96
+ end
97
+ end
98
+
99
+ end # class DataSourcesEnumeratorA
100
+
101
+ end # module DataSources
102
+ end # module Analysis
103
+ end # module Twb
@@ -41,7 +41,7 @@ module Analysis
41
41
 
42
42
  def metrics
43
43
  {
44
- '# of Workbooks' => @twbcount,
44
+ # '# of Workbooks' => @twbcount,
45
45
  '# of Worksheets' => @sheetCnt,
46
46
  '# of Worksheet Fields' => @fieldsCnt
47
47
  }
@@ -93,7 +93,7 @@ module Analysis
93
93
 
94
94
  def metrics
95
95
  {
96
- '# of Workbooks' => @twbcount,
96
+ # '# of Workbooks' => @twbcount,
97
97
  '# of Data Sources' => @dscount,
98
98
  '# of Google Docs' => @filecount,
99
99
  '# of Worksheets' => @sheetcount
@@ -38,9 +38,9 @@ module Analysis
38
38
  @dashSheetsCSV = CSV.open(docFileName,@csvMode)
39
39
  unless @csvAdd
40
40
  if @recordDir
41
- @dashSheetsCSV << ['Rec #','Workbook','Workbook Modified','Workbook Modified','Dashboard','Worksheet','Hidden','Visible', 'Workbook Dir']
41
+ @dashSheetsCSV << ['Rec #','Workbook','Dashboard','Worksheet','Hidden','Visible', 'Workbook Dir']
42
42
  else
43
- @dashSheetsCSV << ['Rec #','Workbook','Workbook Modified','Dashboard','Worksheet','Hidden','Visible' ]
43
+ @dashSheetsCSV << ['Rec #','Workbook','Dashboard','Worksheet','Hidden','Visible' ]
44
44
  end
45
45
  end
46
46
  addDocFile @dashSheetsCSV, docFileName, "Workbooks, Dashboards, and their Worksheets"
@@ -53,7 +53,7 @@ module Analysis
53
53
 
54
54
  def metrics
55
55
  {
56
- '# of Workbooks' => @twbCount,
56
+ # '# of Workbooks' => @twbCount,
57
57
  '# of Dashboards' => @dashCount,
58
58
  '# of Worksheets' => @sheetCount
59
59
  }
@@ -77,8 +77,9 @@ module Analysis
77
77
  @dashCount += 1
78
78
  dash.worksheets.each do |sheet|
79
79
  @sheetCount += 1
80
- emit "SHEET: #{sheet.name}"
81
- recordCSV [@twbName, @modTime, dash.name, sheet.name, sheet.hidden, sheet.visible ]
80
+ # puts "SHEET: #{sheet} -> #{sheet.name}"
81
+ recordCSV [@twbName, dash.name, sheet.name, sheet.hidden, sheet.visible ]
82
+ # recordCSV [@twbName, @modTime, dash.name, sheet.name, sheet.hidden, sheet.visible ]
82
83
  end
83
84
  end
84
85
  end
@@ -47,6 +47,7 @@ module Analysis
47
47
  @ttdocdir = @args[:ttdocdir]
48
48
  @csvAdd = args[:csvMode] == :add
49
49
  @csvMode = @csvAdd ? 'a' : 'w'
50
+ # @localEmit = true
50
51
  init
51
52
  @funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Fields', :description=>nil,}
52
53
  #--
@@ -69,7 +70,7 @@ module Analysis
69
70
 
70
71
  def metrics
71
72
  {
72
- '# of Workbooks' => @twbcount,
73
+ # '# of Workbooks' => @twbcount,
73
74
  '# of Worksheets' => @sheetCnt,
74
75
  '# of Worksheet Fields' => @fieldsCnt
75
76
  }
@@ -0,0 +1,114 @@
1
+ # sheetfieldsanalyzer.rb Copyright (C) 2019 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 SheetsInTooltipAnalyzer
23
+
24
+ include TabTool
25
+
26
+ def initialize(**args)
27
+ @args = args
28
+ @recordDir = !@args.nil? && @args[:recordDir] == true
29
+ @ttdocdir = @args[:ttdocdir]
30
+ @csvAdd = !@args.nil? && args[:csvMode] == :add
31
+ @csvMode = @csvAdd ? 'a' : 'w'
32
+ init
33
+ @funcdoc = {:class=>self.class, :blurb=>'Tooltip Vizzes', :description=>'Identifies the vizzes used in tooltips.',}
34
+ #--
35
+ docFileName = docFile('SheetsInTooltips.csv')
36
+ @csvFile = CSV.open(docFileName,@csvMode)
37
+ unless @csvAdd
38
+ if @recordDir
39
+ @csvFile << ['Rec #','Workbook','Worksheet - Host','Worksheet - Toolip viz','Max Width','Max Height', 'Workbook Dir']
40
+ else
41
+ @csvFile << ['Rec #','Workbook','Worksheet - Host','Worksheet - Toolip viz','Max Height','Max Width']
42
+ end
43
+ end
44
+ addDocFile @csvFile, docFileName, "Workbooks, Worksheets with Vizzes in their Tooltips"
45
+ #--
46
+ @twbCount = 0
47
+ @sheetCount = 0
48
+ @ttvizCount = 0
49
+ @recNum = 0
50
+ end
51
+
52
+ def metrics
53
+ {
54
+ # '# of Workbooks' => @twbCount,
55
+ '# of Worksheets' => @sheetCount,
56
+ '# of Worksheets in Tooltips' => @ttvizCount
57
+ }
58
+ end
59
+
60
+ def processTWB twb
61
+ @twb = twb
62
+ @twbName = @twb.name
63
+ @twbDir = @twb.dir
64
+ @modTime = @twb.modtime
65
+ emit " -- #{@twbName}"
66
+ @twbCount += 1
67
+ parseSheets
68
+ finis
69
+ end
70
+
71
+ def parseSheets
72
+ @sheets = @twb.worksheets
73
+ puts " #Sheets: #{@sheets.length}"
74
+ @sheetCount += @sheets.length
75
+ @sheets.each do |sheet|
76
+ puts "SHEET:: #{sheet.name}"
77
+ # @dashCount += 1
78
+ ttip = sheet.tooltip
79
+ runs = ttip.xpath('.//run')
80
+ runs.each do |run|
81
+ # puts run.text
82
+ text = run.text
83
+ isViz = text =~ /.*<Sheet[ ]+name=.*>.*/
84
+ puts "\t #{text}"
85
+ if isViz
86
+ vizCode = text.gsub(/^[^<]*/,'').gsub(/[^>]*$/,'')
87
+ vizNode = Nokogiri::XML(vizCode).at_xpath('./Sheet')
88
+ puts "\t #{vizCode}"
89
+ puts "\t #{vizNode.class} \t #{vizNode}"
90
+ recordCSV [@twbName, sheet.name, vizNode['name'], vizNode['maxwidth'], vizNode['maxheight']]
91
+ end
92
+
93
+ # @sheetCount += 1
94
+ # recordCSV [@twbName, dash.name, sheet.name, sheet.hidden, sheet.visible ]
95
+ end
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def recordCSV record
102
+ numberedRec = [@recNum+=1] + record
103
+ if @recordDir
104
+ @csvFile << numberedRec.push(@twbDir)
105
+ else
106
+ @csvFile << numberedRec
107
+ end
108
+ end
109
+
110
+
111
+ end #class SheetFieldsAnalyzer
112
+
113
+ end # module Analysis
114
+ end # module Twb
@@ -41,7 +41,7 @@ module Analysis
41
41
 
42
42
  def metrics
43
43
  {
44
- '# of Workbooks' => @twbcount,
44
+ # '# of Workbooks' => @twbcount,
45
45
  '# of Worksheets' => @sheetCnt,
46
46
  '# of Worksheet Fields' => @fieldsCnt
47
47
  }
@@ -54,7 +54,7 @@ module Analysis
54
54
 
55
55
  def metrics
56
56
  {
57
- '# of Workbooks' => @twbCount,
57
+ # '# of Workbooks' => @twbCount,
58
58
  '# of Data Sources' => @dsCount,
59
59
  '# of Dashboards' => @dashCount,
60
60
  '# of Worksheets' => @sheetCount
@@ -21,6 +21,16 @@ module Twb
21
21
 
22
22
  include Comparable
23
23
 
24
+ @@dataTypeRoleMap = {
25
+ 'date' => :dimension,
26
+ 'datetime' => :dimension,
27
+ 'boolean' => :dimension,
28
+ 'integer' => :measure,
29
+ 'float' => :measure,
30
+ 'real' => :measure,
31
+ 'string' => :dimension,
32
+ }
33
+
24
34
  # XML Attributes known to exist in TWB xml
25
35
  # ----------------------------------------
26
36
  # aggregation
@@ -48,15 +58,15 @@ module Twb
48
58
  # visual-totals
49
59
 
50
60
  attr_reader :node, :properties
51
- attr_reader :name, :caption, :uiname
61
+ attr_reader :name, :caption, :uiname, :alias
52
62
  attr_reader :dataType, :defaultFormat, :paramDomainType
53
63
  attr_reader :role, :type, :value
54
64
  attr_reader :alias, :semanticRole, :aggregation
55
65
  attr_reader :autoColumn, :hidden, :datatypeCustomized
56
66
  attr_reader :calcField
67
+ attr_reader :path
57
68
  attr_reader :aliases
58
69
 
59
-
60
70
  def initialize(fieldNode, datasource=nil)
61
71
  @datasource = datasource
62
72
  @node = fieldNode
@@ -67,16 +77,14 @@ module Twb
67
77
  @userDataType = load 'user-datatype'
68
78
  @defaultFormat = load 'default-format'
69
79
  @paramDomainType = load 'param-domain-type'
70
- @role = load 'role'
71
80
  @type = load 'type'
72
81
  @value = load 'value'
73
82
  @alias = load 'alias'
74
83
  @semanticRole = load 'semantic-role'
75
84
  @aggregation = load 'aggregation'
76
85
  @autoColumn = load 'auto-column'
77
- @hidden = load 'hidden'
78
86
  @datatypeCustomized = load 'datatype-customized'
79
- @calcField = loadCalcField
87
+ # @calcField = loadCalcField
80
88
  end
81
89
 
82
90
  def id
@@ -89,10 +97,26 @@ module Twb
89
97
  return val
90
98
  end
91
99
 
100
+ def role
101
+ @role ||= loadRole
102
+ end
103
+
104
+ def loadRole
105
+ role = @node['role']
106
+ if role.nil?
107
+ role = @@dataTypeRoleMap[@dataType].nil? ? @dataType : @@dataTypeRoleMap[@dataType]
108
+ end
109
+ return role
110
+ end
111
+
92
112
  def calcField
93
113
  @calcField ||= loadCalcField
94
114
  end
95
115
 
116
+ def hidden
117
+ @hidden ||= load('hidden').nil? ? false : true
118
+ end
119
+
96
120
  def loadCalcField
97
121
  if !@node.at_xpath('./calculation').nil?
98
122
  @calcField = Twb::CalculatedField.new @node, @datasource
@@ -101,6 +125,14 @@ module Twb
101
125
  end
102
126
  end
103
127
 
128
+ def path
129
+ @path ||= @node.path.gsub(/\[[0-9]+\]/,'[]')
130
+ end
131
+
132
+ def pathbare
133
+ @pathbare ||= path().gsub(/\[\]/,'')
134
+ end
135
+
104
136
  def comment
105
137
  @commentLines ||= loadComment
106
138
  end
@@ -69,7 +69,7 @@ module Twb
69
69
  @caption = @node.attr('caption')
70
70
  @uiname = @caption.nil? ? @name : @caption
71
71
  # puts "DATASOURCE: #{@uiname}"
72
- processConnection
72
+ # processConnection
73
73
  # processFilters
74
74
  loadTableFields
75
75
  loadFieldUINames
@@ -111,41 +111,44 @@ module Twb
111
111
  end
112
112
 
113
113
  def processConnections
114
- processConnection ds, './/connection'
115
- processConnection ds, './/named-connection'
114
+ @connections = Array.new
115
+ processConnection './/connection'
116
+ processConnection './/named-connection'
117
+ return @connections
116
118
  end
117
119
 
118
120
  def processConnection path
119
121
  conns = @node.xpath(path)
120
122
  conns.each do |connNode|
121
- connClass = @dsclass
122
- cpath = conn.path
123
- connPath = cpath.gsub(/\[[0-9]+\]/,'')
124
- connPNum = /(\d+)/.match(cpath)
125
- # puts cpath, connPath
126
- # puts "CPATH: #{cpath}"
127
- conn.attributes.each do |name,value|
128
- # puts "\n\t\t - %-15s -> %-s" % [name, value]
129
- $csvFile << [ $recCount += 1,
130
- $twbName, $dir, $build, $version,
131
- $dsName, $dstype, $dsuiname, connClass,
132
- connPath, connPNum,
133
- name, value.value
134
- ]
135
- end
123
+ @connections << connNode
124
+ # connClass = @dsclass
125
+ # cpath = connNode.path
126
+ # connPath = cpath.gsub(/\[[0-9]+\]/,'')
127
+ # connPNum = /(\d+)/.match(cpath)
128
+ # # puts cpath, connPath
129
+ # # puts "CPATH: #{cpath}"
130
+ # conn.attributes.each do |name,value|
131
+ # # puts "\n\t\t - %-15s -> %-s" % [name, value]
132
+ # $csvFile << [ $recCount += 1,
133
+ # $twbName, $dir, $build, $version,
134
+ # $dsName, $dstype, $dsuiname, connClass,
135
+ # connPath, connPNum,
136
+ # name, value.value
137
+ # ]
138
+ # end
136
139
  end
137
140
  end
138
141
 
139
- def processConnection
140
- @connection = @node.at_xpath('./connection')
141
- @dsclass = @name # handles 'Parameters' data source, which has no connection element (& others if so)
142
- unless @connection.nil?
143
- @dsclass = @connection.attribute('class').text
144
- # note: must use "dsclass" as "class" would override Rubys ".class" Kernel method
145
- setConnectionHash
146
- loadTables @connection
147
- end
148
- end
142
+ # def processConnection
143
+ # @connection = @node.at_xpath('./connection')
144
+ # @dsclass = @name # handles 'Parameters' data source, which has no connection element (& others if so)
145
+ # unless @connection.nil?
146
+ # @dsclass = @connection.attribute('class').text
147
+ # # note: must use "dsclass" as "class" would override Rubys ".class" Kernel method
148
+ # setConnectionHash
149
+ # loadTables @connection
150
+ # end
151
+ # end
149
152
 
150
153
  # Notes:
151
154
  # - TODO: need to determine which, if any, of the connection attributes should be
@@ -174,12 +177,19 @@ module Twb
174
177
  @isPublished = !node.at_xpath('./repository-location').nil?
175
178
  end
176
179
 
177
- def loadTables connection
180
+ def tables
181
+ @tables ||= loadTables
182
+ end
183
+
184
+ def loadTables
178
185
  @tables = {}
179
- nodes = connection.xpath(".//relation[@type='table']")
180
- nodes.each do |node|
181
- @tables[node.attr('name')] = node.attr('table')
186
+ connections.each do |conn|
187
+ nodes = conn.xpath(".//relation[@type='table']")
188
+ nodes.each do |node|
189
+ @tables[node.attr('name')] = node.attr('table')
190
+ end
182
191
  end
192
+ return @tables
183
193
  end
184
194
 
185
195
  def joinPairs
@@ -237,7 +247,7 @@ module Twb
237
247
  def loadColumnFields
238
248
  @columnFields = Set.new
239
249
  @columnFieldsMap = {}
240
- nodes = @node.xpath('./column')
250
+ nodes = @node.xpath('.//column')
241
251
  nodes.each do |n|
242
252
  field = Twb::ColumnField.new n, self
243
253
  @columnFields << field
@@ -467,7 +477,7 @@ module Twb
467
477
  def loadAllFields
468
478
  @allFields = SortedSet.new
469
479
  dbf = dbFields
470
- @allFields << dbf.keys
480
+ @allFields << dbf
471
481
  @allFields << calculatedFieldNames
472
482
  end
473
483
 
@@ -31,7 +31,7 @@ module Twb
31
31
  attr_reader :formulaResolved
32
32
  attr_reader :formulaFlat
33
33
  attr_reader :formulaFlatResolved
34
- attr_reader :formulaLines, :formulaResolvedLines
34
+ attr_reader :formulaLines, :formulaResolvedLines, :formulaLinesCount
35
35
  attr_reader :is_tableCalc
36
36
  attr_reader :is_lod, :lodCodePos
37
37
  attr_reader :class, :scopeIsolation
@@ -176,6 +176,10 @@ module Twb
176
176
  formulaResolved.split(/\n|\r\n/)
177
177
  end
178
178
 
179
+ def formulaLinesCount
180
+ @formulaLinesCount ||= formulaLines.length
181
+ end
182
+
179
183
  def enlineResolvedFormula
180
184
  end
181
185
 
@@ -194,7 +198,7 @@ module Twb
194
198
  # line.strip
195
199
  formula += ' ' + line.gsub(/\/\/.*/, '') # unless line =~ /^[ ]*\/\//
196
200
  end
197
- return formula # .strip
201
+ return formula.strip
198
202
  end
199
203
 
200
204
 
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: 4.6.3
4
+ version: 4.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-28 00:00:00.000000000 Z
11
+ date: 2019-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: creek
@@ -69,6 +69,7 @@ files:
69
69
  - lib/twb/analysis/datasources/datasourcefieldsanalyzer.rb
70
70
  - lib/twb/analysis/datasources/datasourcefieldscsvemitter.rb
71
71
  - lib/twb/analysis/datasources/datasourceoriginsanalyzer.rb
72
+ - lib/twb/analysis/datasources/datasourcesenumerator.rb
72
73
  - lib/twb/analysis/datasources/datasourceslocationsanalyzer.rb
73
74
  - lib/twb/analysis/datasources/datasourcetablefieldscsvemitter.rb
74
75
  - lib/twb/analysis/datasources/googlesheetdatasourcesanalyzer.rb
@@ -80,6 +81,7 @@ files:
80
81
  - lib/twb/analysis/sheets/sheetfieldsanalyzer.rb
81
82
  - lib/twb/analysis/sheets/sheetfiltersanalyzer.rb
82
83
  - lib/twb/analysis/sheets/sheetfiltersanalyzera.rb
84
+ - lib/twb/analysis/sheets/sheetsintooltipanalyzer.rb
83
85
  - lib/twb/analysis/sheets/sheetsourcesanalyzer.rb
84
86
  - lib/twb/analysis/sheets/worksheetdatastructurecsvemitter.rb
85
87
  - lib/twb/analysis/workbooksummaryanalyzer.rb