twb 4.4.1 → 4.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/twb.rb +1 -1
- data/lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb +3 -2
- data/lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb +23 -19
- data/lib/twb/analysis/DataSources/dataSourceOriginsAnalyzer.rb +3 -2
- data/lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb +1 -0
- data/lib/twb/analysis/Sheets/dashsheetsanalyzer.rb +3 -2
- data/lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb +99 -38
- data/lib/twb/analysis/Sheets/sheetfiltersanalyzer.rb +28 -10
- data/lib/twb/codedfield.rb +3 -3
- data/lib/twb/datasource.rb +37 -19
- data/lib/twb/quickfilter.rb +4 -0
- data/lib/twb/worksheet.rb +91 -137
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8330ec06a3076b01a2e2f6958b630ae2312c74d1fd0fdb6a575d2271ffdb745d
|
4
|
+
data.tar.gz: 7db555e49b52c9f0bc218aff47ab4a1af2b6a03064d5ce5f8fe04ee7323d3b4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 801ed0a3f287f170f1d6f477641fa9c8ee761eb879a317ec779be9a9c4886a1f4dd78145b26b9e7dec9534d353ad583a3e4ceaaf8d9cf3f0781be657c364c19c
|
7
|
+
data.tar.gz: 22e0fc10a913f1fe27a0aac56c2230d35d8483dfeeea7ee8a8d28d1d8b67c05073eb1f925b5abda8e3dd8de98d1c704b0b1b93f242b3ad73b1aafaaf7987a9b9
|
data/lib/twb.rb
CHANGED
@@ -82,10 +82,11 @@ module Analysis
|
|
82
82
|
DOTHEADER
|
83
83
|
|
84
84
|
def initialize(**args)
|
85
|
+
@args = args
|
85
86
|
@csvAdd = args[:csvMode] == :add
|
86
87
|
@csvMode = @csvAdd ? 'a' : 'w'
|
87
|
-
emit true, "@csvAdd : #{@csvAdd}"
|
88
|
-
emit true, "@csvMode: #{@csvMode}"
|
88
|
+
# emit true, "@csvAdd : #{@csvAdd}"
|
89
|
+
# emit true, "@csvMode: #{@csvMode}"
|
89
90
|
init
|
90
91
|
@funcdoc = {:class=>self.class, :blurb=>'Analyze Calculated Fields', :description=>'Calculated fields can be complex, this tool provides robust coverage.',}
|
91
92
|
#-- CSV records collectors
|
@@ -24,30 +24,14 @@ module CalculatedFields
|
|
24
24
|
|
25
25
|
attr_reader :docFileName
|
26
26
|
|
27
|
-
def initialize
|
27
|
+
def initialize(**args)
|
28
|
+
@args = args
|
28
29
|
init
|
30
|
+
puts "RECORD DOC: "
|
29
31
|
@funcdoc = {:class=>self.class, :blurb=>'Create Markdown files (one per Workbook) documenting Calculated Fields', :description=>'Create Markdown files (one per Workbook) documenting Calculated Fields' }
|
30
32
|
@metrics = {}
|
31
33
|
end
|
32
34
|
|
33
|
-
def kramdownAvailable
|
34
|
-
gem_name, *gem_ver_reqs = 'kramdown', '~> 1.17.0'
|
35
|
-
gdep = Gem::Dependency.new(gem_name, *gem_ver_reqs)
|
36
|
-
# find latest that satisifies
|
37
|
-
found_gspec = gdep.matching_specs.max_by(&:version)
|
38
|
-
# instead of using Gem::Dependency, you can also do:
|
39
|
-
# Gem::Specification.find_all_by_name(gem_name, *gem_ver_reqs)
|
40
|
-
# if found_gspec
|
41
|
-
# puts "Requirement '#{gdep}' already satisfied by #{found_gspec.name}-#{found_gspec.version}"
|
42
|
-
# else
|
43
|
-
# puts "Requirement '#{gdep}' not satisfied; could be installing..."
|
44
|
-
# # reqs_string will be in the format: "> 1.0, < 1.2"
|
45
|
-
# # reqs_string = gdep.requirements_list.join(', ')
|
46
|
-
# # multi-arg is safer, to avoid injection attacks
|
47
|
-
# # system('gem', 'install', gem_name, '-v', reqs_string)
|
48
|
-
# end
|
49
|
-
end
|
50
|
-
|
51
35
|
def processTWB twb
|
52
36
|
# twb = File.basename(twb)
|
53
37
|
@twb = twb #Twb::Workbook.new twb
|
@@ -103,6 +87,26 @@ module CalculatedFields
|
|
103
87
|
finis
|
104
88
|
end # def processTwb twb
|
105
89
|
|
90
|
+
private
|
91
|
+
|
92
|
+
def kramdownAvailable
|
93
|
+
gem_name, *gem_ver_reqs = 'kramdown', '~> 1.17.0'
|
94
|
+
gdep = Gem::Dependency.new(gem_name, *gem_ver_reqs)
|
95
|
+
# find latest that satisifies
|
96
|
+
found_gspec = gdep.matching_specs.max_by(&:version)
|
97
|
+
# instead of using Gem::Dependency, you can also do:
|
98
|
+
# Gem::Specification.find_all_by_name(gem_name, *gem_ver_reqs)
|
99
|
+
# if found_gspec
|
100
|
+
# puts "Requirement '#{gdep}' already satisfied by #{found_gspec.name}-#{found_gspec.version}"
|
101
|
+
# else
|
102
|
+
# puts "Requirement '#{gdep}' not satisfied; could be installing..."
|
103
|
+
# # reqs_string will be in the format: "> 1.0, < 1.2"
|
104
|
+
# # reqs_string = gdep.requirements_list.join(', ')
|
105
|
+
# # multi-arg is safer, to avoid injection attacks
|
106
|
+
# # system('gem', 'install', gem_name, '-v', reqs_string)
|
107
|
+
# end
|
108
|
+
end
|
109
|
+
|
106
110
|
end # class MarkdownEmitter
|
107
111
|
|
108
112
|
end # nodule CalculatedFields
|
@@ -28,11 +28,12 @@ module Analysis
|
|
28
28
|
attr_accessor :localEmit
|
29
29
|
|
30
30
|
def initialize(**args)
|
31
|
+
@args = args
|
31
32
|
#-- TODO move @csvAdd * #csvMode resolution to TabTool
|
32
33
|
@csvAdd = args[:csvMode] == :add
|
33
34
|
@csvMode = @csvAdd ? 'a' : 'w'
|
34
|
-
emit "@csvAdd : #{@csvAdd}"
|
35
|
-
emit "@csvMode: #{@csvMode}"
|
35
|
+
# emit "@csvAdd : #{@csvAdd}"
|
36
|
+
# emit "@csvMode: #{@csvMode}"
|
36
37
|
#--
|
37
38
|
init
|
38
39
|
@funcdoc = {:class=>self.class, :blurb=>'Analyze Data Source Origins, i.e. where the data comes from', :description=>nil,}
|
@@ -27,10 +27,11 @@ module Analysis
|
|
27
27
|
|
28
28
|
def initialize(**args)
|
29
29
|
#-- TODO move @csvAdd * #csvMode resolution to TabTool
|
30
|
+
@args = args
|
30
31
|
@csvAdd = args[:csvMode] == :add
|
31
32
|
@csvMode = @csvAdd ? 'a' : 'w'
|
32
|
-
emit "@csvAdd : #{@csvAdd}"
|
33
|
-
emit "@csvMode: #{@csvMode}"
|
33
|
+
# emit "@csvAdd : #{@csvAdd}"
|
34
|
+
# emit "@csvMode: #{@csvMode}"
|
34
35
|
#--
|
35
36
|
init
|
36
37
|
@funcdoc = {:class=>self.class, :blurb=>'Analyze Dashboard Worksheets', :description=>'Identifies the Worksheets present in Dashboards.',}
|
@@ -25,34 +25,42 @@ module Analysis
|
|
25
25
|
|
26
26
|
@@fieldTypeCodes = { 'DB ref' => 'Db',
|
27
27
|
'color' => 'Clr',
|
28
|
-
'filter' => '
|
29
|
-
'lod' => '
|
30
|
-
'page' => '
|
31
|
-
'path' => '
|
32
|
-
'shape' => '
|
33
|
-
'size' => '
|
34
|
-
'text' => '
|
35
|
-
'tooltip' => '
|
36
|
-
:column => '
|
37
|
-
:row => '
|
28
|
+
'filter' => 'Flt',
|
29
|
+
'lod' => 'LoD',
|
30
|
+
'page' => 'Pge',
|
31
|
+
'path' => 'Pth',
|
32
|
+
'shape' => 'Shp',
|
33
|
+
'size' => 'Siz',
|
34
|
+
'text' => 'Tex',
|
35
|
+
'tooltip' => 'TTp',
|
36
|
+
:column => 'Clm',
|
37
|
+
:row => 'Row',
|
38
|
+
'slice' => 'Slc',
|
38
39
|
}
|
39
40
|
|
40
41
|
|
41
42
|
attr_accessor :localEmit
|
42
43
|
|
43
44
|
def initialize(**args)
|
44
|
-
@
|
45
|
-
@
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
@args = args
|
46
|
+
@csvAdd = args[:csvMode] == :add
|
47
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
48
|
+
# puts " args: #{@args}"
|
49
|
+
# puts " @recordDir: #{@recordDir}"
|
50
|
+
# @csvMode = @csvAdd ? 'a' : 'w'
|
51
|
+
# emit true, "@csvAdd : #{@csvAdd}"
|
52
|
+
# emit true, "@csvMode: #{@csvMode}"
|
49
53
|
init
|
50
54
|
@funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Fields', :description=>nil,}
|
51
55
|
#--
|
52
56
|
docFileName = docFile('WorksheetFields.csv')
|
53
57
|
@sheetFieldsCSV = CSV.open(docFileName,'w')
|
54
58
|
unless @csvAdd
|
55
|
-
@
|
59
|
+
if @recordDir
|
60
|
+
@sheetFieldsCSV << ['Rec #', 'Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)','Usage','Usage - code','Workbook Dir']
|
61
|
+
else
|
62
|
+
@sheetFieldsCSV << ['Rec #', 'Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)','Usage','Usage - code' ]
|
63
|
+
end
|
56
64
|
end
|
57
65
|
addDocFile @sheetFieldsCSV, docFileName, "Workbooks, Worksheets, and the Sheets' Data Sources and Fields"
|
58
66
|
#--
|
@@ -92,37 +100,65 @@ module Analysis
|
|
92
100
|
end
|
93
101
|
|
94
102
|
def showFields sheet
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
103
|
+
recordDBFields sheet
|
104
|
+
recordRCFields sheet.rowFields, :row
|
105
|
+
recordRCFields sheet.colFields, :column
|
106
|
+
recordEncodedFields sheet
|
107
|
+
recordFilterFields sheet
|
108
|
+
recordPageFields sheet
|
109
|
+
recordSlicesFields sheet
|
110
|
+
recordDSFilterFields sheet
|
101
111
|
end
|
102
112
|
|
103
|
-
def
|
113
|
+
def recordPageFields sheet
|
104
114
|
sheet.pageFields.each do |pfield|
|
105
115
|
ds = @twb.datasource pfield.dataSource
|
106
|
-
fuiname = ds.fieldUIName pfield.name
|
107
|
-
|
116
|
+
fuiname = ds.fieldUIName pfield.name
|
117
|
+
# if @recordDir
|
118
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, ds.name, fuiname, pfield.name, 'page', ftc('filter'), @twb.dir]
|
119
|
+
# else
|
120
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, ds.name, fuiname, pfield.name, 'page', ftc('filter') ]
|
121
|
+
# end
|
122
|
+
recordCSV [@twb.name, @sheet, ds.uiname, ds.name, fuiname, pfield.name, 'page', ftc('page')]
|
108
123
|
end
|
109
124
|
end
|
110
125
|
|
111
|
-
def
|
126
|
+
def recordFilterFields sheet
|
112
127
|
filters = sheet.filters
|
113
128
|
filters.each do |filter|
|
114
129
|
dsName = filter.dataSource.name
|
115
130
|
dsUIName = filter.dataSource.uiname
|
116
131
|
# puts "Filter field: #{filter.dataSource.name} ui:'#{}'"
|
117
|
-
|
132
|
+
# if @recordDir
|
133
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, dsUIName, dsName, filter.uiname, filter.name, 'filter', ftc('filter'), @twb.dir]
|
134
|
+
# else
|
135
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, dsUIName, dsName, filter.uiname, filter.name, 'filter', ftc('filter') ]
|
136
|
+
# end
|
137
|
+
recordCSV [@twb.name, @sheet, dsUIName, dsName, filter.uiname, filter.name, 'filter', ftc('filter')]
|
118
138
|
end
|
119
139
|
end
|
120
140
|
|
121
|
-
def
|
141
|
+
def recordDSFilterFields sheet
|
142
|
+
sheet.slicesFields.each do |field|
|
143
|
+
dsName = field.dataSource
|
144
|
+
ds = @twb.datasource dsName
|
145
|
+
dsUIName = ds.uiname
|
146
|
+
ds.filters.each do |filter|
|
147
|
+
recordCSV [@twb.name, @sheet, dsUIName, dsName, filter.uiname, filter.name, 'dsfilter', ftc('dsfilter')]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def recordDBFields sheet
|
122
153
|
fields = sheet.datasourceFields
|
123
|
-
emit "def
|
154
|
+
emit "def recordDBFields sheet: #{sheet.name} #FIELDS: #{fields.length}"
|
124
155
|
if fields.nil?
|
125
|
-
|
156
|
+
# if @recordDir
|
157
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil, @twb.dir]
|
158
|
+
# else
|
159
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil]
|
160
|
+
# end
|
161
|
+
recordCSV [@twb.name, @sheet, nil, nil, nil, nil, nil]
|
126
162
|
end
|
127
163
|
fields.each do |dsName, dsfields|
|
128
164
|
ds = @twb.datasource dsName
|
@@ -134,16 +170,18 @@ module Analysis
|
|
134
170
|
emit " f: #{sheetField}"
|
135
171
|
emit " c: #{sheetField.class}"
|
136
172
|
fuiName = ds.fieldUIName sheetField #Fields[sheetField]
|
137
|
-
@sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, sheetField.uiname, sheetField.name, 'DB ref', ftc('DB ref')]
|
173
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, sheetField.uiname, sheetField.name, 'DB ref', ftc('DB ref')]
|
174
|
+
recordCSV [@twb.name, @sheet, ds.uiname, dsName, sheetField.uiname, sheetField.name, 'DB ref', ftc('DB ref')]
|
138
175
|
# emit true, " : #{dsFields[field].class}"
|
139
176
|
end
|
140
177
|
end
|
141
178
|
end
|
142
179
|
|
143
|
-
def
|
144
|
-
emit "def
|
180
|
+
def recordRCFields fields, usage
|
181
|
+
emit "def recordRCFields #fields: #{fields.length} \t #{fields}"
|
145
182
|
if fields.nil?
|
146
|
-
@sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil]
|
183
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, nil, nil, nil, nil, nil]
|
184
|
+
recordCSV [@twb.name, @sheet, nil, nil, nil, nil, nil]
|
147
185
|
else
|
148
186
|
fields.each do |cf|
|
149
187
|
emit "coded field: #{cf}"
|
@@ -155,23 +193,46 @@ module Analysis
|
|
155
193
|
emit " ds: #{dsName}"
|
156
194
|
emit " - #{ds.uiname}"
|
157
195
|
emit " : #{ds.class}"
|
158
|
-
@sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, fldName, usage, ftc(usage)]
|
196
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, fldName, usage, ftc(usage)]
|
197
|
+
recordCSV [@twb.name, @sheet, ds.uiname, dsName, fuiName, fldName, usage, ftc(usage)]
|
159
198
|
end
|
160
199
|
end
|
161
200
|
end
|
162
201
|
|
163
|
-
def
|
202
|
+
def recordEncodedFields sheet
|
164
203
|
unless sheet.encodedFields.nil?
|
165
204
|
sheet.encodedFields.each do |type,fields|
|
166
205
|
fields.each do |field|
|
167
206
|
dsName = field.dataSource
|
168
207
|
ds = @twb.datasource dsName
|
169
208
|
fuiName = ds.fieldUIName field.name
|
170
|
-
@sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, field.name, type, ftc(type)]
|
209
|
+
# @sheetFieldsCSV << [@recNum+=1, @twb.name, @sheet, ds.uiname, dsName, fuiName, field.name, type, ftc(type)]
|
210
|
+
recordCSV [@twb.name, @sheet, ds.uiname, dsName, fuiName, field.name, type, ftc(type)]
|
171
211
|
end
|
172
212
|
end
|
173
213
|
end
|
174
|
-
end #def
|
214
|
+
end #def recordEncodedFields
|
215
|
+
|
216
|
+
def recordSlicesFields sheet
|
217
|
+
# puts "recordSlicesFields"
|
218
|
+
unless sheet.slicesFields.nil?
|
219
|
+
sheet.slicesFields.each do |field|
|
220
|
+
dsName = field.dataSource
|
221
|
+
ds = @twb.datasource dsName
|
222
|
+
fuiName = ds.fieldUIName field.name
|
223
|
+
recordCSV [@twb.name, @sheet, ds.uiname, dsName, fuiName, field.name, 'slice', ftc('slice')]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def recordCSV record
|
229
|
+
numberedRec = [@recNum+=1] + record
|
230
|
+
if @recordDir
|
231
|
+
@sheetFieldsCSV << numberedRec.push(@twb.dir)
|
232
|
+
else
|
233
|
+
@sheetFieldsCSV << numberedRec
|
234
|
+
end
|
235
|
+
end
|
175
236
|
|
176
237
|
def ftc type # ftc : abbr for fieldTypeCode, for brevity
|
177
238
|
@@fieldTypeCodes[type].nil? ? type : @@fieldTypeCodes[type]
|
@@ -26,22 +26,29 @@ module Analysis
|
|
26
26
|
attr_accessor :localEmit
|
27
27
|
|
28
28
|
def initialize(**args)
|
29
|
-
@
|
30
|
-
@
|
31
|
-
|
32
|
-
|
29
|
+
@args = args
|
30
|
+
@recordDir = !@args.nil? && @args[:recordDir] == true
|
31
|
+
@csvAdd = args[:csvMode] == :add
|
32
|
+
# @csvMode = @csvAdd ? 'a' : 'w'
|
33
|
+
# emit "@csvAdd : #{@csvAdd}"
|
34
|
+
# emit "@csvMode: #{@csvMode}"
|
33
35
|
init
|
34
36
|
@funcdoc = {:class=>self.class, :blurb=>'Analyze Worksheet Filters', :description=>'Documents Quick Filters and the values they employ, if any. Work in progess.',}
|
35
37
|
#--
|
36
38
|
docFileName = docFile('WorksheetFilters.csv')
|
37
|
-
|
39
|
+
@sheetFieldsCSV = CSV.open( docFileName ,'w')
|
38
40
|
unless @csvAdd
|
39
|
-
|
41
|
+
if @recordDir
|
42
|
+
@sheetFieldsCSV << ['Rec #','Workbook','Worksheet','Filter Type','Operation','Data Source','Field','Value','Alias', 'Alias?','Operation Mode','Include Null?','Kind','Workbook Dir']
|
43
|
+
else
|
44
|
+
@sheetFieldsCSV << ['Rec #','Workbook','Worksheet','Filter Type','Operation','Data Source','Field','Value','Alias', 'Alias?','Operation Mode','Include Null?','Kind']
|
45
|
+
end
|
40
46
|
end
|
41
|
-
addDocFile
|
47
|
+
addDocFile @sheetFieldsCSV, docFileName, "Workbooks, Worksheets and the sheets' Quick Filters"
|
42
48
|
#--
|
43
49
|
@sheetCount = 0
|
44
50
|
@filterCount = 0
|
51
|
+
@recNum = 0
|
45
52
|
end
|
46
53
|
|
47
54
|
def metrics
|
@@ -68,20 +75,31 @@ module Analysis
|
|
68
75
|
filters.each do |filter|
|
69
76
|
filter.emit "-----------------------------\nWORKSHEET:: #{sheet.name}\n-----------------------------"
|
70
77
|
if filter.values.empty?
|
71
|
-
#
|
72
|
-
|
78
|
+
# @sheetFieldsCSV << ['Workbook','Worksheet','Filter Type','Operation' ,'Data Source','Field','Value','Alias', 'Alias?']
|
79
|
+
recordCSV [@twbName, sheet.name, filter.type, filter.inexclude, filter.dataSource.uiname, filter.uiname, nil, nil, nil, filter.inexMode, filter.includeNull, filter.kind]
|
73
80
|
end
|
74
81
|
filter.values.each do |valueMap|
|
75
82
|
value = valueMap[:value]
|
76
83
|
valias = valueMap[:alias]
|
77
84
|
same = value.eql? valias
|
78
85
|
emit "RECORDING FILTER VALUES: %-35s -- %-25s same? %s " % [value,valias,same]
|
79
|
-
|
86
|
+
recordCSV [@twbName, sheet.name, filter.type, filter.inexclude, filter.dataSource.uiname, filter.uiname, value, valias, same, filter.inexMode, filter.includeNull, filter.kind]
|
80
87
|
end
|
81
88
|
end
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
92
|
+
private
|
93
|
+
|
94
|
+
def recordCSV record
|
95
|
+
numberedRec = [@recNum+=1] + record
|
96
|
+
if @recordDir
|
97
|
+
@sheetFieldsCSV << numberedRec.push(@twbDir)
|
98
|
+
else
|
99
|
+
@sheetFieldsCSV << numberedRec
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
85
103
|
end # class SheetFiltersAnalyzerA
|
86
104
|
|
87
105
|
end # module Twb
|
data/lib/twb/codedfield.rb
CHANGED
@@ -27,10 +27,10 @@ module Twb
|
|
27
27
|
attr_reader :name, :techCode, :function, :rawCode
|
28
28
|
|
29
29
|
def initialize code
|
30
|
-
|
30
|
+
# puts "...CodedField :: #{code}"
|
31
31
|
@rawCode = code
|
32
|
-
trimmed = code.gsub(/^['"]|['"]$/,'').gsub(/^\[|\]$/,'')
|
33
|
-
# puts "trimmed
|
32
|
+
trimmed = code.gsub(/^['"]|['"]$/,'').gsub(/^\[|\]$/,'').gsub(/:[0-9]+$/,'')
|
33
|
+
# puts " trimmed :: #{trimmed}"
|
34
34
|
parts = trimmed.split('].[')
|
35
35
|
#puts "Field: #{code} parts: #{parts.length} - #{parts.inspect}"
|
36
36
|
#puts " p1: #{parts[0]}"
|
data/lib/twb/datasource.rb
CHANGED
@@ -70,7 +70,7 @@ module Twb
|
|
70
70
|
@uiname = @caption.nil? ? @name : @caption
|
71
71
|
# puts "DATASOURCE: #{@uiname}"
|
72
72
|
processConnection
|
73
|
-
processFilters
|
73
|
+
# processFilters
|
74
74
|
loadTableFields
|
75
75
|
loadFieldUINames
|
76
76
|
return self
|
@@ -503,10 +503,16 @@ module Twb
|
|
503
503
|
end
|
504
504
|
end
|
505
505
|
|
506
|
+
def filters
|
507
|
+
@filters ||= loadFilters
|
508
|
+
end
|
509
|
+
|
506
510
|
def groups
|
507
511
|
@groups ||= loadGroups
|
508
512
|
end
|
509
513
|
|
514
|
+
private
|
515
|
+
|
510
516
|
def loadGroups
|
511
517
|
@groups = []
|
512
518
|
groupNodes = @node.xpath('.//group')
|
@@ -517,25 +523,37 @@ module Twb
|
|
517
523
|
return @groups
|
518
524
|
end
|
519
525
|
|
520
|
-
def processFilters
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
memberNodes = fn.xpath('.//groupfilter/@member')
|
528
|
-
unless memberNodes.nil?
|
529
|
-
members = []
|
530
|
-
memberNodes.each do |m|
|
531
|
-
members.push m.text
|
532
|
-
end
|
533
|
-
@filters[columnN.text] = members
|
534
|
-
end
|
535
|
-
end
|
536
|
-
end
|
526
|
+
# def processFilters
|
527
|
+
def loadFilters
|
528
|
+
@filters = []
|
529
|
+
sharedFilters = @workbook.node.xpath('./shared-views/shared-view[@name="excel.41269.481293159719"]//filter')
|
530
|
+
sharedFilters.each do |sf|
|
531
|
+
filter = QuickFilter.new(sf,@workbook)
|
532
|
+
@filters << filter
|
537
533
|
end
|
538
|
-
|
534
|
+
return @filters
|
535
|
+
end
|
536
|
+
|
537
|
+
# @filters <<
|
538
|
+
# if @filters.nil?
|
539
|
+
# @filters = {}
|
540
|
+
# fnodes = @node.xpath('./filter')
|
541
|
+
# fnodes.each do |fn|
|
542
|
+
# columnN = fn.attribute('column')
|
543
|
+
# unless columnN.nil?
|
544
|
+
# memberNodes = fn.xpath('.//groupfilter/@member')
|
545
|
+
# unless memberNodes.nil?
|
546
|
+
# members = []
|
547
|
+
# memberNodes.each do |m|
|
548
|
+
# members.push m.text
|
549
|
+
# end
|
550
|
+
# @filters[columnN.text] = members
|
551
|
+
# end
|
552
|
+
# end
|
553
|
+
# end
|
554
|
+
# end
|
555
|
+
# end
|
556
|
+
|
539
557
|
|
540
558
|
end # class DataSource
|
541
559
|
|
data/lib/twb/quickfilter.rb
CHANGED
data/lib/twb/worksheet.rb
CHANGED
@@ -28,7 +28,7 @@ module Twb
|
|
28
28
|
|
29
29
|
attr_reader :node, :name, :datasourcenames, :datasources
|
30
30
|
attr_reader :panesCount
|
31
|
-
attr_reader :fields, :rowFields, :colFields, :paneFields, :datasourceFields, :pageFields, :encodedFields
|
31
|
+
attr_reader :fields, :rowFields, :colFields, :paneFields, :datasourceFields, :pageFields, :encodedFields, :slicesFields
|
32
32
|
attr_reader :filters
|
33
33
|
attr_reader :tooltip
|
34
34
|
attr_accessor :hidden, :visible
|
@@ -38,8 +38,7 @@ module Twb
|
|
38
38
|
@node = sheetNode
|
39
39
|
@name = @node['name']
|
40
40
|
emit "########################## Worksheet initialize name: #{@name}"
|
41
|
-
|
42
|
-
loadDataSourceNames
|
41
|
+
loadDataSources
|
43
42
|
loadFields
|
44
43
|
return self
|
45
44
|
end
|
@@ -48,15 +47,6 @@ module Twb
|
|
48
47
|
@id ||= @name.hash
|
49
48
|
end
|
50
49
|
|
51
|
-
def loadDataSourceNames
|
52
|
-
@datasources = {}
|
53
|
-
dsNodes = @node.xpath('.//datasource')
|
54
|
-
dsNodes.each do |dsn|
|
55
|
-
ds = WorksheetDataSource.new dsn
|
56
|
-
@datasources[ds.name] = ds
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
50
|
def workbook
|
61
51
|
@workbook ||= @node.at_xpath('/').root
|
62
52
|
end
|
@@ -78,6 +68,10 @@ module Twb
|
|
78
68
|
# @fields.nil? ? loadFields : @fields
|
79
69
|
end
|
80
70
|
|
71
|
+
def slicesFields
|
72
|
+
@slicesFields ||= loadSlicesFields
|
73
|
+
end
|
74
|
+
|
81
75
|
def filters
|
82
76
|
@filters ||= loadFilters
|
83
77
|
end
|
@@ -94,6 +88,36 @@ module Twb
|
|
94
88
|
@visible ||= !hidden
|
95
89
|
end
|
96
90
|
|
91
|
+
def addDSFields fields, usage
|
92
|
+
fields.each do
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def panesCount
|
97
|
+
@panesCount ||= @node.xpath('.//panes/pane').length
|
98
|
+
end
|
99
|
+
|
100
|
+
def paneFields
|
101
|
+
@paneFields ||= loadPaneFields
|
102
|
+
end
|
103
|
+
|
104
|
+
def pageFields
|
105
|
+
@pageFields ||= loadpageFields
|
106
|
+
end
|
107
|
+
|
108
|
+
def datasourcenames
|
109
|
+
@datasources.keys
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# def resolveHidden
|
115
|
+
# xpath = "//windows/window[@name=\"#{@name}\"]"
|
116
|
+
# emit true, "resolveHidden: #{xpath}"
|
117
|
+
# windowNode = @node.at_xpath(xpath)
|
118
|
+
# @hidden = !windowNode.nil? && 'true' == windowNode['hidden']
|
119
|
+
# end
|
120
|
+
|
97
121
|
def loadFields
|
98
122
|
# puts "WORKSHEET loadFields"
|
99
123
|
@fields = {}
|
@@ -117,43 +141,29 @@ module Twb
|
|
117
141
|
loadFieldEncodings
|
118
142
|
end
|
119
143
|
|
120
|
-
def
|
121
|
-
@
|
122
|
-
|
123
|
-
enodes.each do |enode|
|
124
|
-
enode.children.each do |child|
|
125
|
-
unless child['column'].nil?
|
126
|
-
@encodedFields[child.name] << CodedField.new(child['column'])
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
@encodedFields.each do |type, fields|
|
131
|
-
@fields[type] = fields
|
132
|
-
end
|
144
|
+
def loadPaneFields
|
145
|
+
@paneFields = Set.new
|
146
|
+
panes = @node.xpath('.//pane')
|
133
147
|
end
|
134
148
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
# end
|
143
|
-
# end
|
144
|
-
# end
|
145
|
-
# $encodedFields.each do |type, fields|
|
146
|
-
# $fields[type] = fields
|
147
|
-
# end
|
148
|
-
# end
|
149
|
-
|
150
|
-
def addDSFields fields, usage
|
151
|
-
fields.each do
|
149
|
+
def loadFilters
|
150
|
+
emit ""########################## loadFilters"
|
151
|
+
@filters = []
|
152
|
+
filterNodes = @node.xpath('./table/view//filter[@column]')
|
153
|
+
filterNodes.each do |fnode|
|
154
|
+
filter = QuickFilter.new(fnode,@twb)
|
155
|
+
@filters << filter
|
152
156
|
end
|
157
|
+
return @filters
|
153
158
|
end
|
154
159
|
|
155
|
-
def
|
156
|
-
@
|
160
|
+
def loadDataSources
|
161
|
+
@datasources = {}
|
162
|
+
dsNodes = @node.xpath('.//datasource')
|
163
|
+
dsNodes.each do |dsn|
|
164
|
+
ds = WorksheetDataSource.new dsn
|
165
|
+
@datasources[ds.name] = ds
|
166
|
+
end
|
157
167
|
end
|
158
168
|
|
159
169
|
def loadRowColFields(type)
|
@@ -174,17 +184,8 @@ module Twb
|
|
174
184
|
return fields
|
175
185
|
end
|
176
186
|
|
177
|
-
def
|
178
|
-
@
|
179
|
-
end
|
180
|
-
|
181
|
-
def loadPaneFields
|
182
|
-
@paneFields = Set.new
|
183
|
-
panes = @node.xpath('.//pane')
|
184
|
-
end
|
185
|
-
|
186
|
-
def pageFields
|
187
|
-
@pageFields ||= loadpageFields
|
187
|
+
def loadTooltip
|
188
|
+
@tooltip = @node.xpath('./table/panes/pane/customized-tooltip')
|
188
189
|
end
|
189
190
|
|
190
191
|
def loadpageFields
|
@@ -196,33 +197,47 @@ module Twb
|
|
196
197
|
return @pageFields
|
197
198
|
end
|
198
199
|
|
199
|
-
def
|
200
|
-
@
|
200
|
+
def loadSlicesFields
|
201
|
+
@slicesFields = []
|
202
|
+
nodes = @node.xpath('./table/view/slices//column')
|
203
|
+
nodes.each do |node|
|
204
|
+
# puts "Slice field: #{node.text}"
|
205
|
+
@slicesFields << CodedField.new(node.text)
|
206
|
+
end
|
207
|
+
return @slicesFields
|
201
208
|
end
|
202
209
|
|
203
|
-
|
210
|
+
def loadFieldEncodings
|
211
|
+
@encodedFields = Hash.new { |h,k| h[k] = [] }
|
212
|
+
enodes = @node.xpath('.//table/panes/pane/encodings')
|
213
|
+
enodes.each do |enode|
|
214
|
+
enode.children.each do |child|
|
215
|
+
unless child['column'].nil?
|
216
|
+
@encodedFields[child.name] << CodedField.new(child['column'])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
@encodedFields.each do |type, fields|
|
221
|
+
@fields[type] = fields
|
222
|
+
end
|
223
|
+
end
|
204
224
|
|
205
|
-
# def
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
225
|
+
# def loadFieldEncodings node
|
226
|
+
# $encodedFields = Hash.new { |h,k| h[k] = [] }
|
227
|
+
# enodes = node.xpath('.//table/panes/pane/encodings')
|
228
|
+
# enodes.each do |enode|
|
229
|
+
# enode.children.each do |child|
|
230
|
+
# unless child['column'].nil?
|
231
|
+
# $encodedFields[child.name] << CodedField.new(child['column'])
|
232
|
+
# end
|
233
|
+
# end
|
234
|
+
# end
|
235
|
+
# $encodedFields.each do |type, fields|
|
236
|
+
# $fields[type] = fields
|
237
|
+
# end
|
210
238
|
# end
|
211
239
|
|
212
|
-
def loadFilters
|
213
|
-
emit ""########################## loadFilters"
|
214
|
-
@filters = []
|
215
|
-
filterNodes = @node.xpath('./table/view//filter[@column]')
|
216
|
-
filterNodes.each do |fnode|
|
217
|
-
filter = QuickFilter.new(fnode,@twb)
|
218
|
-
@filters << filter
|
219
|
-
end
|
220
|
-
return @filters
|
221
|
-
end
|
222
240
|
|
223
|
-
def loadTooltip
|
224
|
-
@tooltip = @node.xpath('./table/panes/pane/customized-tooltip')
|
225
|
-
end
|
226
241
|
|
227
242
|
end # class Worksheet
|
228
243
|
|
@@ -273,65 +288,4 @@ module Twb
|
|
273
288
|
end # class RowsColsSplitter
|
274
289
|
|
275
290
|
|
276
|
-
|
277
|
-
class CodedField
|
278
|
-
|
279
|
-
include Comparable
|
280
|
-
|
281
|
-
attr_reader :code, :dataSource, :prefix, :name, :suffix
|
282
|
-
|
283
|
-
def initialize incode
|
284
|
-
# puts "CF: #{incode}"
|
285
|
-
@code = incode
|
286
|
-
trimCode = code.gsub(/^\[/,'').gsub(/\]$/,'')
|
287
|
-
# puts " : '#{trimCode}'"
|
288
|
-
@dataSource = nil
|
289
|
-
dsFldBits = trimCode.split('].[')
|
290
|
-
if dsFldBits.length == 2
|
291
|
-
@dataSource = dsFldBits[0]
|
292
|
-
fieldCode = dsFldBits[1]
|
293
|
-
else
|
294
|
-
fieldCode = dsFldBits[0]
|
295
|
-
end
|
296
|
-
# puts "fc: #{fieldCode}"
|
297
|
-
parts = fieldCode.split(':')
|
298
|
-
bits =
|
299
|
-
if ':Measure Names'.eql?(fieldCode)
|
300
|
-
{:prefix => nil, :name => fieldCode, :suffix => nil }
|
301
|
-
else
|
302
|
-
case parts.length
|
303
|
-
when 1
|
304
|
-
bits = {:prefix => nil, :name => parts[0], :suffix => nil}
|
305
|
-
when 3
|
306
|
-
bits = {:prefix => parts[0], :name => parts[1], :suffix => parts[2]}
|
307
|
-
when 4
|
308
|
-
if parts[-1].match(/^(\d)+$/)
|
309
|
-
bits = {:prefix => parts[0], :name => parts[1], :suffix => "#{parts[2]}:#{parts[3]}"}
|
310
|
-
else
|
311
|
-
bits = {:prefix => "#{parts[0]}:#{parts[1]}", :name => parts[2], :suffix => parts[3]}
|
312
|
-
end
|
313
|
-
when 5
|
314
|
-
bits = {:prefix => "#{parts[0]}:#{parts[1]}", :name => parts[2], :suffix => "#{parts[3]}:#{parts[4]}"}
|
315
|
-
else
|
316
|
-
bits = {:prefix => "OOPS #{parts.inspect}", :name => '', :suffix => '' }
|
317
|
-
end
|
318
|
-
end
|
319
|
-
@prefix = bits[:prefix]
|
320
|
-
@name = bits[:name]
|
321
|
-
@suffix = bits[:suffix]
|
322
|
-
# puts " l: #{parts.length} == #{bits}"
|
323
|
-
# bits.each { |k,v| puts " l: %-7s %s" % [k,v] }
|
324
|
-
end
|
325
|
-
# --
|
326
|
-
def to_s
|
327
|
-
@code
|
328
|
-
end
|
329
|
-
|
330
|
-
def <=>(other)
|
331
|
-
@code <=> other.code
|
332
|
-
end
|
333
|
-
|
334
|
-
end #class CodedField
|
335
|
-
|
336
|
-
|
337
291
|
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.
|
4
|
+
version: 4.4.2
|
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-
|
11
|
+
date: 2019-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: creek
|