twb 4.9.4 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@
16
16
  require 'nokogiri'
17
17
  require 'digest/md5'
18
18
  require 'csv'
19
+ require 'pry'
19
20
 
20
21
  module Twb
21
22
 
@@ -35,7 +36,7 @@ module Twb
35
36
  attr_reader :is_tableCalc
36
37
  attr_reader :is_lod, :lodCodePos
37
38
  attr_reader :class, :scopeIsolation
38
- attr_reader :fields, :remoteFields, :calcFields
39
+ attr_reader :fields, :remoteFields, :referencedFields
39
40
  attr_reader :comments, :uuid
40
41
 
41
42
  # attr_accessor :ttlogfile
@@ -120,59 +121,33 @@ module Twb
120
121
  end
121
122
 
122
123
  def formulaResolved
123
- @formulaResolved ||= @formulaResolved = resolveFormula
124
+ @formulaResolved ||= resolveFormula
124
125
  end
125
126
 
126
127
  def resolveFormula
127
- # puts "\ndef resolveFormula:\n--\n#{@formula}"
128
- formula = @formula
129
- parseFormFields # - extracts the fields from the formula; as persisted they're the internal names
130
- @calcFields.each do |calcField|
131
- if calcField.techUIdiff
132
- # puts ":::: #{calcField.techCode} // #{calcField.uiCode}"
133
- formula = formula.gsub(calcField.techCode,calcField.uiCode)
134
- # puts ":--: #{formula}"
135
- end
128
+ # emit "\ndef resolveFormula:\n--\n#{@formula}"
129
+ resolved = @formula
130
+ # emit "\t formula:#{resolved}:"
131
+ # parseFormFields # - extracts the fields from the formula; as persisted they're the internal names
132
+ referencedFields.each do |refField|
133
+ # emit "\t refField: "
134
+ resolved.gsub!(refField.techCode,refField.uiCode)
135
+ # if calcField.techUIdiff
136
+ # # puts ":::: #{calcField.techCode} // #{calcField.uiCode}"
137
+ # formula = formula.gsub(calcField.techCode,calcField.uiCode)
138
+ # # puts ":--: #{formula}"
139
+ # end
136
140
  end
137
- return formula
141
+ # emit "\t formula:#{resolved}:"
142
+ return resolved
138
143
  end
139
144
 
140
- def calcFields
141
- @calcFields ||= parseFormFields
145
+ def referencedFields
146
+ @referencedFields ||= parseFormFields
142
147
  end
143
148
 
144
- def parseFormFields
145
- # puts "--parseFormFields"
146
- @fields = Set.new
147
- @calcFields = Set.new
148
- formula = @formulaFlat
149
- if !formula.nil? && formula.include?('[') && formula.include?(']')
150
- fields = Set.new
151
- # noSqLits = formula.gsub( /'[\[\.\]]+'/, ' ')
152
- quotes = formula.gsub('"',"'")
153
- noSqLits = quotes.gsub( /'[\[\.\]]+'/, ' ')
154
- flatForm = noSqLits.gsub( /\n/, ' ')
155
- stripFrt = flatForm.gsub( /^[^\[]*[\[]/ , '[' )
156
- stripBck = stripFrt.gsub( /\][^\]]+$/ , ']' )
157
- stripMid = stripBck.gsub( /\][^\]]{2,}\[/ , ']]..[[' )
158
- stripCom = stripMid.gsub( /\][ ]*,[ ]*\[/ , ']]..[[' )
159
- stripFns = stripMid.gsub( /\][ ]*[\*\/+\-><,=][ ]*\[/ , ']]..[[' )
160
- fields = stripFns.split(']..[')
161
- emit "::self::: #{self} :: #{__LINE__} :: fields:'#{fields.inspect}'"
162
- fields.each do |field|
163
- emit "::self::: #{self} :: #{__LINE__} :: field:'#{field}'"
164
- cf = CalculationField.new( field.gsub(/^\[|\]$/, ''), @dataSource )
165
- @calcFields.add cf
166
- @fields.add field.gsub(/^\[|\]$/, '')
167
- end
168
- end
169
- return @calcFields
170
- end
171
149
 
172
150
  def formulaResolvedLines
173
- # puts "\ndef formulaResolvedLines\n--\n#{formulaResolved}"
174
- # puts "--\n#{formulaResolved.split(/\n|\r\n/)}"
175
- # puts "--\n#{formulaResolved.split(/\n|\r\n/)}"
176
151
  formulaResolved.split(/\n|\r\n/)
177
152
  end
178
153
 
