twb 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8aae5b5038ecc0eade737b33b274b8a05dd3cc94
4
- data.tar.gz: 161e0430d5558f2151f04be57a79a1ddb9e8c02a
3
+ metadata.gz: 4680a8b2c0894aed8b9da0a4d6ba3fd0070c3008
4
+ data.tar.gz: 07d8a00756ff29178a6a331fe129737a563f5c24
5
5
  SHA512:
6
- metadata.gz: 297a5b3feadd0ad310843a4308883e7a74971ecb200b31450cabd568cba460fbd7b7b1dfb09a401f8f82e3612618310ded0c1c7049217d84f26f4592418ef44b
7
- data.tar.gz: 8ae0b5c9b192d3f9796fe7f9bee9cc09cd2b7bd415692903d6861d34d24c39239c0fc230b69b60b0edef7d6b2e842b745ae62d3b1968b0b2b50f8baffde4b9a6
6
+ metadata.gz: 9451fdcfcbc401ec98eb42c978621c76db842a3b785bf1d896c3283b55cdd2d524f1f2d52ff1c416b9c042efa3c3de140eab4bdc727e1be604790a30646e7a86
7
+ data.tar.gz: 12376fde72224cee30b7c0ceb2141f017b1a7cbb8991ba70c4dc4ba05748990a3b135212e6409b4f810c56705e983c210d3a90f6b31c185ef336003efd0d4fdc
data/lib/twb.rb CHANGED
@@ -40,5 +40,5 @@ require_relative 'twb/analysis/calculatedfieldsanalyzer'
40
40
  # Represents Tableau Workbooks and their contents.
41
41
  #
42
42
  module Twb
43
- VERSION = '1.0.1'
43
+ VERSION = '1.0.4'
44
44
  end
@@ -1,4 +1,4 @@
1
- # TTC_CalculatedFields.rb - this Ruby script Copyright 2017 Christopher Gerrard
1
+ # calculatedfieldsanalyzer.rb - this Ruby script Copyright 2017 Christopher Gerrard
2
2
  #
3
3
  # This program is free software: you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -111,7 +111,6 @@ DOTHEADER
111
111
  def processTWB twbWithDir
112
112
  twb = File.basename(twbWithDir)
113
113
  @twb = Twb::Workbook.new twbWithDir
114
- puts " - #{twbWithDir}"
115
114
  emit "- Workbook: #{twbWithDir}"
116
115
  emit " version: #{@twb.version}"
117
116
  return if twbWithDir.end_with? == "Tableau Calculated Fields Analyses.twb"
@@ -144,7 +143,7 @@ DOTHEADER
144
143
  calculationNodes = ds.calculatedFields
145
144
  emit "calculationNodes : nil? '#{calculationNodes.nil?}'" # - len '#{calculationNodes.length}'"
146
145
  calculationNodes.each do |calcNode|
147
- calculation = Twb::FieldCalculation.new calcNode
146
+ calculation = Twb::FieldCalculation.new(calcNode, ds)
148
147
  emit "HANDLING CALCULATION NODE:"
149
148
  emit calcNode.attributes
150
149
  #-- field names --
@@ -39,7 +39,7 @@ module Twb
39
39
  attr_reader :name, :caption, :uiname, :dsclass
40
40
  attr_reader :connection, :connHash
41
41
  attr_reader :tables
42
- attr_reader :localfields, :metadatafields, :mappedFields, :fieldUINames, :calculatedFields
42
+ attr_reader :localfields, :metadatafields, :mappedFields, :fieldUINames, :calculatedFields
43
43
  attr_reader :filters
44
44
  attr_reader :node
45
45
 
@@ -19,34 +19,66 @@ module Twb
19
19
 
20
20
  class FieldCalculation
21
21
 
22
- attr_reader :node, :fieldNode
23
- attr_reader :formula, :formulaLines, :formulaFlat
24
- attr_reader :uiname, :techname, :caption
22
+ attr_reader :node, :fieldNode, :dataSource
23
+ attr_reader :formula, :resolvedFormula, :formulaLines, :formulaFlat
24
+ attr_reader :uiname, :techname, :caption
25
25
  attr_reader :class, :scopeIsolation
26
- attr_reader :fields, :resolvedFields
26
+ attr_reader :fields, :resolvedFields, :remoteFields
27
27
  attr_reader :comments
28
28
 
29
- def initialize calcNode
29
+ def initialize(calcNode, datasource=nil)
30
30
  if calcNode
