twb 4.9.4 → 4.9.9

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: 9bf5871fe93aaf4afc19f4c4b789d18db29545c43f77c6ae1d2c901dc23cd142
4
- data.tar.gz: e529613db65063341cde12d6393201765f3a53b680e4fbc7fe21707b9ff83681
3
+ metadata.gz: b285e90d1a99aa8de5a3613e00f03e634611643cac0ede6360a67a6f13f66f50
4
+ data.tar.gz: 32ef66741caea4210c0ca8959c001046a6884799a2bd544974fd155bc86fe625
5
5
  SHA512:
6
- metadata.gz: 7fb310fd663173d925df07488ec1f8d147651ca6588b725f03acaa99e88cfbcc07bb5aed2b797a8e70afd57143466a06ca0857bab0e4bdad99fda42423093652
7
- data.tar.gz: 460b6aee7fe9bf62baa9611a350dc3b7fe671ae18c03b8943431506a43bf0598247e92e784604cf35450bdc1f3dc09c04380ae43ff35c33344877885f16ca191
6
+ metadata.gz: 2ba95c4825210b53050e39cd172672456c46ff38e22dfabd0b1dcfe5d63a4e1ba0761295a92eedae92e744e34197c2a70625fdd36cddc284b874b66fe07bb18f
7
+ data.tar.gz: d78f2d12dd031a66ce686ad9bc2ca2cd5546d509ef049a7e129f58f7a0da00deddaa1860bba8946cf8ff7cbe5ef5d255d9b2dbda48a25acd77fd75f387803882
@@ -0,0 +1,311 @@
1
+
2
+ # Copyright (C) 2014, 2020 Chris Gerrard
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'nokogiri'
18
+ require 'zip'
19
+
20
+ module Flow
21
+
22
+
23
+ ##
24
+ # A Tableau Prep Flow file.
25
+ #
26
+ class Flow < TabClass
27
+
28
+ attr_reader :name, :dir, :type, :modtime
29
+ attr_reader :version, :build, :platform, :base
30
+ attr_reader :root
31
+ #--
32
+ attr_reader :datasources, :datasource
33
+ attr_reader :datasourceNames, :datasourceUINames, :dataSourceNamesMap
34
+ # attr_reader :orphanDataSources # i.e. not referenced in any Worksheet
35
+ #--
36
+ # attr_reader :dashboards, :storyboards, :worksheets
37
+ # attr_reader :parameters, :actions
38
+ # attr_reader :valid
39
+
40
+ ##
41
+ # Creates a Flow from its file name.
42
+ #
43
+ # == Parameters:
44
+ # flowWithDir
45
+ # The Flow's file name, the Flow can be a TWB or TWBX file.
46
+ #
47
+ def initialize tflWithDir
48
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must be a String, is a #{tflWithDir.class} \n ") unless tflWithDir.is_a? String
49
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must have an extension of .tfl or .tflx \n ") unless tflWithDir.upcase.end_with?(".TFL", ".TFLX")
50
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' must must be a file, is a Directory\\Folder \n ") if File.directory?(tflWithDir)
51
+ raise ArgumentError.new("ERROR in Flow creation: '#{tflWithDir}' cannot be found, must be a Tableau Flow file. \n ") unless File.file?(tflWithDir)
52
+ @valid = false
53
+ if File.file?(tflWithDir) then
54
+ @name = File.basename(tflWithDir)
55
+ @dir = File.dirname(File.expand_path(tflWithDir))
56
+ @modtime = File.new(tflWithDir).mtime.strftime("%Y-%m-%d %H:%M:%S")
57
+ case File.extname(tflWithDir).downcase
58
+ when '.tlf' then processTFL(tflWithDir)
59
+ when '.tflx' then processTFLX(flowWithDir)
60
+ end
61
+ end
62
+ end
63
+
64
+ def id
65
+ @id ||= @id = @name.hash
66
+ end
67
+
68
+ def build
69
+ @build ||= loadBuild
70
+ end
71
+
72
+ def release
73
+ @build ||= loadBuild
74
+ end
75
+
76
+ def worksheets
77
+ @worksheets.values
78
+ end
79
+
80
+ def worksheet name
81
+ @worksheets[name]
82
+ end
83
+
84
+ def worksheetNames
85
+ @worksheets.keys
86
+ end
87
+
88
+ def dashboards
89
+ @dashboards.values
90
+ end
91
+
92
+ def dashboardNames
93
+ @dashboards.keys
94
+ end
95
+
96
+ def dashboard name
97
+ @dashboards[name]
98
+ end
99
+
100
+ def actions
101
+ @actions.values
102
+ end
103
+
104
+ def actionNames
105
+ @actions.keys
106
+ end
107
+
108
+ def datasource name
109
+ @dataSourceNamesMap[name]
110
+ end
111
+
112
+ def parameters
113
+ @parameters ||= loadParameters
114
+ end
115
+
116
+ def orphanDataSources
117
+ @orphanDataSources ||= identifyOrphandatasoUrceS
118
+ end
119
+
120
+ def storyboards
121
+ @storyboards.values
122
+ end
123
+
124
+ def storyboardNames
125
+ @storyboards.keys
126
+ end
127
+
128
+ def storyboard name
129
+ @storyboards[name]
130
+ end
131
+
132
+ private
133
+
134
+ def processTFLX(twbxWithDir)
135
+ Zip::File.open(twbxWithDir) do |zip_file|
136
+ twb = zip_file.glob('*.twb').first
137
+ @ndoc = Nokogiri::XML(twb.get_input_stream)
138
+ @type = :twbx
139
+ processDoc
140
+ end
141
+ end
142
+
143
+ def processTFL(twbFile)
144
+ @ndoc = Nokogiri::XML(open(twbFile))
145
+ @type = :twb
146
+ processDoc
147
+ end
148
+
149
+ def processDoc
150
+ @valid = true
151
+ end
152
+
153
+ def loadBuild
154
+ # - earlier Version, need to confirm when source-build began
155
+ # @build = @ndoc.xpath('/flow/comment()').text.gsub(/^[^0-9]+/,'').strip
156
+ @build = if !@ndoc.at_xpath('/flow/@source-build').nil?
157
+ @ndoc.at_xpath('/flow/@source-build').text
158
+ else
159
+ if @ndoc.at_xpath('/flow/comment()').nil?
160
+ 'not found'
161
+ else
162
+ @ndoc.at_xpath('/flow/comment()').text.gsub(/^[^0-9]+/,'').strip
163
+ end
164
+ end
165
+ end
166
+
167
+ def loaddatasources
168
+ # puts "LOAD DATA SOURCES"
169
+ # @dataSourcesNode = @ndoc.at_xpath('//flow/datasources')
170
+ @datasources = Set.new
171
+ @datasourceNames = SortedSet.new
172
+ @datasourceUINames = SortedSet.new
173
+ @dataSourceNamesMap = {}
174
+ datasourceNodes = @ndoc.xpath('//flow/datasources/datasource')
175
+ # puts "DATASOURCENODES : #{@datasourceNodes.length}"
176
+ datasourceNodes.each do |node|
177
+ datasource = Twb::DataSource.new(node,self)
178
+ @datasources << datasource
179
+ @datasourceNames << datasource.name
180
+ @datasourceNames << datasource.uiname
181
+ @datasourceUINames << datasource.uiname
182
+ @dataSourceNamesMap[datasource.name] = datasource
183
+ @dataSourceNamesMap[datasource.uiname] = datasource
184
+ end
185
+ # puts "DATASOURCES : #{@datasources.length}"
186
+ end
187
+
188
+ def loadWorksheets
189
+ @worksheets = {}
190
+ hiddenSheets = []
191
+ @ndoc.xpath('//flow/windows/window[@hidden="true"]').each do |hs|
192
+ hiddenSheets << hs['name']
193
+ end
194
+ sheets = @ndoc.xpath('//flow/worksheets/worksheet' ).to_a
195
+ sheets.each do |node|
196
+ sheet = Twb::Worksheet.new(node, self)
197
+ sheet.hidden = hiddenSheets.include? sheet.name
198
+ @worksheets[sheet.name] = sheet
199
+ end
200
+ end
201
+
202
+ def loadDashboards
203
+ @dashesNode = @ndoc.at_xpath('//flow/dashboards')
204
+ @dashboards = {}
205
+ dashes = @ndoc.xpath('//flow/dashboards/dashboard').to_a
206
+ dashes.each do |node|
207
+ unless node.attr('type') == 'storyboard' then
208
+ dashboard = Twb::Dashboard.new(node, @worksheets)
209
+ @dashboards[dashboard.name] = dashboard
210
+ end
211
+ end
212
+ end
213
+
214
+ def loadStoryboards
215
+ @storyboards = {}
216
+ boards = @ndoc.xpath("//flow/dashboards/dashboard[@type='storyboard']" ).to_a
217
+ boards.each do |node|
218
+ sheet = Twb::Storyboard.new(node)
219
+ @storyboards[sheet.name] = sheet
220
+ end
221
+ end
222
+
223
+ def loadWindows
224
+ @windowsnode = @ndoc.at_xpath("//flow/windows")
225
+ @windows = {}
226
+ windows = @ndoc.xpath("//flow/windows/window[@name]")
227
+ windows.each do |node|
228
+ window = Twb::Window.new(node)
229
+ @windows[window.name] = window
230
+ end
231
+ end
232
+
233
+ def loadActions
234
+ @actions = {}
235
+ actionNodes = @ndoc.xpath("//flow/actions/action")
236
+ actionNodes.each do |anode|
237
+ action = Twb::Action.new(anode, @flownode)
238
+ @actions[action.uiname] = action
239
+ end
240
+ end
241
+
242
+ def identifyOrphandatasoUrceS
243
+ sheetDataSources = Set.new
244
+ @worksheets.values.each do |sheet|
245
+ sheet.datasources.each do |ds|
246
+ sheetDataSources << ds.uiname
247
+ end
248
+ end
249
+ @orphanDataSources = @datasourceUINames - sheetDataSources
250
+ end
251
+
252
+ def writeTwb(name=@name)
253
+ $f = File.open(name,'w')
254
+ if $f
255
+ $f.puts @ndoc
256
+ $f.close
257
+ end
258
+ return name
259
+ end
260
+
261
+ def writeTwbx(name=@name)
262
+ emit "Writing the Workbook, need implementation"
263
+ end
264
+
265
+ # Make sure that the TWB has a <dashboards> node.
266
+ # It's possible for a TWB to have no dashboards, and therefore no <dashboards> node.
267
+ def ensureDashboardsNodeExists
268
+ if @dashesNode.nil?
269
+ @dashesNode = Nokogiri::XML::Node.new "dashboards", @ndoc
270
+ # TODO fix this @dataSourcesNode.add_next_sibling(@dashesNode)
271
+ end
272
+ end
273
+
274
+ def ensureWindowsNodeExists
275
+ if @windowsnode.nil?
276
+ @windowsnode = Nokogiri::XML::Node.new "windows", @ndoc
277
+ # TODO fix this @dataSourcesNode.add_next_sibling(@windowsnode)
278
+ end
279
+ end
280
+
281
+ def getNewDashboardTitle(t)
282
+ title = t
283
+ if @datasources.include?(title)
284
+ inc = 0
285
+ loop do
286
+ inc+=1
287
+ title = t + ' ' + inc.to_s
288
+ if !@datasources.include?(title)
289
+ break
290
+ end
291
+ end
292
+ end
293
+ return title
294
+ end
295
+
296
+ def loadParameters
297
+ @parameters = {}
298
+ paramsDS = ndoc.at_xpath('./flow/datasources/datasource[@name="Parameters"]')
299
+ unless paramsDS.nil?
300
+ paramNodes = paramsDS.xpath('.//column')
301
+ paramNodes.each do |pn|
302
+ parameter = Twb::Parameter.new pn
303
+ @parameters[parameter.name] = parameter
304
+ end
305
+ end
306
+ return @parameters
307
+ end
308
+
309
+ end # class Flow
310
+
311
+ end # module Twb
data/lib/twb.rb CHANGED
@@ -73,12 +73,12 @@ require_relative 'twb/analysis/sheets/worksheetsummarizer'
73
73
  require_relative 'twb/analysis/sheets/worksheetdatastructurecsvemitter'