@@ -212,11 +187,149 @@ module Twb
212
187
  return comments.strip
213
188
  end
214
189
 
215
- end # class FieldCalculation
190
+ private
216
191
 
217
192
 
193
+ def pullString chars
194
+ delim1 = chars.shift
195
+ delim2 = delim1+delim1
196
+ field = delim1
197
+ done = false
198
+ until done | chars.empty?
199
+ s01 = chars[0..1].join
200
+ if !delim1.eql? chars[0]
201
+ field += chars.shift
202
+ else
203
+ case s01
204
+ when delim2
205
+ field += delim2
206
+ chars.shift(2)
207
+ when delim1
208
+ field += delim1
209
+ chars.shift
210
+ done = true
211
+ else
212
+ field += delim1
213
+ chars.shift
214
+ done = true
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ def pullField chars
221
+ # chars = str.split ''
222
+ done = false
223
+ ds = ''
224
+ field = ''
225
+ until done
226
+ s01 = chars[0..1].join
227
+ s02 = chars[0..2].join
228
+ if ']'.eql? chars[0]
229
+ case s01
230
+ when ']]'
231
+ field += ']]'
232
+ chars.shift(2)
233
+ when ']'
234
+ field += chars.shift
235
+ done = true
236
+ else
237
+ if '].['.eql?(s02)
238
+ ds = field + ']'
239
+ chars.shift(2)
240
+ # fldstr = chars.join
241
+ field = pullField(chars)[:field]
242
+ done = true
243
+ else
244
+ field += ']'
245
+ chars.shift
246
+ done = true
247
+ end
248
+ end
249
+ else
250
+ field += chars[0]
251
+ chars.shift
252
+ end
253
+ end
254
+ # puts "field: '#{field}' \t\t ds: #{ds}"
255
+ return {:field => field.sub(/\[/,'').sub(/\]$/,''), :ds => ds.sub(/\[/,'').sub(/\]$/,'') }
256
+ end
218
257
 
219
- class CalculationField
258
+ def parseFormFields # formula
259
+ @referencedFields = Array.new
260
+ rawFields = Array.new
261
+ if !@formula.nil? && @formula.include?('[') && @formula.include?(']')
262
+ chars = formula.split('')
263
+ until chars.empty?
264
+ char0 = chars[0]
265
+ case char0
266
+ when '"', "'"
267
+ pullString(chars)
268
+ when '['
269
+ rawFields << pullField(chars)
270
+ else
271
+ unless chars.nil? | chars.empty?
272
+ chars.shift
273
+ end
274
+ end
275
+ end
276
+ rawFields.each do |rf|
277
+ ds = rf[:ds]
278
+ dataSource = if ''.eql? ds
279
+ @dataSource
280
+ else
281
+ @dataSource.workbook.datasource(ds)
282
+ end
283
+ # fieldUIName = dataSource.fieldUIName(rf[:field])
284
+ refField = ReferencedField.new(rf[:field], dataSource)
285
+ @referencedFields << refField
286
+ end
287
+ end
288
+ return @referencedFields
289
+ end
290
+
291
+ def parseFormFieldsx # formula
292
+ rawFields = Set.new
293
+ if !@formula.nil? && @formula.include?('[') && @formula.include?(']')
294
+ noComms = @formula.gsub(/\/\/.*\r\n/,' ')
295
+ formBase = noComms.gsub(/\r\n/,' ')
296
+ formLen = formBase.length
297
+ formChars = formBase.split ''
298
+ until formChars.empty?
299
+ c = formChars.shift
300
+ case c
301
+ when '"', "'"
302
+ pullString(formChars, c)
303
+ when '['
304
+ rawFields << pullField(formChars, ']', @referencedFields)
305
+ end
306
+ end
307
+ end
308
+ @referencedFields = Set.new
309
+ rawFields.each do |rf|
310
+ # @referencedFields << rf
311
+ dataSource = if ''.eql? rf[:ds]
312
+ @dataSource
313
+ else
314
+ @dataSource.workbook.datasource(rf[:ds])
315
+ end
316
+ # if dataSource.nil?
317
+ # binding.pry
318
+ # end
319
+ fieldUIName = dataSource.fieldUIName(rf[:field])
320
+ # binding.pry
321
+ refField = ReferencedField.new(rf[:field], dataSource)
322
+ # binding.pry
323
+ @referencedFields << refField
324
+ end
325
+ return @referencedFields
326
+ end
327
+
328
+ end # class FieldCalculation
329
+
330
+
331
+ # class CalculationField
332
+ class ReferencedField
220
333
  # is a field used in a calculation, resolved into its human-meaningful form
