twb 2.2.1 → 3.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/twb.rb +13 -1
- data/lib/twb/action.rb +5 -1
- data/lib/twb/analysis/AnnotatedFieldsCSVEmitter.rb +3 -0
- data/lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb +276 -287
- data/lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb +48 -34
- data/lib/twb/analysis/DataSources/DataSourceFieldsCSVEmitter.rb +103 -103
- data/lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb +79 -0
- data/lib/twb/analysis/DocumentedFieldsMarkdownEmitter.rb +1 -1
- data/lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb +82 -0
- data/lib/twb/analysis/Sheets/sheetfiltersanalyzer.rb +214 -0
- data/lib/twb/calculatedfield.rb +20 -5
- data/lib/twb/codedfield.rb +87 -0
- data/lib/twb/columnfield.rb +21 -2
- data/lib/twb/connection.rb +33 -0
- data/lib/twb/dashboard.rb +5 -1
- data/lib/twb/datasource.rb +131 -20
- data/lib/twb/dbfield.rb +4 -0
- data/lib/twb/field.rb +5 -1
- data/lib/twb/fieldcalculation.rb +134 -78
- data/lib/twb/localfield.rb +5 -1
- data/lib/twb/mappedfield.rb +5 -1
- data/lib/twb/metadatafield.rb +5 -1
- data/lib/twb/storyboard.rb +5 -1
- data/lib/twb/tabclass.rb +71 -0
- data/lib/twb/tabtest.rb +31 -0
- data/lib/twb/tabtool.rb +63 -0
- data/lib/twb/twbcodedfield.rb +87 -0
- data/lib/twb/util/cypher.rb +112 -0
- data/lib/twb/util/cypherpython.rb +128 -0
- data/lib/twb/util/docprep.rb +46 -0
- data/lib/twb/util/fielddomainloader.rb +108 -0
- data/lib/twb/util/gml.rb +144 -0
- data/lib/twb/util/gmledge.rb +73 -0
- data/lib/twb/util/graph.rb +30 -0
- data/lib/twb/util/graphedge.rb +8 -9
- data/lib/twb/util/graphnode.rb +46 -29
- data/lib/twb/util/tabgraph.rb +30 -0
- data/lib/twb/window.rb +5 -1
- data/lib/twb/workbook.rb +18 -5
- data/lib/twb/worksheet.rb +5 -1
- data/test/fieldAliases.rb +10 -0
- data/test/testFieldAliases.rb +65 -0
- data/test/testFieldDomainLoaded.rb +14 -0
- data/test/testFieldDomainLoader.rb +131 -0
- metadata +22 -1
@@ -0,0 +1,82 @@
|
|
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
|
+
require 'set'
|
19
|
+
|
20
|
+
module Twb
|
21
|
+
module Analysis
|
22
|
+
|
23
|
+
class SheetFieldsAnalyzer
|
24
|
+
|
25
|
+
include TabTool
|
26
|
+
|
27
|
+
attr_accessor :localEmit
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@twbCnt = 0
|
31
|
+
@sheetCnt = 0
|
32
|
+
@filterCnt = 0
|
33
|
+
@funcdoc = {:class=>self.class, :blurb=>'Analyzing Sheet Fields from Tableau Workbooks.', :description=>nil,}
|
34
|
+
docFileName = docFile('TWBWorksheetFields.csv')
|
35
|
+
@sheetFieldsCSV = CSV.open(docFileName,'w')
|
36
|
+
@sheetFieldsCSV << ['Workbook','Worksheet','Data Source','Data Source (tech)','Field','Field (tech)']
|
37
|
+
@docfiles = [{:name=>docFileName,:desc=>"CSV File containing the data relating Workbooks,Worksheets, and the sheets' Data Sources and Fields"}]
|
38
|
+
end
|
39
|
+
|
40
|
+
def processTWB twb
|
41
|
+
@twb = twb
|
42
|
+
emit " -- #{@twb.name}"
|
43
|
+
@twbCnt += 1
|
44
|
+
@twbDomainsLoaded = false
|
45
|
+
parseSheets
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def parseSheets
|
50
|
+
@worksheets = @twb.worksheets
|
51
|
+
@worksheets.each do |sheet|
|
52
|
+
emit "SHEET: #{sheet.name}"
|
53
|
+
showFields sheet unless sheet.datasourceFields.nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def showFields sheet
|
58
|
+
fields = sheet.datasourceFields
|
59
|
+
emit " #FIELDS: #{fields.length}"
|
60
|
+
if fields.nil?
|
61
|
+
@sheetFieldsCSV << [@twb.name, sheet.name, nil, nil, nil, nil]
|
62
|
+
end
|
63
|
+
fields.each do |dsName, dsfields|
|
64
|
+
ds = @twb.datasource dsName
|
65
|
+
emit " ds: #{dsName}"
|
66
|
+
emit " - #{ds.uiname}"
|
67
|
+
emit " : #{ds.class}"
|
68
|
+
dsfields.each do |sheetField|
|
69
|
+
emit " f: #{sheetField}"
|
70
|
+
emit " c: #{sheetField.class}"
|
71
|
+
fuiName = ds.fieldUIName sheetField #Fields[sheetField]
|
72
|
+
@sheetFieldsCSV << [@twb.name, sheet.name, ds.uiname, dsName, sheetField.uiname, sheetField.name]
|
73
|
+
# emit true, " : #{dsFields[field].class}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end #class SheetFieldsAnalyzer
|
80
|
+
|
81
|
+
end # module Analysis
|
82
|
+
end # module Twb
|
@@ -0,0 +1,214 @@
|
|
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
|
+
require 'set'
|
19
|
+
|
20
|
+
module Twb
|
21
|
+
module Analysis
|
22
|
+
|
23
|
+
class SheetFiltersAnalyzer
|
24
|
+
|
25
|
+
include TabTool
|
26
|
+
|
27
|
+
attr_accessor :localEmit
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@twbCnt = 0
|
31
|
+
@sheetCnt = 0
|
32
|
+
@filterCnt = 0
|
33
|
+
# @ttlogfile = File.new('./ttdoc/SheetFiltersAnalyzer.ttlog','w')
|
34
|
+
$sheetFieldsCSV = CSV.open(docFile('TWBWorksheetFilters.csv') ,'w')
|
35
|
+
$sheetFieldsCSV << ['Workbook','Worksheet','Filter Type','Data Source','Field','Value','Alias', 'Alias?']
|
36
|
+
end
|
37
|
+
|
38
|
+
def processTWB twb
|
39
|
+
@twb = twb
|
40
|
+
emit " -- #{@twb.name}"
|
41
|
+
@twbCnt += 1
|
42
|
+
@twbDomainsLoaded = false
|
43
|
+
parseFilters
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def parseFilters
|
48
|
+
@worksheets = @twb.worksheets
|
49
|
+
@worksheets.each do |sheet|
|
50
|
+
emit "\n\nSHEET: #{sheet.name}"
|
51
|
+
@sheetCnt += 1
|
52
|
+
filters = sheet.node.xpath('.//filter[@column]')
|
53
|
+
filters.each do |filter|
|
54
|
+
emit "\nFILTER:\n#{filter}\n====="
|
55
|
+
fieldCode = filter.attribute('column').text
|
56
|
+
codedField = Twb::CodedField.new(fieldCode)
|
57
|
+
fieldTech = codedField.name
|
58
|
+
srcTech = codedField.dataSource
|
59
|
+
dataSource = @twb.datasource(srcTech)
|
60
|
+
@dsAliases = dataSource.aliases
|
61
|
+
field = dataSource.fieldUIName fieldTech
|
62
|
+
emit "\n:: FIELD :: #{field} -- #{fieldTech} -- #{codedField.rawCode}"
|
63
|
+
filterValues = collectFilterValues sheet, dataSource, field, filter
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def collectFilterValues sheet, dataSource, field, node
|
69
|
+
emit "collectFilterValues"
|
70
|
+
emit " sheet: #{sheet.name}"
|
71
|
+
emit " ds: #{dataSource.uiname}"
|
72
|
+
emit " field: #{field}"
|
73
|
+
emit " node: #{node}"
|
74
|
+
emit " "
|
75
|
+
firstChild = node.at_xpath('./groupfilter')
|
76
|
+
results = {}
|
77
|
+
unless firstChild.nil?
|
78
|
+
function = firstChild.attribute('function').text
|
79
|
+
emit "function: #{function}"
|
80
|
+
emit node.to_s
|
81
|
+
#-- single element filter
|
82
|
+
if 'member'.eql? function
|
83
|
+
emit "HANDLING SINGLE MEMBER FILTER"
|
84
|
+
value = firstChild.attribute('member').text.gsub(/^"|"$/,'')
|
85
|
+
alia = dataSource.deAlias(field,value)
|
86
|
+
emit "value :%-25s => alias: %-s" % [value, alia]
|
87
|
+
$sheetFieldsCSV << [ @twb.name, sheet.name, 'single', dataSource.uiname, field, value, alia ]
|
88
|
+
return {value => alia}
|
89
|
+
end
|
90
|
+
#-- otherwise filter contains multiple elements
|
91
|
+
#-- handle individual member elements
|
92
|
+
elements = firstChild.xpath('.//groupfilter')
|
93
|
+
elements.each do |element|
|
94
|
+
function = element.attribute('function').text
|
95
|
+
emit "firstCHild\nfunction: #{function}\n node:\n#{element}"
|
96
|
+
if 'member'.eql? function
|
97
|
+
name = element.attribute('member').text.gsub(/^"|"$/,'')
|
98
|
+
emit "%%%% NAME:: #{name}"
|
99
|
+
alia = dataSource.fieldAlias(field,name) # $TableNameAliases[name]
|
100
|
+
results[name] = alia
|
101
|
+
end
|
102
|
+
if 'range'.eql? function
|
103
|
+
t = filtersFromRangeNode(dataSource, field, element)
|
104
|
+
t.each do |name,alia|
|
105
|
+
emit "RANGE ELEMENT Name: %-20s ALIAS: %-s " % [name, alia]
|
106
|
+
results[name] = dataSource.fieldAlias(field,name)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
results.each do |name,alia|
|
111
|
+
$sheetFieldsCSV << [ @twb.name, sheet.name, 'single', dataSource.uiname, field, name, alia, !name.eql?(alia) ]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
return results
|
115
|
+
end
|
116
|
+
|
117
|
+
def filtersFromRangeNode dataSource, field, node
|
118
|
+
unless @twbDomainsLoaded
|
119
|
+
loadDomains
|
120
|
+
end
|
121
|
+
emit "filtersFromRangeNode"
|
122
|
+
emit " from: #{node.attribute('from')}"
|
123
|
+
emit " to. : #{node.attribute('to')}"
|
124
|
+
from = node.attribute('from').text.gsub(/^"|"$/,'')
|
125
|
+
to = node.attribute( 'to').text.gsub(/^"|"$/,'')
|
126
|
+
emit " from: #{from}"
|
127
|
+
emit " to. : #{to}"
|
128
|
+
filtersInRange dataSource, field, from, to
|
129
|
+
end
|
130
|
+
|
131
|
+
def filtersInRange dataSource, field, from, to
|
132
|
+
emit "filtersInRange"
|
133
|
+
results = {}
|
134
|
+
dsFields = @twbFielddomains[dataSource.uiname]
|
135
|
+
emit "dsFields : #{dsFields}"
|
136
|
+
if dsFields.nil? || dsFields.empty?
|
137
|
+
emit "#### ALERT - FIELD DOMAIN VALUES FOR DATASOURCE #{dataSource.uiname} NOT LOADED ####"
|
138
|
+
emit @twbFieldDomains
|
139
|
+
emit "==========="
|
140
|
+
emit dsFields
|
141
|
+
emit "==========="
|
142
|
+
else
|
143
|
+
fieldVals = dsFields[field].to_a
|
144
|
+
if dataSource.fieldHasAliases field
|
145
|
+
#-- resolve aliases
|
146
|
+
dbValues = SortedSet.new
|
147
|
+
aliases = dataSource.fieldAliases field
|
148
|
+
fieldVals.each do |fv|
|
149
|
+
fvAliased = aliases.has_value? fv
|
150
|
+
if fvAliased
|
151
|
+
dbValues << aliases.key(fv)
|
152
|
+
else
|
153
|
+
dbValues << fv
|
154
|
+
end
|
155
|
+
end
|
156
|
+
$fieldVals = dbValues.to_a
|
157
|
+
else
|
158
|
+
#-- use domain values as returned
|
159
|
+
$fieldVals = dsFields[field].to_a
|
160
|
+
end
|
161
|
+
# domainVals = dsFields[field].to_a
|
162
|
+
# #-- need to dealias (unalias?) the field domain values
|
163
|
+
# dbVals = SortedSet.new
|
164
|
+
# domainVals.each do |dv|
|
165
|
+
emit "field values: #{$fieldVals}"
|
166
|
+
unless $fieldVals.nil? || $fieldVals.empty?
|
167
|
+
values = $fieldVals
|
168
|
+
f_i = values.index from
|
169
|
+
t_i = values.index to
|
170
|
+
emit " from: #{f_i} :: '#{from}'"
|
171
|
+
emit " to: #{t_i} :: '#{to}'"
|
172
|
+
badRange = f_i.nil? || t_i.nil?
|
173
|
+
emit "badRange: #{badRange}"
|
174
|
+
if badRange
|
175
|
+
emit "BAD RANGE"
|
176
|
+
else
|
177
|
+
tnames = values[f_i..t_i]
|
178
|
+
tnames.each do |tname|
|
179
|
+
results[tname] = dataSource.deAlias(field,tname) # $TableNameAliases[tname]
|
180
|
+
end
|
181
|
+
emit " filtersInRange f:%-35s t:%-s " % ["'#{from}:#{f_i}'", "'#{to}:#{t_i}'"]
|
182
|
+
emit " names: #{results.keys}"
|
183
|
+
emit " aliases: #{results.values}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
return results
|
188
|
+
end
|
189
|
+
|
190
|
+
def loadDomains
|
191
|
+
emit "def loadDomains\n=="
|
192
|
+
loader = Twb::Util::FieldDomainLoader.new
|
193
|
+
@twbFielddomains = loader.loadWorkbook @twb
|
194
|
+
emit "#{@twbFielddomains}\n=="
|
195
|
+
@twbDomainsLoaded = true
|
196
|
+
end
|
197
|
+
|
198
|
+
# def emit(local=@localEmit, stuff)
|
199
|
+
# if stuff.is_a? String then
|
200
|
+
# lines = stuff.split(/\n/)
|
201
|
+
# lines.each do |line|
|
202
|
+
# @ttlogfile.puts "#{$emitPrefix}#{line}"
|
203
|
+
# puts "#{$emitPrefix}#{line}" if local
|
204
|
+
# end
|
205
|
+
# else
|
206
|
+
# @ttlogfile.puts "#{$emitPrefix}#{stuff}"
|
207
|
+
# puts "#{$emitPrefix}#{stuff}" if local
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
end # class
|
212
|
+
|
213
|
+
end # module Twb
|
214
|
+
end # module Analysis
|
data/lib/twb/calculatedfield.rb
CHANGED
@@ -14,15 +14,16 @@
|
|
14
14
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
15
|
|
16
16
|
require 'nokogiri'
|
17
|
+
require 'digest/md5'
|
17
18
|
|
18
19
|
module Twb
|
19
20
|
|
20
|
-
class CalculatedField
|
21
|
+
class CalculatedField < TabClass
|
21
22
|
|
22
23
|
attr_reader :dataSource
|
23
24
|
attr_reader :node, :properties
|
24
|
-
attr_reader :caption, :name, :uiname
|
25
|
-
attr_reader :datatype, :role, :
|
25
|
+
attr_reader :caption, :name, :uiname
|
26
|
+
attr_reader :datatype, :role, :propType
|
26
27
|
attr_reader :calculation, :calcFields
|
27
28
|
attr_reader :hidden
|
28
29
|
|
@@ -36,7 +37,7 @@ module Twb
|
|
36
37
|
# --
|
37
38
|
@datatype = @node.attribute('datatype').text
|
38
39
|
@role = @node.attribute('role').text
|
39
|
-
@
|
40
|
+
@propType = @node.attribute('type').text # n.b. 'type' is used as a proxy for class
|
40
41
|
# --
|
41
42
|
@calculation = Twb::FieldCalculation.new(self, datasource)
|
42
43
|
# --
|
@@ -47,7 +48,7 @@ module Twb
|
|
47
48
|
@properties ||= loadProperties
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
+
def calcFields
|
51
52
|
@calculation.calcFields
|
52
53
|
end
|
53
54
|
|
@@ -69,9 +70,23 @@ module Twb
|
|
69
70
|
@properties[name] = attr.value
|
70
71
|
end
|
71
72
|
@properties[:uiname] = @uiname
|
73
|
+
@properties[:uuid] = uuid
|
72
74
|
return @properties
|
73
75
|
end
|
74
76
|
|
77
|
+
def id
|
78
|
+
@id ||= @id = "#{@dataSource.uiname}::#{@uiname}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# def uuid
|
82
|
+
# @uuid ||= loadUUID
|
83
|
+
# end
|
84
|
+
|
85
|
+
# def loadUUID
|
86
|
+
# dsn = @dataSource.nil? ? 'NO DATASOURCE' : dataSource.uuid
|
87
|
+
# @uuid = Digest::MD5.hexdigest("#{dsn}::@name").hash
|
88
|
+
# end
|
89
|
+
|
75
90
|
def to_s
|
76
91
|
"%s(%s) => %s" % [uiname, name, @calculation.formulaFlat]
|
77
92
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copyright (C) 2014, 2015, 2017 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 'nokogiri'
|
17
|
+
require 'digest/md5'
|
18
|
+
require 'csv'
|
19
|
+
|
20
|
+
module Twb
|
21
|
+
|
22
|
+
class CodedField
|
23
|
+
|
24
|
+
include Comparable
|
25
|
+
|
26
|
+
attr_reader :dataSource
|
27
|
+
attr_reader :name, :techCode, :rawCode
|
28
|
+
|
29
|
+
def initialize code
|
30
|
+
#puts "\n\nCodedField :: #{code}"
|
31
|
+
@rawCode = code
|
32
|
+
trimmed = code.gsub(/^"|"$/,'').gsub(/^\[|\]$/,'')
|
33
|
+
parts = trimmed.split('].[')
|
34
|
+
#puts "Field: #{code} parts: #{parts.length} - #{parts.inspect}"
|
35
|
+
#puts " p1: #{parts[0]}"
|
36
|
+
#puts " p2: #{parts[1]}"
|
37
|
+
if parts.length == 1
|
38
|
+
#puts '==1'
|
39
|
+
@name = parts[0]
|
40
|
+
@techCode = "[#{@name}]"
|
41
|
+
else # parts.length <> 1
|
42
|
+
#puts '<>1'
|
43
|
+
#puts "p[0]: #{parts[0]}"
|
44
|
+
#puts "p[1]: #{parts[1]}"
|
45
|
+
@dataSource = parts[0]
|
46
|
+
fldName = parts[1]
|
47
|
+
if fldName.start_with?(':') && fldName.count(':') == 1
|
48
|
+
@name = fldName
|
49
|
+
else
|
50
|
+
parseField fldName
|
51
|
+
end
|
52
|
+
@techCode = "[#{@dataSource}].[#{@name}]"
|
53
|
+
end
|
54
|
+
end # initialize
|
55
|
+
|
56
|
+
def parseField str
|
57
|
+
# puts "parseField: #{str}"
|
58
|
+
parts = str.split(':')
|
59
|
+
# puts "parseField: #{str}"
|
60
|
+
# puts " parts : #{parts}"
|
61
|
+
# puts " partsl: #{parts.length}"
|
62
|
+
# puts " p[0]: #{parts[0]}"
|
63
|
+
# puts " p[1]: #{parts[1]}"
|
64
|
+
case parts.length
|
65
|
+
when 1
|
66
|
+
@name = parts[0]
|
67
|
+
else
|
68
|
+
@name = parts[1]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def id
|
73
|
+
@id ||= @id = "#{@dataSourceName}::#{@uiname}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def <=>(other)
|
77
|
+
# myName = @uiname.nil? ? '' : @uiname
|
78
|
+
# otherName = other.uiName.nil? ? "" : other.uiName
|
79
|
+
# ##puts "#{@uiname} / #{myName} <=> #{otherName} / #{other.uiName}"
|
80
|
+
# ##puts "#{@uiname.nil?} // #{other.uiName.nil?}"
|
81
|
+
# myName <=> otherName
|
82
|
+
@fqName <=> other.techCode
|
83
|
+
end
|
84
|
+
|
85
|
+
end # class CalculationField
|
86
|
+
|
87
|
+
end # module Twb
|
data/lib/twb/columnfield.rb
CHANGED
@@ -17,7 +17,7 @@ require 'nokogiri'
|
|
17
17
|
|
18
18
|
module Twb
|
19
19
|
|
20
|
-
class ColumnField
|
20
|
+
class ColumnField < TabClass
|
21
21
|
|
22
22
|
include Comparable
|
23
23
|
|
@@ -54,10 +54,10 @@ module Twb
|
|
54
54
|
attr_reader :alias, :semanticRole, :aggregation
|
55
55
|
attr_reader :autoColumn, :hidden, :datatypeCustomized
|
56
56
|
attr_reader :calcField
|
57
|
+
attr_reader :aliases
|
57
58
|
|
58
59
|
|
59
60
|
def initialize(fieldNode, datasource=nil)
|
60
|
-
|
61
61
|
@datasource = datasource
|
62
62
|
@node = fieldNode
|
63
63
|
@name = load 'name'
|
@@ -79,6 +79,10 @@ module Twb
|
|
79
79
|
@calcField = loadCalcField
|
80
80
|
end
|
81
81
|
|
82
|
+
def id
|
83
|
+
@id ||= @id = @name.hash
|
84
|
+
end
|
85
|
+
|
82
86
|
def load nodeName
|
83
87
|
attr = @node.attribute(nodeName)
|
84
88
|
val = attr.nil? ? nil : attr.text.strip.gsub(/^\[|\]$/,'')
|
@@ -135,6 +139,21 @@ module Twb
|
|
135
139
|
@commentLines.empty?
|
136
140
|
end
|
137
141
|
|
142
|
+
def aliases
|
143
|
+
@aliases ||= loadAliases
|
144
|
+
end
|
145
|
+
|
146
|
+
def loadAliases
|
147
|
+
@aliases = {}
|
148
|
+
aliasNodes = @node.xpath('.//alias')
|
149
|
+
aliasNodes.each do |node|
|
150
|
+
key = node.attribute('key').text.gsub(/^"|"$/,'')
|
151
|
+
value = node.attribute('value').text.gsub(/^"|"$/,'')
|
152
|
+
@aliases[key] = value
|
153
|
+
end
|
154
|
+
return @aliases
|
155
|
+
end
|
156
|
+
|
138
157
|
def properties
|
139
158
|
@properties ||= loadProperties
|
140
159
|
end
|