74
74
  require_relative 'twb/analysis/sheets/sheetfiltersanalyzer'
75
75
  require_relative 'twb/analysis/sheets/sheetfieldsanalyzer'
76
+ require_relative 'twb/analysis/sheets/dashboardsummarizer'
76
77
  require_relative 'twb/analysis/sheets/dashsheetsanalyzer'
77
78
  require_relative 'twb/analysis/sheets/sheetsintooltipanalyzer'
78
79
 
79
-
80
80
  # Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
81
81
  #
82
82
  module Twb
83
- VERSION = '4.9.4'
83
+ VERSION = '4.9.9'
84
84
  end
@@ -298,8 +298,8 @@ DOTHEADER
298
298
  @referencedFields.merge referencedFields
299
299
  @twbRootFields.merge dsRootFields
300
300
  if @doGraph
301
- cypher @twb.name
302
- cypherPy @twb.name
301
+ # cypher @twb.name
302
+ # cypherPy @twb.name
303
303
  end
304
304
  emit "#######################"
305
305
  #--
@@ -71,7 +71,7 @@ module DataSources
71
71
  fileDir = File.dirname fqFileName
72
72
  modtime = File.mtime fqFileName
73
73
  size = File.size fqFileName
74
- data = [$recNum+=1, twbName, twb.dir, ds.uiname, fileName, fileDir, modtime, size]
74
+ data = [@recNum+=1, twbName, twb.dir, ds.uiname, fileName, fileDir, modtime, size]
75
75
  @csvFile << data