221
334
 
222
335
  include Comparable
@@ -228,65 +341,29 @@ module Twb
228
341
  attr_reader :fqName, :type
229
342
  attr_reader :techUIdiff
230
343
 
231
- def initialize code, datasource
232
- # puts "\n\nCalculationField :: %-25s | %s " % [datasource.uiname, code]
344
+ def initialize name, datasource
345
+ # puts "\n\nReferencedField :: ds: %-25s | n: %s " % [datasource, name]
346
+ @name = name
233
347
  @dataSource = datasource
234
- @dataSourceName = datasource.uiname
348
+ @dataSourceName = datasource.nil? ? nil : datasource.uiname
235
349
  @dataSourceRef = :local
236
350
  @dataSourceExists = true
351
+ @techCode = "[#{name}]"
237
352
  @techUIdiff = false
238
- @uiname = ''
239
- rawCode = code.gsub(/^\[|\]$/,'')
240
- parts = rawCode.split('].[')
241
- #puts "Field: #{code} \t parts: #{parts.length} - #{parts.inspect}"
242
- if parts.length == 1
243
- @name = parts[0]
244
- @techCode = "[#{parts[0]}]"
245
- #puts "@name: #{@name}"
246
- if datasource.nil?
247
- # puts 'a'
248
- @uiname = @name
249
- @uiCode = @techCode
250
- @techUIdiff = false
251
- else # !datasource.nil?
252
- # puts 'b'
253
- #puts "b - found uiname for '#{@name}'?: #{!datasource.fieldUIName(@name).nil?} \t is:#{datasource.fieldUIName(@name)} "
254
- @uiname = datasource.fieldUIName(@name).nil? ? @name : datasource.fieldUIName(@name)
255
- @uiCode = @uiname.nil? ? @techCode : "[#{@uiname}]"
256
- @techUIdiff = !@techCode.eql?(@uiCode)
257
- # puts ":b #{datasource.fieldUIName(@name).nil?} ... #{@name} ... #{@uiname}"
258
- # puts "CalculationField :: uin: %-25s | @name:%-s" % [@uiname,@name]
259
- end
260
- else # parts.length <> 1
261
- # puts 'c'
262
- rdstech = parts[0]
263
- calcField = parts[1]
264
- @uiname = calcField
265
- @dataSourceName = rdstech
266
- @dataSourceRef = :remote
267
- @techCode = "[#{rdstech}].[#{calcField}]"
268
- workbook = datasource.workbook
269
- @dataSource = workbook.nil? ? nil : workbook.datasource(rdstech)
270
- # puts "\t twb: #{workbook.class} / remoteds: #{remoteds.class} : #{remoteds.nil? ? "<<NOT FOUND:#{rdstech}:>>" : remoteds.uiname} "
271
- #--
272
- if @dataSource.nil? || @dataSource.fieldUIName(calcField).nil?
273
- # puts 'd'
274
- @uiname = calcField
275
- @uiCode = "[<<NOT FOUND>>#{rdstech}].[#{calcField}]"
276
- @techUIdiff = true
277
- @dataSourceExists = false
278
- else # !remoteds.nil?
279
- # puts 'e'
280
- @dataSourceName = @dataSource.uiname
281
- @uiname = @dataSource.fieldUIName(calcField)
282
- @uiCode = "[#{@dataSourceName}].[#{@uiname}]"
283
- @techUIdiff = !@techCode.eql?(@uiCode)
284
- @dataSourceExists = true
285
- end
353
+ if dataSource.nil?
354
+ # puts 'a'
355
+ @uiname = @name
356
+ @uiCode = @techCode
357
+ @techUIdiff = false
358
+ else # !datasource.nil?
359
+ # puts 'b'
360
+ # puts "b - found uiname for '#{@name}'?: #{!datasource.fieldUIName(@name).nil?} \t is:#{datasource.fieldUIName(@name)} "
361
+ @uiname = datasource.fieldUIName(@name).nil? ? @name : datasource.fieldUIName(@name)
362
+ @uiCode = @uiname.nil? ? @techCode : "[#{@uiname}]"
363
+ @techUIdiff = !@techCode.eql?(@uiCode)
364
+ # puts ":b #{datasource.fieldUIName(@name).nil?} ... #{@name} ... #{@uiname}"
365
+ # puts "CalculationField :: uin: %-25s | @name:%-s" % [@uiname,@name]
286
366
  end
287
- # puts "\t dsName: #{@dataSourceName}"
288
- # puts "\t @name: #{@name}"
289
- # puts "\t uiname: #{@uiname}"
290
367
  @fqName = "#{@dataSourceName}::#{@uiname}"