31
31
  @node = calcNode
32
- @fieldNode = @node.xpath('..')
33
- # field names
34
- @caption, = attribText(@fieldNode, 'caption')
35
- @techname = @fieldNode.attribute('name').text.gsub(/^\[|\]$/,'') # assumes the name attribute exists
36
- @uiname = @caption.nil? ? @techName : @caption
37
- #-- Calculation --
38
- @has_formula = @node.has_attribute?('formula')
39
- if @has_formula
40
- @formula = @node.attribute('formula').text
41
- @formulaLines = formula.split(/\n|\r\n/)
42
- @formulaFlat = flattenFormula(formulaLines)
43
- @comments = getComments(formulaLines)
32
+ @fieldNode = @node.at_xpath('..')
33
+ @dataSource = datasource
34
+ @class = attribText(@node, 'class')
35
+ @remoteFields = {}
36
+ if 'categorical-bin'.eql? @class
37
+ # puts calcNode
38
+ # <calculation class='categorical-bin'
39
+ # column='[Calculation_507569757376950272]'
40
+ # default='&quot;Other&quot;'
41
+ # new-bin='true'>
42
+ @techname = calcNode.attribute('column').text.gsub(/^\[|\]$/,'') # assumes the column attribute exists
43
+ @caption = attribText(@fieldNode, 'caption')
44
+ uiname = if datasource.nil?
45
+ @techName
46
+ else
47
+ datasource.fieldUIName(@techname)
48
+ end
49
+ @uiname = "#{uiname} (group)"
50
+ @formula = "grouped '#{uiname}' values"
51
+ @comments = [ ]
52
+ @resolvedFields = [ {:field => uiname, :fieldui => uiname, :source => nil} ]
53
+ else
54
+ # field names
55
+ # puts "\n****** "
56
+ # puts " fnode: #{@fieldNode}\n****** "
57
+ @caption = @fieldNode.attribute('caption').nil? ? nil : @fieldNode.attribute('caption').text
58
+ @techname = @fieldNode.attribute('name').text.gsub(/^\[|\]$/,'') # assumes the name attribute exists
59
+ @uiname = @caption.nil? ? @techname : @caption
60
+ # puts " caption: #{@caption}"
61
+ # puts "techname: #{@techname}"
62
+ # puts " uiname: #{@uiname}"
63
+ #--
64
+ @scopeIsolation = attribText(@node, 'scope-isolation')
65
+ #-- Formula --
66
+ @has_formula = @node.has_attribute?('formula')
67
+ if @has_formula
68
+ @formula = @node.attribute('formula').text
69
+ @formulaLines = formula.split(/\n|\r\n/)
70
+ @formulaFlat = flattenFormula(@formulaLines)
71
+ @comments = getComments(@formulaLines)
72
+ elsif @class.eql? 'categorical-bin'
73
+ @formula = '<<Group>>'
74
+ @formulaLines = [ @formula ]
75
+ @formulaFlat = [ @formula ]
76
+ @comments = [ ]
77
+ end
78
+ #-- Fields --
79
+ parseFormFields # establishes @ fields
80
+ resolveFields # establishes @ resolvedFields
44
81
  end
45
- @class = attribText(@node, 'class')
46
- @scopeIsolation = attribText(@node, 'scope-isolation')
47
- #-- Fields --
48
- parseFormFields # establishes @ fields
49
- resolveFields # establishes @ resolvedFields
50
82
  end
51
83
  end
52
84
 
@@ -54,11 +86,11 @@ module Twb
54
86
  node.attribute(attribute).nil? ? nil : node.attribute(attribute).text
55
87
  end
56
88
 
57
-
89
+
58
90
  def parseFormFields
59
91
  @fields = Set.new []
60
92
  formula = formulaFlat
61
- if formula.include?('[') && formula.include?(']')
93
+ if !formula.nil? && formula.include?('[') && formula.include?(']')
62
94
  noSqLits = formula.gsub(/'[\[\.\]]+'/, ' ')
63
95
  flatForm = noSqLits.gsub( /\n/, ' ')