76
76
  end
77
77
  end
@@ -0,0 +1,94 @@
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 DashboardsSummarizer
23
+
24
+ include TabTool
25
+
26
+ attr_accessor :localEmit
27
+
28
+ def initialize(**args)
29
+ @args = args
30
+ @recordDir = !@args.nil? && @args[:recordDir] == true
31
+ @ttdocdir = @args[:ttdocdir]
32
+ @csvAdd = !@args.nil? && args[:csvMode] == :add
33
+ @csvMode = @csvAdd ? 'a' : 'w'
34
+ init
35
+ @funcdoc = {:class=>self.class, :blurb=>'Analyze Dashboard Worksheets', :description=>'Identifies the Worksheets present in Dashboards.',}
36
+ #--
37
+ docFileName = docFile('DashboardSummaries.csv')
38
+ @dashboardsCSV = CSV.open(docFileName,@csvMode)
39
+ unless @csvAdd
40
+ if @recordDir
41
+ @dashboardsCSV << ['Rec #','Workbook','Dashboard','# Worksheets','Workbook Dir']
42
+ else
43
+ @dashboardsCSV << ['Rec #','Workbook','Dashboard','# Worksheets' ]
44
+ end
45
+ end
46
+ addDocFile @dashboardsCSV, docFileName, "Workbooks and their Dashboards' summaries"
47
+ #--
48
+ @twbCount = 0
49
+ @dashCount = 0
50
+ @recNum = 0
51
+ end
52
+
53
+ def metrics
54
+ {
55
+ # '# of Workbooks' => @twbCount,
56
+ '# of Dashboards' => @dashCount,
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
+ parseDashes
68
+ finis
69
+ end
70
+
71
+ def parseDashes
72
+ @dashboards = @twb.dashboards
73
+ @dashboards.each do |dash|
74
+ emit "DASH:: #{dash.name}"
75
+ @dashCount += 1
76
+ recordCSV [@twbName, dash.name, dash.worksheets.length]
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def recordCSV record
83
+ numberedRec = [@recNum+=1] + record
84
+ if @recordDir
85
+ @dashboardsCSV << numberedRec.push(@twbDir)
86
+ else
87
+ @dashboardsCSV << numberedRec
88
+ end
89
+ end
90
+
91
+ end #class SheetFieldsAnalyzer
92
+
93
+ end # module Analysis
94
+ end # module Twb
@@ -37,7 +37,7 @@ module Analysis
37
37
  docFileName = docFile('WorkbookSummary.csv')
38
38
  @csvFile = CSV.open(docFileName,@csvMode)
39
39
  unless @csvAdd
40
- csvHeader = ['Rec #', 'Workbook','Type','Version','Build','Platform','Modified','# Data Sources','# Dashboards','# Worksheets']
40
+ csvHeader = ['Rec #', 'Workbook','Directory','Type','Version','Build','Platform','Modified','# Data Sources','# Dashboards','# Worksheets']
41
41
  if @recordDir
42
42
  csvHeader.push('Workbook Directory')
43
43
  end
@@ -65,6 +65,7 @@ module Analysis
65
65
  @twb = twb
66
66
  emit " -- #{@twbName}"
67
67
  recordCSV [ @twb.name,
68
+ @twb.dir,
68
69
  @twb.type,
69
70
  @twb.version,
70
71
  @twb.build,
@@ -48,7 +48,7 @@ module Util
48
48
  end
49
49
 
50
50
  def renderNodes
51
- puts "Cypher def renderNodes @nodes:#{@nodes}"
51
+ puts "Cypher def renderNodes @nodes:#{@nodes.to_s}"
52
52
  csv = CSV.open(docFile("#{@fileName}.nodes.csv"),'w')
53
53
  csv << ['Type','Name','UUID']
54
54
  nodesCSV = Set.new
@@ -77,7 +77,7 @@ GMLHEADER
77
77
 
78
78
  def renderNodes file
79
79
  nodes = Set.new
80
- puts 'def renderNodes'
80
+ # puts 'def renderNodes'
81
81
  @nodes.each do |node|
82
82
  gmlID = Digest::MD5.hexdigest(node.id)
83
83
  gmlName = node.name.gsub('&','&amp;').gsub('"','&quot;')
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.9.4
4
+ version: 4.9.9
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-12-09 00:00:00.000000000 Z
11
+ date: 2020-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: creek
@@ -58,6 +58,7 @@ extensions: []
58
58
  extra_rdoc_files: []
59
59
  files:
60
60
  - lib/t.rb
61
+ - lib/tfl/Flow.rb
61
62
  - lib/twb.rb
62
63
  - lib/twb/action.rb
63
64
  - lib/twb/analysis/annotatedfieldscsvemitter.rb
@@ -82,6 +83,7 @@ files:
82
83
  - lib/twb/analysis/documentedfieldscsvemitter.rb
83
84
  - lib/twb/analysis/documentedfieldsmarkdownemitter.rb
84
85
  - lib/twb/analysis/sheets/analyzedashboardsheets.rb
86
+ - lib/twb/analysis/sheets/dashboardsummarizer.rb
85
87
  - lib/twb/analysis/sheets/dashsheetsanalyzer.rb
86
88
  - lib/twb/analysis/sheets/sheetfieldsanalyzer.rb
87
89
  - lib/twb/analysis/sheets/sheetfiltersanalyzer.rb