291
368
  @type = if @dataSource.nil?
292
369
  :CalculatedField
@@ -308,6 +385,6 @@ module Twb
308
385
  @fqName <=> other.fqName
309
386
  end
310
387
 
311
- end # class CalculationField
388
+ end # class ReferencedField
312
389
 
313
390
  end # module Twb
@@ -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;')
@@ -16,7 +16,9 @@
16
16
  require 'nokogiri'
17
17
 
18
18
  #require 'twb'
19
- require 'C:\tech\Tableau\tools\Ruby\gems\twb\lib\twb.rb'
19
+ # require 'C:\tech\Tableau\tools\Ruby\gems\twb\lib\twb.rb'
20
+ # require 'C:\tech\Tableau\Tableau Tools\Ruby\gems\twb\lib\twb.rb'
21
+ require 'twb'
20
22
  require "test/unit"
21
23
 
22
24
  system "cls"
@@ -25,10 +27,11 @@ class TestFieldCalculation < Test::Unit::TestCase
25
27
 
26
28
  def test_fragment1
27
29
  doc = Nokogiri::XML::Document.parse <<-EOHTML
28
- <calculation class='tableau' formula='abc' />
30
+ <calculation class='tableau' name='I am a formular field' formula='abc' datatype='datatype' role='' type='' class='calcfield' />
29
31
  EOHTML
30
- calcNode = doc.at_xpath('./calculation')
31
- calc = Twb::FieldCalculation.new(calcNode)
32
+ calcNode = doc.at_xpath('./calculation')
33
+ calcField = Twb::CalculatedField.new calcNode
34
+ calc = Twb::FieldCalculation.new(calcField)
32
35
  assert(!calc.nil?)
33
36
  #puts "node: #{calcNode}"
34
37
  #puts "formula: #{calc.formula}"
@@ -41,10 +44,11 @@ EOHTML
41
44
 
42
45
  def test_fragment2
43
46
  doc = Nokogiri::XML::Document.parse <<-EOHTML
44
- <calculation class='tableau' formula='// this is the number of days between the order and shipment&#13;&#10;&#13;&#10;datediff(&apos;day&apos;,[Order Date] , [other].[Ship Date])' />
47
+ <calculation class='tableau' name='Another formula fied' formula='// this is the number of days between the order and shipment&#13;&#10;&#13;&#10;datediff(&apos;day&apos;,[Order Date] , [other].[Ship Date])' />
45
48
  EOHTML
46
49
  calcNode = doc.at_xpath('./calculation')
47
- calc = Twb::FieldCalculation.new(calcNode)
50
+ calcField = Twb::CalculatedField calcNode
51
+ calc = Twb::FieldCalculation.new(calcField)
48
52
  assert(!calc.nil?)
49
53
  #puts "node: #{calcNode}"
50
54
  #puts "formula: #{calc.formula}"
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: 5.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-09 00:00:00.000000000 Z
11
+ date: 2020-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: creek
@@ -58,14 +58,17 @@ 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
64
65
  - lib/twb/analysis/calculatedfields/calculatedfieldsanalyzer.rb
65
66
  - lib/twb/analysis/calculatedfields/csvemitter.rb
67
+ - lib/twb/analysis/calculatedfields/dotanalyzer.rb
66
68
  - lib/twb/analysis/calculatedfields/fieldsaliasesanalyzer.rb
67
69
  - lib/twb/analysis/calculatedfields/groupfieldsanalyzer.rb
68
70
  - lib/twb/analysis/calculatedfields/markdownemitter.rb
71
+ - lib/twb/analysis/calculatedfields/t.rb
69
72
  - lib/twb/analysis/datasources/categoricalcolorcodinganalyzer.rb
70
73
  - lib/twb/analysis/datasources/datasourcefieldsanalyzer.rb
71
74
  - lib/twb/analysis/datasources/datasourcefieldscsvemitter.rb
@@ -82,6 +85,7 @@ files:
82
85
  - lib/twb/analysis/documentedfieldscsvemitter.rb
83
86
  - lib/twb/analysis/documentedfieldsmarkdownemitter.rb
84
87
  - lib/twb/analysis/sheets/analyzedashboardsheets.rb
88
+ - lib/twb/analysis/sheets/dashboardsummarizer.rb
85
89
  - lib/twb/analysis/sheets/dashsheetsanalyzer.rb
86
90
  - lib/twb/analysis/sheets/sheetfieldsanalyzer.rb
87
91
  - lib/twb/analysis/sheets/sheetfiltersanalyzer.rb