64
96
  stripFrt = flatForm.gsub( /^[^\[]*[\[]/ , '[' )
@@ -74,18 +106,55 @@ module Twb
74
106
 
75
107
  def resolveFields
76
108
  @resolvedFields = []
77
- fields.each do |field|
109
+ @fields.each do |field|
78
110
  rawField = field.gsub(/^\[|\]$/,'')
79
111
  parts = rawField.split('].[')
80
112
  if parts.length > 1
81
- hash = { :field => parts[1], :source => parts[0] }
113
+ source = parts[0]
114
+ fieldCalc = parts[1]
115
+ fieldui = fieldCalc
82
116
  else
83
- hash = { :field => parts[0], :source => nil }
117
+ source = nil
118
+ fieldCalc = parts[0]
119
+ fieldui = @dataSource.fieldUIName(fieldCalc)
120
+ end
121
+ hash = { :field => fieldCalc, :fieldui => fieldui, :source => source }
122
+ @resolvedFields << hash
123
+ end
124
+ end
125
+
126
+
127
+ def resolvedFormula
128
+ @resolvedFormula ||= resolveFormula
129
+ end
130
+
131
+ def resolveFormula
132
+ # puts "resolveFormula :\n-- formula --\n %s \n-- @dataSource.nil? : %s \n-- @resolvedFields.nil? : %s \n--" % [ @formula, @dataSource.nil?, @resolvedFields.nil? ]
133
+ formula = @formula
134
+ unless @dataSource.nil? || @formula.nil? || @resolvedFields.nil?
135
+ @resolvedFields.each do |rf|
136
+ field = rf[:field]
137
+ source = rf[:source]
138
+ # puts " field: #{field}"
139
+ # puts " src: #{source}"
140
+ if source.nil?
141
+ fieldInternal = field # "[#{rf[:field]}]"
142
+ fieldUI = @dataSource.fieldUIName(field)
143
+ # puts " f?: #{formula.include?(field)}"
144
+ # puts " fui: #{fieldUI}"
145
+ formula = formula.gsub(field,fieldUI) unless fieldUI.nil?
146
+ # puts "formula:\n--\n#{formula}"
147
+ else
148
+ @remoteFields[source] = SortedSet.new unless @remoteFields.include? source
149
+ @remoteFields[source].add field
150
+ end
84
151
  end
85
- @resolvedFields << hash unless hash.nil?
86
152
  end
153
+ # puts "resolvedFormula:\n==\n#{formula}\n--"
154
+ return formula
87
155
  end
88
156
 
157
+
89
158
  def flattenFormula lines
90
159
  formula = ''
91
160
  lines.each do |line|
@@ -94,7 +163,8 @@ module Twb
94
163
  end
95
164
  return formula.strip
96
165
  end
97
-
166
+
167
+
98
168
  def getComments lines
99
169
  comments = ''
100
170
  lines.each do |line|
@@ -105,6 +175,7 @@ module Twb
105
175
  return comments.strip
106
176
  end
107
177
 
108
- end
109
178
 
110
- end
179
+ end # class FieldCalculation
180
+
181
+ end # module Twb
@@ -15,19 +15,19 @@
15
15
 
16
16
  module Twb
17
17
  module Util
18
-
18
+
19
19
  class DotFileRenderer
20
20
  @@gvDotLocation = 'C:\\tech\\graphviz\\Graphviz2.38\\bin\\dot.exe'
21
- @@renderTypes = ['pdf', 'png', 'svg']
21
+ @@renderTypes = [:pdf, :png, :svg]
22
22
 
23
23
  def initialize
24
24
  @gvDotLocation = @@gvDotLocation
25
25
  end
26
-
26
+
27
27
  def gvDotLocation=(location)
28
28
  @gvDotLocation = location
29
29
  end
30
-
30
+
31
31
  def renderAll(dotFile)
32
32
  renderedFiles = []
33
33
  @@renderTypes.each do |type|
@@ -35,12 +35,11 @@ module Util
35
35
  end
36
36
  return renderedFiles
37
37
  end
38
-
38
+
39
39
  def render(dotFile, type)
40
- type = type.downcase
41
40
  if @@renderTypes.include?(type)
42
- typeParam = '-T' + type
43
- renderedFile = dotFile.sub(/.dot$/,'') + '.' + type
41
+ typeParam = '-T' + type.to_s
42
+ renderedFile = dotFile.sub(/.dot$/,'') + '.' + type.to_s
44
43
  renderedFileParam = '-o' + renderedFile
45
44
  #puts "\t <render cmd> system #{@gvDotLocation}, #{typeParam}, #{renderedFileParam}, #{dotFile} "
46
45
  system @gvDotLocation, typeParam, renderedFileParam, dotFile
@@ -30,17 +30,18 @@ module Util
30
30
  @@typeColors = { :CalculatedField => 'fillcolor=lightskyblue3',
31
31
  :DBTable => 'fillcolor=steelblue',
32
32
  :TwbDataConnection => 'fillcolor=cornflowerblue',
33
- :DatabaseField => 'fillcolor=steelblue',
33
+ :DatabaseField => 'fillcolor=grey',
34
34
  }
35
35
 
36
+ # not currently used
36
37
  @@typeStyles = { :CalculatedField => 'style=filled',
37
38
  :DBTable => 'style=filled',
38
39
  :TwbDataConnection => 'style=filled',
39
40
  :DatabaseField => 'style=filled'
40
41
  }
41
42
 
43
+ # @id - the technical fully qualified identifier, distinquishes the node from similarly named nodes
42
44
  # @name - the visible name
43
- # @id - the technical identifier, used to distinquish the node from similarly named nodes
44
45
  # @type - useful for categorizing the node
45
46
  attr_reader :id, :type, :name
46
47
  attr_reader :cypherID, :cypherCreate
@@ -73,10 +74,7 @@ module Util
73
74
 
74
75
 
75
76
  def dotLabel
76
- # "JIRA 1::JIRA 1.csv" [label="JIRA 1.csv"]
77
- # style = @type =~ /Data Source|DB Table|Database Field/ ? "style=filled" : ''
78
- # style = @type =~ /Data Source|DB Table|Database Field/ ? "style=filled" : ''
79
- "\"%s\" [label=\"%s\" %s %s %s ]" % [id, name, @@typeShapes[@type], 'style=filled', @@typeColors[@type]]
77
+ "\"%s\" [label=\"%s\" %s %s ]" % [id, name.gsub('"','\"'), @@typeShapes[@type], @@typeColors[@type]]
80
78
  end
81
79
 
82
80
 
@@ -15,33 +15,33 @@
15
15
 
16
16
  module Twb
17
17
  module Util
18
-
18
+
19
19
  class DotFileRenderer
20
20
  @@gvDotLocation = 'C:\\tech\\graphviz\\Graphviz2.38\\bin\\dot.exe'
21
- @@renderTypes = ['pdf', 'png', 'svg']
21
+ @@renderTypes = [:pdf, :png, :svg]
22
22
  def initialize
23
23
  @gvDotLocation = @@gvDotLocation
24
24
  end
25
-
25
+
26
26
  def gvDotLocation=(location)
27
27
  @gvDotLocation = location
28
28
  end
29
-
29
+
30
30
  def render dotFile
31
31
  renderedFiles = []
32
32
  @@renderTypes.each do |type|
33
33
  renderedFiles << render(dotFile,type)
34
34
  end
35
35
  end
36
-
36
+
37
37
  def render(dotFile,type)
38
38
  if @@renderTypes.includes(type)
39
- renderedFile = dotFile + '.' + type
40
- system "\"#{@gvDotLocation}\" -T#{type} -o\"#{renderedFile}\" \"#{dotFile}\""
39
+ renderedFile = dotFile + '.' + type.to_s
40
+ system "\"#{@gvDotLocation}\" -T#{type.to_s} -o\"#{renderedFile}\" \"#{dotFile}\""
41
41
  end
42
42
  return renderedFile
43
43
  end
44
-
44
+
45
45
  end
46
46
 
47
47
  def renderDot(twb,dot)
@@ -38,15 +38,11 @@ class TestDotFileRenderer < Test::Unit::TestCase
38
38
 
39
39
  def test_SpecifyType
40
40
  renderer = Twb::Util::DotFileRenderer.new
41
- renderedFile = renderer.render(@@testDotFile,'pdf')
41
+ renderedFile = renderer.render(@@testDotFile,:pdf)
42
42
  assert(!renderedFile.nil?)
43
- renderedFile = renderer.render(@@testDotFile,'png')
43
+ renderedFile = renderer.render(@@testDotFile,:png)
44
44
  assert(!renderedFile.nil?)
45
- renderedFile = renderer.render(@@testDotFile,'PnG') # should convert to 'png'
46
- assert(!renderedFile.nil?)
47
- renderedFile = renderer.render(@@testDotFile,'PNG') # should convert to 'png'
48
- assert(!renderedFile.nil?)
49
- renderedFile = renderer.render(@@testDotFile,'svg')
45
+ renderedFile = renderer.render(@@testDotFile,:svg)
50
46
  assert(!renderedFile.nil?)
51
47
  renderedFile = renderer.render(@@testDotFile,'xyz') # should fail
52
48
  assert(renderedFile.nil?)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard