twb 4.7.1 → 4.9.0
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 +8 -2
- data/lib/twb/analysis/calculatedfields/fieldsaliasesanalyzer.rb +110 -0
- data/lib/twb/analysis/datasources/datasourcefilesanalyzer.rb +83 -0
- data/lib/twb/analysis/datasources/datasourcetablefieldsanalyzer.rb +117 -0
- data/lib/twb/analysis/datasources/extractsanalyzer.rb +199 -0
- data/lib/twb/analysis/datasources/fieldsaliasesanalyzer.rb +117 -0
- data/lib/twb/analysis/sheets/sheetsintooltipanalyzer.rb +5 -5
- data/lib/twb/analysis/sheets/worksheetsummarizer.rb +118 -0
- data/lib/twb/columnfield.rb +22 -2
- data/lib/twb/datasource.rb +7 -1
- data/lib/twb/tabtool.rb +1 -1
- data/lib/twb/util/atomizecsvrecords.rb +105 -0
- data/lib/twb/util/csvrecordsatomizer.rb +114 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39d006e0c059121c7c53795a7b2c7b90c425a3809bb0287b215f5950ac4187b8
|
4
|
+
data.tar.gz: a49a8f7fb9cbf9a206def1cdc1faf649455dea27d180c88d64e518ae1da3b4e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f2983b81057ba13bfa029b4103fac22728f0fe34a7e41346373019161d7f6dc9857a54f67f071ae23f531e6a2a140448bc3c8e9ed95577b0c35ec4bd2e560d8
|
7
|
+
data.tar.gz: 9397a53a76c078a36dbfffa170c4a8f91b85a76d5c288e20c38e5a84ea9a3f78d9e7e01488f85d1c917dc6ce4f371671066367550723bd13ba79afa7f98b2b1c
|
data/lib/twb.rb
CHANGED
@@ -37,6 +37,7 @@ require_relative 'twb/quickfilter'
|
|
37
37
|
# require_relative 'twb/docdashboardimagevert'
|
38
38
|
# require_relative 'twb/docdashboardwebvert'
|
39
39
|
require_relative 'twb/util/twbdashsheetdatadotbuilder'
|
40
|
+
require_relative 'twb/util/csvrecordsatomizer'
|
40
41
|
require_relative 'twb/util/dotfilerenderer'
|
41
42
|
# require_relative 'twb/util/htmllistcollapsible'
|
42
43
|
require_relative 'twb/util/xraydashboards'
|
@@ -59,11 +60,16 @@ require_relative 'twb/analysis/calculatedfields/csvemitter'
|
|
59
60
|
# require_relative 'twb/analysis/datasources/datasourcefieldscsvemitter'
|
60
61
|
require_relative 'twb/analysis/datasources/datasourcesenumerator.rb'
|
61
62
|
require_relative 'twb/analysis/datasources/datasourcefieldsanalyzer'
|
62
|
-
require_relative 'twb/analysis/datasources/
|
63
|
+
require_relative 'twb/analysis/datasources/datasourcefilesanalyzer'
|
64
|
+
# require_relative 'twb/analysis/datasources/datasourcetablefieldscsvemitter'
|
65
|
+
# require_relative 'twb/analysis/datasources/datasourcetablefieldsanalyzer'
|
63
66
|
require_relative 'twb/analysis/datasources/categoricalcolorcodinganalyzer'
|
64
67
|
require_relative 'twb/analysis/datasources/googlesheetdatasourcesanalyzer'
|
65
68
|
require_relative 'twb/analysis/datasources/parametersanalyzer'
|
66
69
|
require_relative 'twb/analysis/datasources/datasourceoriginsanalyzer'
|
70
|
+
require_relative 'twb/analysis/datasources/fieldsaliasesanalyzer'
|
71
|
+
require_relative 'twb/analysis/datasources/extractsanalyzer'
|
72
|
+
require_relative 'twb/analysis/sheets/worksheetsummarizer'
|
67
73
|
require_relative 'twb/analysis/sheets/worksheetdatastructurecsvemitter'
|
68
74
|
require_relative 'twb/analysis/sheets/sheetfiltersanalyzer'
|
69
75
|
require_relative 'twb/analysis/sheets/sheetfieldsanalyzer'
|
@@ -74,5 +80,5 @@ require_relative 'twb/analysis/sheets/sheetsintooltipanalyzer'
|
|
74
80
|
# Represents Tableau Workbooks, their contents, and classes that analyze and manipulate them.
|
75
81
|
#
|
76
82
|
module Twb
|
77
|
-
VERSION = '4.
|
83
|
+
VERSION = '4.9.0'
|
78
84
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# fieldsaliasesanalyzer.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 'csv'
|
17
|
+
|
18
|
+
module Twb
|
19
|
+
module Analysis
|
20
|
+
|
21
|
+
class FieldsAliasesAnalyzer
|
22
|
+
|
23
|
+
include TabTool
|
24
|
+
|
25
|
+
attr_reader :calculatedFieldsCount, :referencedFieldsCount, :metrics
|
26
|
+
|
27
|
+
@@csvFileName = 'FieldAliases.csv'
|
28
|
+
@@csvFileHeader = [
|
29
|
+
'Record #',
|
30
|
+
"Record Number",
|
31
|
+
"Workbook",
|
32
|
+
"Data Source",
|
33
|
+
'Data Source Caption',
|
34
|
+
'Data Source (tech)',
|
35
|
+
'Field',
|
36
|
+
'Field Caption',
|
37
|
+
'Field Name (tech)',
|
38
|
+
'Data Type',
|
39
|
+
'Role',
|
40
|
+
'Type',
|
41
|
+
'Field Value',
|
42
|
+
'Field Alias'
|
43
|
+
]
|
44
|
+
|
45
|
+
|
46
|
+
def initialize(**args)
|
47
|
+
emit "initialize FieldsAliasesAnalyzer args #{args}"
|
48
|
+
@args = args
|
49
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
50
|
+
@ttdocdir = @args[:ttdocdir]
|
51
|
+
@csvAdd = @args[:csvMode] == :add
|
52
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
53
|
+
init
|
54
|
+
@funcdoc = {:class=>self.class, :blurb=>"Analyze Fields' Aliases", :description=>'Understanding the aliases for field values can be important and useful.',}
|
55
|
+
#-- CSV records collectors
|
56
|
+
# @csvFormulaFields = Set.new
|
57
|
+
# @csvFormulaLines = Set.new
|
58
|
+
#-- Counters setup --
|
59
|
+
# @twbCount = 0
|
60
|
+
@dataSourcesCount = 0
|
61
|
+
@aliasedFieldsCount = 0
|
62
|
+
@aliasessCount = 0
|
63
|
+
#--
|
64
|
+
# @referencedFields = SortedSet.new
|
65
|
+
#--
|
66
|
+
twbdirLabel = @recordDir.nil? ? nil : 'Workbook Dir'
|
67
|
+
@csvFile = initCSV(@@calcFieldsCSVFileName, 'Calculated fields and their formulas.', @@csvFileHeader )
|
68
|
+
#--
|
69
|
+
@localEmit = false
|
70
|
+
# @imageFiles = Array.new
|
71
|
+
#--
|
72
|
+
# @doGraph = config(:dograph)
|
73
|
+
end
|
74
|
+
|
75
|
+
def processTWB twb
|
76
|
+
twb.datasources.each do |ds|
|
77
|
+
processDS ds
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def processDS ds
|
82
|
+
@dsUIName = ds.uiname
|
83
|
+
@dsCaption = ds.caption
|
84
|
+
@dsName = ds.name
|
85
|
+
#--
|
86
|
+
aliasesNodes = ds.node.xpath('.//aliases')
|
87
|
+
aliasesNodes.each do |an|
|
88
|
+
processAliases an
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def processAliases aliasesNode
|
93
|
+
#-- Field --
|
94
|
+
caption = d.xpath('../../@caption').text
|
95
|
+
techName = d.xpath('../../@name').text
|
96
|
+
name = if caption == '' then getName(techName) else caption end
|
97
|
+
dataType = d.xpath('../../@datatype').text
|
98
|
+
role = d.xpath('../../@role').text
|
99
|
+
type = d.xpath('../../@type').text
|
100
|
+
|
101
|
+
#-- Alias --
|
102
|
+
aliasKey = d.xpath('./@key').text
|
103
|
+
aliasValue = d.xpath('./@value').text
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
end # class FieldsAliasesAnalyzer
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# datasourcefilesanalyzer.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 'csv'
|
17
|
+
|
18
|
+
module Twb
|
19
|
+
module Analysis
|
20
|
+
module DataSources
|
21
|
+
|
22
|
+
class DataSourceFilesAnalyzer
|
23
|
+
|
24
|
+
include TabTool
|
25
|
+
|
26
|
+
attr_reader :filesCount
|
27
|
+
|
28
|
+
@@csvFileName = 'DataSourceFiles.csv'
|
29
|
+
@@csvFileHeader = [ 'Record #',
|
30
|
+
'Workbook',
|
31
|
+
'Workbook Dir',
|
32
|
+
'Data Source',
|
33
|
+
'File Name',
|
34
|
+
'File Dir',
|
35
|
+
'File Modified',
|
36
|
+
'File Size'
|
37
|
+
]
|
38
|
+
|
39
|
+
def initialize(**args)
|
40
|
+
emit "initialize DataSourceFilesAnalyzer args #{args}"
|
41
|
+
@args = args
|
42
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
43
|
+
@ttdocdir = @args[:ttdocdir]
|
44
|
+
@csvAdd = @args[:csvMode] == :add
|
45
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
46
|
+
init
|
47
|
+
@funcdoc = {:class=>self.class, :blurb=>"Analyze Data Sources' Files", :description=>'Identifying the files accessed by Data Sources.',}
|
48
|
+
@dataSourcesCount = 0
|
49
|
+
@recNum = 0
|
50
|
+
#--
|
51
|
+
@csvFile = initCSV(@@csvFileName, 'Data Sources and the Files they access.', @@csvFileHeader )
|
52
|
+
#--
|
53
|
+
@localEmit = false
|
54
|
+
end
|
55
|
+
|
56
|
+
def processTWB twb
|
57
|
+
@twbName = twb.name
|
58
|
+
@twDir = twb.dir
|
59
|
+
twb.datasources.each do |ds|
|
60
|
+
processFiles ds
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def processFiles ds
|
65
|
+
dirFiles = Hash.new { |d,fs| d[fs] = Set.new }
|
66
|
+
ds.node.xpath('.//connection[@filename]').each do |fnode|
|
67
|
+
twbFileDir = fnode['directory']
|
68
|
+
twbFileName = fnode['filename']
|
69
|
+
fqFileName = twbFileDir.nil? ? twbFileName : twbFileDir + '/' + twbFileName
|
70
|
+
fileName = File.basename fqFileName
|
71
|
+
fileDir = File.dirname fqFileName
|
72
|
+
modtime = File.mtime fqFileName
|
73
|
+
size = File.size fqFileName
|
74
|
+
data = [$recNum+=1, twbName, twb.dir, ds.uiname, fileName, fileDir, modtime, size]
|
75
|
+
@csvFile << data
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class DataSourceFilesAnalyzer
|
80
|
+
|
81
|
+
end # module DataSources
|
82
|
+
end # module Analysis
|
83
|
+
end # module Twb
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# datasourcetablefieldsanalyzer.rb - this Ruby script Copyright 2019 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
|
+
module DataSources
|
21
|
+
|
22
|
+
class require_relative DataSourceTableFieldsAnalyzer
|
23
|
+
|
24
|
+
attr_reader :csvFileName, :csvRecords
|
25
|
+
attr_reader :dsCount, :tablesCount, :fieldsCount
|
26
|
+
|
27
|
+
@@csvFileName = 'DataSourceTableFields.csv'
|
28
|
+
@csvFileDescription = 'Contains CSV records, each containing the details for an individual Field contained in a table in the Data Source. Data Sources are identified within their host Workbook. '
|
29
|
+
|
30
|
+
@@csvHeader = ['Record #',
|
31
|
+
'Workbook',
|
32
|
+
'Workbook Dir',
|
33
|
+
'Data Source',
|
34
|
+
'Data Source (tech)',
|
35
|
+
'Table',
|
36
|
+
'Field',
|
37
|
+
'Field (code)',
|
38
|
+
'Field (table)',
|
39
|
+
]
|
40
|
+
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@csvFile = CSV.open(@@csvFileName, 'w')
|
44
|
+
@csvFile << @@csvHeader
|
45
|
+
@outputs = Set.new
|
46
|
+
@outputs << @@csvFileName
|
47
|
+
@dsCount = 0
|
48
|
+
@tablesCount = 0
|
49
|
+
@fieldsCount = 0
|
50
|
+
@csvRecords = Set.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def doc
|
54
|
+
{
|
55
|
+
:filedoc => [
|
56
|
+
{ :file => @@csvFileName,
|
57
|
+
:description => @csvFileDescription,
|
58
|
+
:header => @@csvHeader
|
59
|
+
}
|
60
|
+
],
|
61
|
+
:outputs => @outputs
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.csvHeader
|
66
|
+
@@csvHeader
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.csvFileType
|
70
|
+
@@csvFileName
|
71
|
+
end
|
72
|
+
|
73
|
+
def outputs
|
74
|
+
@outputs
|
75
|
+
end
|
76
|
+
|
77
|
+
def processTwb twb
|
78
|
+
@recNum = 0
|
79
|
+
@twb = twb if twb.instance_of? Twb::Workbook
|
80
|
+
@twb = Twb::Workbook.new(twb) if twb.instance_of? String
|
81
|
+
# --
|
82
|
+
dss = @twb.datasources
|
83
|
+
dss.each do |ds|
|
84
|
+
tables = Set.new
|
85
|
+
@dsCount += 1
|
86
|
+
ds.node.xpath('./connection/cols/map').each do |cnode|
|
87
|
+
# puts cnode
|
88
|
+
key = cnode.attribute('key').text
|
89
|
+
codename = key.gsub(/^\[|\]$/,'')
|
90
|
+
fielduiname = ds.fieldUIName(codename)
|
91
|
+
value = cnode.attribute('value').text.gsub(/^\[|\]$/,'')
|
92
|
+
parts = value.split('].[')
|
93
|
+
# puts "%-30s %-45s %s \n " % [fielduiname, value, parts]
|
94
|
+
csvRecord = [ @fieldsCount += 1,
|
95
|
+
@twb.name,
|
96
|
+
@twb.dir,
|
97
|
+
ds.uiname,
|
98
|
+
ds.name,
|
99
|
+
parts[0],
|
100
|
+
fielduiname,
|
101
|
+
codename,
|
102
|
+
parts[1]
|
103
|
+
]
|
104
|
+
tables.add parts[0]
|
105
|
+
@csvRecords.add csvRecord
|
106
|
+
@csvFile << csvRecord
|
107
|
+
end
|
108
|
+
@tablesCount += tables.length
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end # class CSVEmitter
|
113
|
+
|
114
|
+
|
115
|
+
end # module DataSources
|
116
|
+
end # module Analysis
|
117
|
+
end # module Twb
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# worksheetsummarizer.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
|
+
module DataSources
|
22
|
+
|
23
|
+
class ExtractsAnalyzer
|
24
|
+
|
25
|
+
include TabTool
|
26
|
+
|
27
|
+
attr_accessor :localEmit
|
28
|
+
|
29
|
+
def initialize(**args)
|
30
|
+
@args = args
|
31
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
32
|
+
@ttdocdir = @args[:ttdocdir]
|
33
|
+
@csvAdd = !@args.nil? && args[:csvMode] == :add
|
34
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
35
|
+
init
|
36
|
+
@funcdoc = {:class=>self.class, :blurb=>'Analyze Extracts', :description=>'Identifies Data Source Extracts & records relevant data.',}
|
37
|
+
#--
|
38
|
+
docFileName = docFile('Extracts.csv')
|
39
|
+
@extractsCSV = CSV.open(docFileName,@csvMode)
|
40
|
+
#--
|
41
|
+
# <extract count='-1' enabled='true' units='records'>
|
42
|
+
# <connection access_mode='readonly'
|
43
|
+
# authentication='auth-none'
|
44
|
+
# author-locale='en_US'
|
45
|
+
# class='hyper'
|
46
|
+
# dbname='C:/tech/Tableau/Tableau Tools/Ruby/gems/twb/lib/twb/analysis/datasources/data/Sample - World Bank Indicators (Excel).hyper'
|
47
|
+
# default-settings='yes'
|
48
|
+
# schema='Extract'
|
49
|
+
# sslmode=''
|
50
|
+
# update-time='05/17/2019 10:39:21 PM'
|
51
|
+
# username='tableau_internal_user'>
|
52
|
+
# <relation name='Extract' table='[Extract].[Extract]' type='table' />
|
53
|
+
# <refresh>
|
54
|
+
# <refresh-event add-from-file-path='Sample - World Bank Indicators (Excel)' increment-value='%null%' refresh-type='create' rows-inserted='2354' timestamp-start='2019-05-17 22:39:21.474' />
|
55
|
+
# </refresh>
|
56
|
+
# </connection>
|
57
|
+
# </extract>
|
58
|
+
#--
|
59
|
+
unless @csvAdd
|
60
|
+
@csvHeader = [ 'Rec #',
|
61
|
+
'Workbook',
|
62
|
+
'Data Source',
|
63
|
+
'Enabled',
|
64
|
+
'Units',
|
65
|
+
'Access Mode',
|
66
|
+
'Authentication',
|
67
|
+
'Class',
|
68
|
+
'Extract Name (FQ)',
|
69
|
+
'Extract Name',
|
70
|
+
'Extract Directory',
|
71
|
+
'Default Settings',
|
72
|
+
'Schema',
|
73
|
+
'SSL Mode',
|
74
|
+
'Updated (UTC)',
|
75
|
+
'User Name'
|
76
|
+
]
|
77
|
+
if @recordDir
|
78
|
+
@csvHeader.push 'Workbook Dir'
|
79
|
+
end
|
80
|
+
@extractsCSV << @csvHeader
|
81
|
+
end
|
82
|
+
addDocFile @extractsCSV, docFileName, "Workbooks and their Data Source Extracts."
|
83
|
+
#--
|
84
|
+
@twbCount = 0
|
85
|
+
@dsCount = 0
|
86
|
+
@extractCount = 0
|
87
|
+
@recNum = 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def metrics
|
91
|
+
{
|
92
|
+
'# of Data Sources' => @dsCount,
|
93
|
+
'# of Extracts' => @extractCount
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def processTWB twb
|
98
|
+
@twb = twb
|
99
|
+
@twbName = @twb.name
|
100
|
+
@twbDir = @twb.dir
|
101
|
+
emit " -- #{@twbName}"
|
102
|
+
@twbCount += 1
|
103
|
+
parseDataSources
|
104
|
+
finis
|
105
|
+
end
|
106
|
+
|
107
|
+
def parseDataSources
|
108
|
+
@dataSources = @twb.datasources
|
109
|
+
@dataSources.each do |ds|
|
110
|
+
@dsCount += 1
|
111
|
+
emit "DATA SOURCE:: #{ds.name}"
|
112
|
+
dsNode = ds.node
|
113
|
+
exnode = ds.node.at_xpath('./extract')
|
114
|
+
unless exnode.nil?
|
115
|
+
cnNode = exnode.at_xpath('./connection')
|
116
|
+
# emit true, cnNode
|
117
|
+
unless cnNode.nil?
|
118
|
+
@extractCount += 1
|
119
|
+
dbName = cnNode['dbname']
|
120
|
+
# emit true, "cnNode['dbname'] :: #{cnNode['dbname']}"
|
121
|
+
# unless dbName.nil?
|
122
|
+
exName = File.basename dbName
|
123
|
+
exDir = File.dirname dbName
|
124
|
+
# end
|
125
|
+
recordCSV [ @twbName,
|
126
|
+
ds.uiname,
|
127
|
+
exnode['enabled'],
|
128
|
+
exnode['units'],
|
129
|
+
cnNode['access_mode'],
|
130
|
+
cnNode['authentication'],
|
131
|
+
cnNode['class'],
|
132
|
+
dbName,
|
133
|
+
exName,
|
134
|
+
exDir,
|
135
|
+
cnNode['default-settings'],
|
136
|
+
cnNode['schema'],
|
137
|
+
cnNode['sslmode'],
|
138
|
+
cnNode['update-time'],
|
139
|
+
cnNode['username']
|
140
|
+
]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# <extract count='-1' enabled='true' units='records'>
|
147
|
+
# <connection access_mode='readonly'
|
148
|
+
# authentication='auth-none'
|
149
|
+
# author-locale='en_US'
|
150
|
+
# class='hyper'
|
151
|
+
# dbname='C:/tech/Tableau/Tableau Tools/Ruby/gems/twb/lib/twb/analysis/datasources/data/Sample - World Bank Indicators (Excel).hyper'
|
152
|
+
# default-settings='yes'
|
153
|
+
# schema='Extract'
|
154
|
+
# sslmode=''
|
155
|
+
# update-time='05/17/2019 10:39:21 PM'
|
156
|
+
# username='tableau_internal_user'>
|
157
|
+
# <relation name='Extract' table='[Extract].[Extract]' type='table' />
|
158
|
+
# <refresh>
|
159
|
+
# <refresh-event add-from-file-path='Sample - World Bank Indicators (Excel)' increment-value='%null%' refresh-type='create' rows-inserted='2354' timestamp-start='2019-05-17 22:39:21.474' />
|
160
|
+
# </refresh>
|
161
|
+
# </connection>
|
162
|
+
# </extract>
|
163
|
+
#--
|
164
|
+
# unless @csvAdd
|
165
|
+
# @csvHeader = [ 'Rec #',
|
166
|
+
# 'Workbook',
|
167
|
+
# 'Data Source',
|
168
|
+
# 'Enabled',
|
169
|
+
# 'Units',
|
170
|
+
# 'Access Mode',
|
171
|
+
# 'Authentication',
|
172
|
+
# 'Class',
|
173
|
+
# 'Db Name',
|
174
|
+
# 'Default Settings',
|
175
|
+
# 'Schema',
|
176
|
+
# 'SSL Mode',
|
177
|
+
# 'Updated',
|
178
|
+
# 'User Name'
|
179
|
+
# ]
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def recordCSV record
|
187
|
+
numberedRec = [@recNum+=1] + record
|
188
|
+
if @recordDir
|
189
|
+
@extractsCSV << numberedRec.push(@twbDir)
|
190
|
+
else
|
191
|
+
@extractsCSV << numberedRec
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end # class ExtractsAnalyzer
|
196
|
+
|
197
|
+
end # module DataSources
|
198
|
+
end # module Analysis
|
199
|
+
end # module Twb
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# fieldsaliasesanalyzer.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 'csv'
|
17
|
+
|
18
|
+
module Twb
|
19
|
+
module Analysis
|
20
|
+
module DataSources
|
21
|
+
|
22
|
+
class FieldsAliasesAnalyzer
|
23
|
+
|
24
|
+
include TabTool
|
25
|
+
|
26
|
+
attr_reader :calculatedFieldsCount, :referencedFieldsCount, :metrics
|
27
|
+
|
28
|
+
@@csvFileName = 'FieldAliases.csv'
|
29
|
+
@@csvFileHeader = [
|
30
|
+
'Record #',
|
31
|
+
"Workbook",
|
32
|
+
"Data Source",
|
33
|
+
'Field',
|
34
|
+
'Value - Db',
|
35
|
+
'Value - Alias'
|
36
|
+
]
|
37
|
+
|
38
|
+
|
39
|
+
def initialize(**args)
|
40
|
+
emit "initialize FieldsAliasesAnalyzer args #{args}"
|
41
|
+
@args = args
|
42
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
43
|
+
@ttdocdir = @args[:ttdocdir]
|
44
|
+
@csvAdd = @args[:csvMode] == :add
|
45
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
46
|
+
init
|
47
|
+
@funcdoc = {:class=>self.class, :blurb=>"Analyze Fields' Aliases", :description=>'Understanding the aliases for field values can be important and useful.',}
|
48
|
+
#-- CSV records collectors
|
49
|
+
# @csvFormulaFields = Set.new
|
50
|
+
# @csvFormulaLines = Set.new
|
51
|
+
#-- Counters setup --
|
52
|
+
# @twbCount = 0
|
53
|
+
@dataSourcesCount = 0
|
54
|
+
@aliasedFieldsCount = 0
|
55
|
+
@aliasessCount = 0
|
56
|
+
@recNum = 0
|
57
|
+
#--
|
58
|
+
# @referencedFields = SortedSet.new
|
59
|
+
#--
|
60
|
+
@csvFile = initCSV(@@csvFileName, 'Fields and their aliased values.', @@csvFileHeader )
|
61
|
+
#--
|
62
|
+
@localEmit = false
|
63
|
+
# @imageFiles = Array.new
|
64
|
+
#--
|
65
|
+
# @doGraph = config(:dograph)
|
66
|
+
end
|
67
|
+
|
68
|
+
def processTWB twb
|
69
|
+
@twbName = twb.name
|
70
|
+
@twDir = twb.dir
|
71
|
+
twb.datasources.each do |ds|
|
72
|
+
processDS ds
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def processDS ds
|
77
|
+
@dsUIName = ds.uiname
|
78
|
+
@dsCaption = ds.caption
|
79
|
+
@dsName = ds.name
|
80
|
+
#--
|
81
|
+
ds.columnFields.each do |fld|
|
82
|
+
if fld.hasaliases
|
83
|
+
@fieldName = fld.name
|
84
|
+
@fieldCaption = fld.caption
|
85
|
+
@fieldUIName = fld.uiname
|
86
|
+
processAliases(fld)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def processAliases field
|
92
|
+
aliasNodes = field.node.xpath('./aliases//alias')
|
93
|
+
aliasNodes.each do |anode|
|
94
|
+
key = anode['key']
|
95
|
+
value = anode['value']
|
96
|
+
numberedRec = [
|
97
|
+
@recNum +=1,
|
98
|
+
@twbName,
|
99
|
+
@dsUIName,
|
100
|
+
@fieldName,
|
101
|
+
anode['key'].to_s.gsub(/^["]+/,'').gsub(/["]+$/,''),
|
102
|
+
anode['value']
|
103
|
+
]
|
104
|
+
#--
|
105
|
+
if @recordDir
|
106
|
+
@csvFile << numberedRec.push(@twbDir)
|
107
|
+
else
|
108
|
+
@csvFile << numberedRec
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end # class FieldsAliasesAnalyzer
|
114
|
+
|
115
|
+
end # module DataSources
|
116
|
+
end # module Analysis
|
117
|
+
end # module Twb
|
@@ -70,10 +70,10 @@ module Analysis
|
|
70
70
|
|
71
71
|
def parseSheets
|
72
72
|
@sheets = @twb.worksheets
|
73
|
-
puts " #Sheets: #{@sheets.length}"
|
73
|
+
# puts " #Sheets: #{@sheets.length}"
|
74
74
|
@sheetCount += @sheets.length
|
75
75
|
@sheets.each do |sheet|
|
76
|
-
puts "SHEET:: #{sheet.name}"
|
76
|
+
# puts "SHEET:: #{sheet.name}"
|
77
77
|
# @dashCount += 1
|
78
78
|
ttip = sheet.tooltip
|
79
79
|
runs = ttip.xpath('.//run')
|
@@ -81,12 +81,12 @@ module Analysis
|
|
81
81
|
# puts run.text
|
82
82
|
text = run.text
|
83
83
|
isViz = text =~ /.*<Sheet[ ]+name=.*>.*/
|
84
|
-
puts "\t #{text}"
|
84
|
+
# puts "\t #{text}"
|
85
85
|
if isViz
|
86
86
|
vizCode = text.gsub(/^[^<]*/,'').gsub(/[^>]*$/,'')
|
87
87
|
vizNode = Nokogiri::XML(vizCode).at_xpath('./Sheet')
|
88
|
-
puts "\t #{vizCode}"
|
89
|
-
puts "\t #{vizNode.class} \t #{vizNode}"
|
88
|
+
# puts "\t #{vizCode}"
|
89
|
+
# puts "\t #{vizNode.class} \t #{vizNode}"
|
90
90
|
recordCSV [@twbName, sheet.name, vizNode['name'], vizNode['maxwidth'], vizNode['maxheight']]
|
91
91
|
end
|
92
92
|
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# worksheetsummarizer.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 WorksheetSummarizer
|
23
|
+
|
24
|
+
include TabTool
|
25
|
+
|
26
|
+
attr_accessor :localEmit
|
27
|
+
|
28
|
+
# Worksheet attributes; from Worksheet.rb
|
29
|
+
# attr_reader :node, :name, :datasourcenames, :datasources
|
30
|
+
# attr_reader :panesCount
|
31
|
+
# attr_reader :fields, :rowFields, :colFields, :paneFields, :datasourceFields, :pageFields, :encodedFields, :slicesFields
|
32
|
+
# attr_reader :filters
|
33
|
+
# attr_reader :tooltip
|
34
|
+
# attr_accessor :hidden, :visible
|
35
|
+
|
36
|
+
def initialize(**args)
|
37
|
+
@args = args
|
38
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
39
|
+
@ttdocdir = @args[:ttdocdir]
|
40
|
+
@csvAdd = !@args.nil? && args[:csvMode] == :add
|
41
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
42
|
+
init
|
43
|
+
@funcdoc = {:class=>self.class, :blurb=>'Summarize Worksheets', :description=>'Identifies Worksheets & summarizes them.',}
|
44
|
+
#--
|
45
|
+
docFileName = docFile('WorkheetSummaries.csv')
|
46
|
+
@worksheetsCSV = CSV.open(docFileName,@csvMode)
|
47
|
+
unless @csvAdd
|
48
|
+
@csvHeader = [ 'Rec #',
|
49
|
+
'Workbook',
|
50
|
+
'Worksheet',
|
51
|
+
'Hidden', 'Visible',
|
52
|
+
'# Data Sources',
|
53
|
+
'# Fields - Data', '# Fields - Rows', '# Fields - Cols',
|
54
|
+
'Tooltip?', 'Filters?'
|
55
|
+
]
|
56
|
+
if @recordDir
|
57
|
+
@csvHeader.push 'Workbook Dir'
|
58
|
+
end
|
59
|
+
@worksheetsCSV << @csvHeader
|
60
|
+
end
|
61
|
+
addDocFile @worksheetsCSV, docFileName, "Workbooks and their Worksheets' summaries."
|
62
|
+
#--
|
63
|
+
@twbCount = 0
|
64
|
+
@sheetCount = 0
|
65
|
+
@recNum = 0
|
66
|
+
end
|
67
|
+
|
68
|
+
def metrics
|
69
|
+
{
|
70
|
+
'# of Worksheets' => @sheetCount
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def processTWB twb
|
75
|
+
@twb = twb
|
76
|
+
@twbName = @twb.name
|
77
|
+
@twbDir = @twb.dir
|
78
|
+
@modTime = @twb.modtime
|
79
|
+
emit " -- #{@twbName}"
|
80
|
+
@twbCount += 1
|
81
|
+
parseSheets
|
82
|
+
finis
|
83
|
+
end
|
84
|
+
|
85
|
+
def parseSheets
|
86
|
+
@worksheets = @twb.worksheets
|
87
|
+
@worksheets.each do |sheet|
|
88
|
+
emit "SHEET:: #{sheet.name}"
|
89
|
+
@sheetCount += 1
|
90
|
+
recordCSV [ @twbName,
|
91
|
+
sheet.name,
|
92
|
+
sheet.hidden,
|
93
|
+
sheet.visible,
|
94
|
+
sheet.datasources.length,
|
95
|
+
sheet.datasourceFields.length,
|
96
|
+
sheet.rowFields.length,
|
97
|
+
sheet.colFields.length,
|
98
|
+
!sheet.tooltip.nil?,
|
99
|
+
!sheet.filters.nil?,
|
100
|
+
]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def recordCSV record
|
107
|
+
numberedRec = [@recNum+=1] + record
|
108
|
+
if @recordDir
|
109
|
+
@worksheetsCSV << numberedRec.push(@twbDir)
|
110
|
+
else
|
111
|
+
@worksheetsCSV << numberedRec
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end #class WorksheetSummarizer
|
116
|
+
|
117
|
+
end # module Analysis
|
118
|
+
end # module Twb
|
data/lib/twb/columnfield.rb
CHANGED
@@ -58,7 +58,8 @@ module Twb
|
|
58
58
|
# visual-totals
|
59
59
|
|
60
60
|
attr_reader :node, :properties
|
61
|
-
attr_reader :name, :caption, :uiname
|
61
|
+
attr_reader :name, :caption, :uiname
|
62
|
+
attr_reader :hasaliases, :alias
|
62
63
|
attr_reader :dataType, :defaultFormat, :paramDomainType
|
63
64
|
attr_reader :role, :type, :value
|
64
65
|
attr_reader :alias, :semanticRole, :aggregation
|
@@ -109,7 +110,7 @@ module Twb
|
|
109
110
|
return role
|
110
111
|
end
|
111
112
|
|
112
|
-
def
|
113
|
+
def calcField
|
113
114
|
@calcField ||= loadCalcField
|
114
115
|
end
|
115
116
|
|
@@ -137,6 +138,25 @@ module Twb
|
|
137
138
|
@commentLines ||= loadComment
|
138
139
|
end
|
139
140
|
|
141
|
+
def hasaliases
|
142
|
+
@hasaliases ||= !@node.at_xpath('./aliases').nil?
|
143
|
+
end
|
144
|
+
|
145
|
+
def aliases
|
146
|
+
@aliases ||= loadAliases
|
147
|
+
end
|
148
|
+
|
149
|
+
def loadAliases
|
150
|
+
@aliases = {}
|
151
|
+
if hasaliases
|
152
|
+
@node.at_xpath('./aliases//alias').each do |an|
|
153
|
+
dbvalue = an['key'].to_s.gsub(/^["]+/,'').gsub(/["]+$/,'')
|
154
|
+
@aliases[ dbvalue ] = an['value']
|
155
|
+
end
|
156
|
+
end
|
157
|
+
return @aliases
|
158
|
+
end
|
159
|
+
|
140
160
|
# COMMENTED FIELDS
|
141
161
|
# --------------------------------------
|
142
162
|
# <column caption='Calculation1' datatype='real' name='[Calculation_821344020759588865]' role='measure' type='quantitative'>
|
data/lib/twb/datasource.rb
CHANGED
@@ -235,8 +235,14 @@ module Twb
|
|
235
235
|
'Parameters'.eql? @name
|
236
236
|
end
|
237
237
|
|
238
|
+
def columnField fieldName
|
239
|
+
loadColumnFields if @columnFieldsMap.nil?
|
240
|
+
@columnFieldsMap[ fieldName ]
|
241
|
+
end
|
242
|
+
|
243
|
+
|
238
244
|
def columnFields
|
239
|
-
@columnFields ||=
|
245
|
+
@columnFields ||= loadColumnFields
|
240
246
|
end
|
241
247
|
|
242
248
|
def columnFieldsMap
|
data/lib/twb/tabtool.rb
CHANGED
@@ -0,0 +1,105 @@
|
|
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 Util
|
23
|
+
|
24
|
+
class AtomizeCSVRecords
|
25
|
+
|
26
|
+
include TabTool
|
27
|
+
# include Graph
|
28
|
+
|
29
|
+
attr_reader :metrics
|
30
|
+
attr_accessor :ttdocdir
|
31
|
+
|
32
|
+
@@ttlogfile = 'AtomizeCSVRecords.ttlog'
|
33
|
+
@@csvFileName = 'AtomizedCSVRecords.csv'
|
34
|
+
|
35
|
+
def initialize(**args)
|
36
|
+
@ttdocdir = @args[:ttdocdir]
|
37
|
+
@csvAdd = @args[:csvMode] == :add
|
38
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
39
|
+
init
|
40
|
+
@funcdoc = {:class=>self.class, :blurb=>'Analyze Calculated Fields', :description=>'Calculated fields can be complex, this tool provides robust coverage.',}
|
41
|
+
# --
|
42
|
+
@executed = false
|
43
|
+
end
|
44
|
+
|
45
|
+
def loadFields fileName
|
46
|
+
fields = Set.new
|
47
|
+
file = File.open(fileName)
|
48
|
+
unless file.nil?
|
49
|
+
file.each_line { |line|
|
50
|
+
fields.add line.chomp
|
51
|
+
}
|
52
|
+
end
|
53
|
+
return fields
|
54
|
+
end
|
55
|
+
|
56
|
+
def processTWB workbook
|
57
|
+
puts "\n\t ALERT: Utility tool: #{self.class} - does not implement Workbook processing"
|
58
|
+
puts "\t - deferring to single execution"
|
59
|
+
processData fileName
|
60
|
+
end
|
61
|
+
|
62
|
+
def processData fileName
|
63
|
+
unless @executed
|
64
|
+
emit true, "initialize AtomizeCSVRecords args #{args}"
|
65
|
+
@atomicCSV = CSV.open(@@csvFileName, 'w')
|
66
|
+
# --
|
67
|
+
inputFileName = fileName.nil? ? 'csvData.csv' : fileName
|
68
|
+
keyFields = loadFields 'key.fields'
|
69
|
+
excludeFields = loadFields 'exclude.fields'
|
70
|
+
puts "\t Using these key fields: #{$keyFields.inspect}"
|
71
|
+
puts "\t Excluding these fields: #{$excludeFields.inspect}"
|
72
|
+
|
73
|
+
$fieldValsCSV = '.csv'
|
74
|
+
$atomicCSV = CSV.open($fieldValsCSV, 'w')
|
75
|
+
$atomicFields = $keyFields.to_a + [ 'Rec #', 'Field', 'Value' ]
|
76
|
+
puts "\n\t CSV output fields: #{$atomicFields.inspect}"
|
77
|
+
$atomicCSV << $atomicFields
|
78
|
+
|
79
|
+
|
80
|
+
$recCnt, $fldsCnt = 0, 0
|
81
|
+
|
82
|
+
$recNum = 0
|
83
|
+
|
84
|
+
@executed = true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def metrics
|
89
|
+
@metrics ||= loadMetrics
|
90
|
+
end
|
91
|
+
|
92
|
+
def loadMetrics
|
93
|
+
@metrics = {
|
94
|
+
'# of Data Sources' => @dataSourcesCount,
|
95
|
+
'# of Calculated Fields' => @calculatedFieldsCount,
|
96
|
+
'# of Referenced Fields' => @referencedFieldsCount,
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
#-- private methods begin here, to end of class
|
101
|
+
|
102
|
+
end # class
|
103
|
+
|
104
|
+
end # module Analysis
|
105
|
+
end # module Twb
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# CSVRecordsAtomizer.rb - this Ruby script Copyright 2019 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 'csv'
|
17
|
+
|
18
|
+
module Twb
|
19
|
+
module Util
|
20
|
+
|
21
|
+
class CSVRecordsAtomizer
|
22
|
+
|
23
|
+
include TabTool
|
24
|
+
|
25
|
+
attr_reader :metrics
|
26
|
+
attr_accessor :ttdocdir
|
27
|
+
|
28
|
+
@@ttlogfile = 'AtomizeCSVRecords.ttlog'
|
29
|
+
@@csvFileName = 'AtomizedCSVRecords.csv'
|
30
|
+
@@atomFields = ['Record #', 'Field Name', 'Field Value']
|
31
|
+
|
32
|
+
def initialize(**args)
|
33
|
+
@args = args
|
34
|
+
@ttdocdir = @args[:ttdocdir]
|
35
|
+
@csvAdd = @args[:csvMode] == :add
|
36
|
+
@csvMode = @csvAdd ? 'a' : 'w'
|
37
|
+
init
|
38
|
+
@funcdoc = {:class=>self.class, :blurb=>'Analyze Calculated Fields', :description=>'Calculated fields can be complex, this tool provides robust coverage.'}
|
39
|
+
# --
|
40
|
+
@executed = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def processFile fileName
|
44
|
+
emit true, "#{self.class} - processFile: #{fileName} :: #{fileName.class}"
|
45
|
+
# --
|
46
|
+
srcFields = Set.new CSV.open(fileName, 'r:bom|utf-8', &:readline)
|
47
|
+
emit true, "\t Inspecting these #{srcFields.length} #{srcFields.class} fields: "
|
48
|
+
keyFields = loadFields(fileName, :keyfields)
|
49
|
+
excludeFields = loadFields(fileName, :excludefields)
|
50
|
+
recordFields = (srcFields - keyFields - excludeFields).to_a
|
51
|
+
emit true, "\t Using these key fields: #{keyFields.inspect}"
|
52
|
+
emit true, "\t Excluding these fields: #{excludeFields.inspect}"
|
53
|
+
emit true, "\t Recording these fields: #{recordFields.inspect}"
|
54
|
+
# --
|
55
|
+
atomizedFields = keyFields.to_a + @@atomFields
|
56
|
+
dataBaseName = File.basename(fileName, ".*")
|
57
|
+
atomizedCSVFile = "#{dataBaseName}.Atomized.csv"
|
58
|
+
atomizedCSVFile = CSV.open(atomizedCSVFile,'w')
|
59
|
+
atomizedCSVFile << keyFields.to_a + @@atomFields
|
60
|
+
# --
|
61
|
+
@recNum = 0
|
62
|
+
CSV.open(fileName, 'r:bom|utf-8', headers: true) do |csv|
|
63
|
+
csv.each do |row|
|
64
|
+
@recNum += 1
|
65
|
+
atomRec = []
|
66
|
+
keyFields.each do |kf|
|
67
|
+
atomRec << row.fetch(kf)
|
68
|
+
end
|
69
|
+
atomRec << @recNum
|
70
|
+
recordFields.each do |rf|
|
71
|
+
atomizedCSVFile << atomRec + [rf, row.fetch(rf)]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def loadFields fileName, type
|
80
|
+
puts "\n\n\t loadFields -#{fileName}- -#{type}-"
|
81
|
+
fields = Set.new
|
82
|
+
auxFile = "#{fileName}.#{type}"
|
83
|
+
isAuxFile = File.exist?(auxFile)
|
84
|
+
emit true, "\t\t Loading auxilary data: %-12s %7s %-s" % [type, isAuxFile, auxFile]
|
85
|
+
if isAuxFile
|
86
|
+
# file = File.open(fileName)
|
87
|
+
File.open(auxFile).each_line { |line|
|
88
|
+
fields.add line.chomp
|
89
|
+
}
|
90
|
+
end
|
91
|
+
return fields.to_a
|
92
|
+
end
|
93
|
+
|
94
|
+
def processData fileName
|
95
|
+
end
|
96
|
+
|
97
|
+
def metrics
|
98
|
+
@metrics ||= loadMetrics
|
99
|
+
end
|
100
|
+
|
101
|
+
def loadMetrics
|
102
|
+
@metrics = {
|
103
|
+
'# of Data Sources' => @dataSourcesCount,
|
104
|
+
'# of Calculated Fields' => @calculatedFieldsCount,
|
105
|
+
'# of Referenced Fields' => @referencedFieldsCount,
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
#-- private methods begin here, to end of class
|
110
|
+
|
111
|
+
end # class
|
112
|
+
|
113
|
+
end # module Analysis
|
114
|
+
end # module Twb
|
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.
|
4
|
+
version: 4.9.0
|
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-
|
11
|
+
date: 2019-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: creek
|
@@ -63,15 +63,20 @@ files:
|
|
63
63
|
- lib/twb/analysis/annotatedfieldscsvemitter.rb
|
64
64
|
- lib/twb/analysis/calculatedfields/calculatedfieldsanalyzer.rb
|
65
65
|
- lib/twb/analysis/calculatedfields/csvemitter.rb
|
66
|
+
- lib/twb/analysis/calculatedfields/fieldsaliasesanalyzer.rb
|
66
67
|
- lib/twb/analysis/calculatedfields/groupfieldsanalyzer.rb
|
67
68
|
- lib/twb/analysis/calculatedfields/markdownemitter.rb
|
68
69
|
- lib/twb/analysis/datasources/categoricalcolorcodinganalyzer.rb
|
69
70
|
- lib/twb/analysis/datasources/datasourcefieldsanalyzer.rb
|
70
71
|
- lib/twb/analysis/datasources/datasourcefieldscsvemitter.rb
|
72
|
+
- lib/twb/analysis/datasources/datasourcefilesanalyzer.rb
|
71
73
|
- lib/twb/analysis/datasources/datasourceoriginsanalyzer.rb
|
72
74
|
- lib/twb/analysis/datasources/datasourcesenumerator.rb
|
73
75
|
- lib/twb/analysis/datasources/datasourceslocationsanalyzer.rb
|
76
|
+
- lib/twb/analysis/datasources/datasourcetablefieldsanalyzer.rb
|
74
77
|
- lib/twb/analysis/datasources/datasourcetablefieldscsvemitter.rb
|
78
|
+
- lib/twb/analysis/datasources/extractsanalyzer.rb
|
79
|
+
- lib/twb/analysis/datasources/fieldsaliasesanalyzer.rb
|
75
80
|
- lib/twb/analysis/datasources/googlesheetdatasourcesanalyzer.rb
|
76
81
|
- lib/twb/analysis/datasources/parametersanalyzer.rb
|
77
82
|
- lib/twb/analysis/documentedfieldscsvemitter.rb
|
@@ -84,6 +89,7 @@ files:
|
|
84
89
|
- lib/twb/analysis/sheets/sheetsintooltipanalyzer.rb
|
85
90
|
- lib/twb/analysis/sheets/sheetsourcesanalyzer.rb
|
86
91
|
- lib/twb/analysis/sheets/worksheetdatastructurecsvemitter.rb
|
92
|
+
- lib/twb/analysis/sheets/worksheetsummarizer.rb
|
87
93
|
- lib/twb/analysis/workbooksummaryanalyzer.rb
|
88
94
|
- lib/twb/calculatedfield.rb
|
89
95
|
- lib/twb/codedfield.rb
|
@@ -118,6 +124,8 @@ files:
|
|
118
124
|
- lib/twb/there.rb
|
119
125
|
- lib/twb/twbcodedfield.rb
|
120
126
|
- lib/twb/twbtest.rb
|
127
|
+
- lib/twb/util/atomizecsvrecords.rb
|
128
|
+
- lib/twb/util/csvrecordsatomizer.rb
|
121
129
|
- lib/twb/util/cypher.rb
|
122
130
|
- lib/twb/util/cypherpython.rb
|
123
131
|
- lib/twb/util/docprep.rb
|