twb 3.7.5 → 3.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,10 +21,11 @@ module Twb
21
21
  class CalculatedField < TabClass
22
22
 
23
23
  attr_reader :dataSource
24
- attr_reader :node, :properties
25
- attr_reader :caption, :name, :uiname
26
- attr_reader :datatype, :role, :propType
27
- attr_reader :calculation, :calcFields
24
+ attr_reader :node, :properties
25
+ attr_reader :caption, :name, :uiname
26
+ attr_reader :datatype, :role, :propType
27
+ attr_reader :calculation, :calcFields
28
+ attr_reader :isGroup, :groupMembers
28
29
  attr_reader :hidden
29
30
 
30
31
  def initialize(calcNode, datasource=nil)
@@ -42,6 +43,7 @@ module Twb
42
43
  @calculation = Twb::FieldCalculation.new(self, datasource)
43
44
  # --
44
45
  @hidden = true if calcNode.has_attribute?('caption')
46
+ @isGroup = !@node.at_xpath('./calculation[@class="categorical-bin"]').nil?
45
47
  end
46
48
 
47
49
  def properties
@@ -64,6 +66,22 @@ module Twb
64
66
  @calculation.formulaResolved
65
67
  end
66
68
 
69
+ def groupMembers
70
+ @groupMembers ||= loadgroupmembers
71
+ end
72
+
73
+ def binValues binName
74
+ values = []
75
+ binValue = "\"#{binName}\""
76
+ binNode = @node.at_xpath("./calculation[@class='categorical-bin']/bin[@value='#{binValue}']")
77
+ unless binNode.nil?
78
+ binNode.xpath('.//value').each do |v|
79
+ values << v.text.gsub(/^['"]|['"]$/,'')
80
+ end
81
+ end
82
+ return values
83
+ end
84
+
67
85
  def loadProperties
68
86
  @properties= {}
69
87
  @node.attributes.each do |name,attr|
@@ -91,5 +109,25 @@ module Twb
91
109
  "%s(%s) => %s" % [uiname, name, @calculation.formulaFlat]
92
110
  end
93
111
 
112
+ private
113
+
114
+ def loadgroupmembers
115
+ @groupMembers = Hash.new { |h,k| h[k] = [] }
116
+ if @isGroup
117
+ groupLeads = @node.xpath('./calculation[@class="categorical-bin"]//bin')
118
+ groupLeads.each do |gl|
119
+ lead = gl['value']
120
+ groupAlias = @node.at_xpath("./aliases/alias[@key='#{lead}']")
121
+ groupNamex = groupAlias.nil? ? lead : groupAlias['value']
122
+ groupName = groupNamex.gsub(/^['"]|['"]$/,'')
123
+ values = gl.xpath('./value')
124
+ values.each do |v|
125
+ @groupMembers[groupName] << v.text.gsub(/^['"]|['"]$/,'').gsub('\"','"')
126
+ end
127
+ end
128
+ end
129
+ return @groupMembers
130
+ end
131
+
94
132
  end # class
95
133
  end # module
@@ -24,12 +24,13 @@ module Twb
24
24
  include Comparable
25
25
 
26
26
  attr_reader :dataSource
27
- attr_reader :name, :techCode, :rawCode
27
+ attr_reader :name, :techCode, :function, :rawCode
28
28
 
29
29
  def initialize code
30
30
  #puts "\n\nCodedField :: #{code}"
31
31
  @rawCode = code
32
- trimmed = code.gsub(/^"|"$/,'').gsub(/^\[|\]$/,'')
32
+ trimmed = code.gsub(/^['"]|['"]$/,'').gsub(/^\[|\]$/,'')
33
+ # puts "trimmed: #{trimmed}"
33
34
  parts = trimmed.split('].[')
34
35
  #puts "Field: #{code} parts: #{parts.length} - #{parts.inspect}"
35
36
  #puts " p1: #{parts[0]}"
@@ -38,12 +39,12 @@ module Twb
38
39
  #puts '==1'
39
40
  @name = parts[0]
40
41
  @techCode = "[#{@name}]"
41
- else # parts.length <> 1
42
+ elsif # parts.length <> 1
42
43
  #puts '<>1'
43
44
  #puts "p[0]: #{parts[0]}"
44
45
  #puts "p[1]: #{parts[1]}"
45
- @dataSource = parts[0]
46
- fldName = parts[1]
46
+ @dataSource = parts[0]
47
+ fldName = parts[1]
47
48
  if fldName.start_with?(':') && fldName.count(':') == 1
48
49
  @name = fldName
49
50
  else
@@ -56,21 +57,21 @@ module Twb
56
57
  def parseField str
57
58
  # puts "parseField: #{str}"
58
59
  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
60
  case parts.length
65
61
  when 1
66
- @name = parts[0]
62
+ @name = parts[0]
67
63
  else
68
- @name = parts[1]
64
+ @name = parts[-2]
65
+ @function = parts[0]
69
66
  end
70
67
  end
71
68
 
72
69
  def id
73
- @id ||= @id = "#{@dataSourceName}::#{@uiname}"
70
+ @id ||= @id = "#{@dataSource}::#{@uiname}"
71
+ end
72
+
73
+ def to_s
74
+ "ds:#{dataSource}|n:#{name}|tc:#{techCode}"
74
75
  end
75
76
 
76
77
  def <=>(other)
@@ -432,6 +432,10 @@ module Twb
432
432
  dbFieldsMap.has_key? fieldName
433
433
  end
434
434
 
435
+ def field fieldName
436
+ dbFieldsMap[fieldName]
437
+ end
438
+
435
439
  def fieldTable fieldName
436
440
  loadTableFields if @tableFieldsMap.nil?
437
441
  dbField = @tableFieldsMap[fieldName]
@@ -17,29 +17,63 @@ require 'logger'
17
17
 
18
18
  module TabTool
19
19
 
20
- attr_accessor :ttdocdir, :logger, :loglevel, :logfilename
21
- attr_reader :funcdoc, :docfiles, :metrics
20
+ @@licensed = false
21
+
22
+ TTDOCDIR = './ttdoc'
22
23
 
23
- TTDOCDIR = './ttdoc'
24
+ attr_accessor :ttdocdir, :logger, :loglevel, :logfilename
25
+ attr_reader :licensed, :funcdoc, :docfiles, :metrics, :alerts
24
26
 
25
27
  @funcdoc = {:class=>nil, :blurb=>nil, :description=>nil,}
26
28
  @docfiles = [] # should be of form [{:name=>'docFileName',:description=>'doc file description'}]
27
29
 
28
- @ttdocdir = './ttdoc'
29
- @logfilename = 'TabTools.ttlog'
30
- @loglevel = Logger::DEBUG
31
- @localEmit = false
32
- @docDirSet = false
30
+ # @logfilename = 'TabTools.ttlog'
31
+ @@loglevel = Logger::INFO
32
+ # @localEmit = false
33
+ # @docDirSet = false
33
34
 
34
- def funcdoc
35
- @funcdoc.nil? ? {:class=>'n/a', :blurb=>'generic TabTool blurb', :description=>'A useful Tableau Tool.'} : @funcdoc
35
+ def init
36
+ @alerts = []
37
+ initDocDir
38
+ # initLogger
39
+ end
40
+
41
+ def initDocDir
42
+ # return if TTDOCDIR.nil?
43
+ # return if ''.eql?($ttdocdir) && ''.eql?(TTDOCDIR)
44
+ @docDir = TTDOCDIR
45
+ return if Dir.exists?(@docDir)
46
+ if File.exists? @docDir
47
+ @docDir = ''
48
+ else
49
+ Dir.mkdir @docDir
50
+ end
51
+ return @docDir
52
+ end
53
+
54
+ def initLogger
55
+ logFileName = docFile("#{self.class.to_s.split('::').last}.ttlog")
56
+ @logger = Logger.new(logFileName, 2, 100*1024)
57
+ @logger.level = Logger::INFO
58
+ return @logger
36
59
  end
37
60
 
38
61
  def docFile name
39
- initDocDir unless @docDirSet
40
62
  @docDir.nil? ? name : "#{@docDir}/#{name}"
41
63
  end
42
64
 
65
+ def license= fileName
66
+ @@licensed = fileName.is_a?(String) && File.exist?(fileName)
67
+ end
68
+
69
+ def licensed?
70
+ @@licensed
71
+ end
72
+
73
+ def funcdoc
74
+ @funcdoc.nil? ? {:class=>'n/a', :blurb=>'generic TabTool blurb', :description=>'A useful Tableau Tool.'} : @funcdoc
75
+ end
76
+
43
77
  def docfiles
44
78
  @docfiles ||= @docfiles = []
45
79
  end
@@ -66,16 +100,18 @@ module TabTool
66
100
  lines << " - %-#{nameLen}s %-s " % [ dfi[:name], dfi[:description] ]
67
101
  end
68
102
  end
69
- docLines = lines.empty? ? [] : [' ','For documentation and generated data see the following:',' ']
103
+ docLines = lines.empty? ? [] : [' ',' For documentation and generated data see the following:',' ']
70
104
  lines.each do |l|
71
105
  docLines << l
72
106
  end
73
107
  return docLines
74
108
  end
75
109
 
110
+ # def metrics
111
+ # {}
112
+ # end
113
+
76
114
  def initCSV(fileName, desc=nil, header=nil)
77
- # puts 'initCSV'
78
- # puts " @docDirSet: #{@docDirSet} "
79
115
  csvName = docFile(fileName)
80
116
  emit "init CSV #{csvName}"
81
117
  csvFile = CSV.open(csvName, 'w')
@@ -85,48 +121,28 @@ module TabTool
85
121
  end
86
122
 
87
123
  def emit(local=@localEmit, stuff)
88
- initDocDir if @docDirSet.nil? || !@docDirSet
89
- initLogger if @logger.nil?
124
+ # if @logger.closed?
125
+ # @logger.reopen
126
+ # end
90
127
  if stuff.is_a? String then
91
128
  lines = stuff.split(/\n/)
92
129
  lines.each do |line|
93
- @logger.debug "#{@emitPrefix}#{line}"
130
+ @logger.debug "#{@emitPrefix}#{line}" unless @logger.nil?
94
131
  puts "#{@emitPrefix}#{line}" if local
95
132
  end
96
133
  else
97
- @logger.debug "#{@emitPrefix}#{stuff}"
134
+ @logger.debug "#{@emitPrefix}#{stuff}" unless @logger.nil?
98
135
  puts "#{@emitPrefix}#{stuff}" if local
99
136
  end
100
137
  end
101
138
 
102
- def initLogger
103
- initDocDir unless @docDirSet
104
- initDocDir
105
- logFileName = docFile("#{self.class.to_s.split('::').last}.ttlog")
106
- @logger = Logger.new(logFileName)
107
- @logger.level = Logger::DEBUG
139
+ def alert str
140
+ @alerts << str
141
+ emit "#{self.class} :: #{str}"
108
142
  end
109
143
 
110
- def initDocDir
111
- # puts 'initDocDir - begin'
112
- # puts " @docDirSet: #{@docDirSet} "
113
- # puts " TTDOCDIR : #{TTDOCDIR} "
114
- # puts " $ttdocdir : #{$ttdocdir} "
115
- # puts " @docDir : #{@docDir} "
116
- return if @docDirSet
117
- return if TTDOCDIR.nil? && $ttdocdir.nil?
118
- return if ''.eql?($ttdocdir) && ''.eql?(TTDOCDIR)
119
- @docDir = $ttdocdir.nil? ? TTDOCDIR : $ttdocdir
120
- return if Dir.exists?(@docDir)
121
- if File.exists? @docDir
122
- @docDir = nil
123
- return
124
- end
125
- Dir.mkdir @docDir
126
- @docDirSet = true
127
- # puts " @docDirSet: #{@docDirSet} "
128
- # puts " @docDir : #{@docDir} "
129
- # puts 'initDocDir - end'
144
+ def finis
145
+ # @logger.close unless @logger.nil? || @logger.closed?
130
146
  end
131
147
 
132
148
 
@@ -20,6 +20,7 @@ require 'creek'
20
20
  require 'csv'
21
21
 
22
22
  class FieldDomainLoader
23
+ include TabTool
23
24
 
24
25
  @@xmlLocation = './ttdoc'
25
26
 
@@ -27,6 +28,7 @@ require 'csv'
27
28
  attr_accessor :xmllocation, :workboook, :datasource, :csvOption
28
29
 
29
30
  def initialize
31
+ init
30
32
  reset
31
33
  end
32
34
 
@@ -82,7 +84,7 @@ require 'csv'
82
84
  end
83
85
  end
84
86
  else
85
- puts "#### ALERT #### XLSX file does not exist: #{fileName}"
87
+ alert "#### ALERT #### Twb:'#{@workbook}' DS: '#{@datasource}' DomRef: #{fileName}' file does not exist."
86
88
  end
87
89
  return fieldDomains
88
90
  end
@@ -25,6 +25,7 @@ module Twb
25
25
  attr_reader :node, :name, :datasourcenames, :datasources
26
26
  attr_reader :panesCount
27
27
  attr_reader :fields, :rowFields, :colFields, :paneFields, :datasourceFields
28
+ attr_reader :hidden, :visible
28
29
 
29
30
  def initialize sheetNode
30
31
  @node = sheetNode
@@ -64,6 +65,14 @@ module Twb
64
65
  # @fields.nil? ? loadFields : @fields
65
66
  end
66
67
 
68
+ def hidden
69
+ @hidden ||= resolveHidden
70
+ end
71
+
72
+ def visible
73
+ @visible ||= !hidden
74
+ end
75
+
67
76
  def loadFields
68
77
  # puts "WORKSHEET loadFields"
69
78
  @fields = {}
@@ -121,7 +130,13 @@ module Twb
121
130
  def datasourcenames
122
131
  @datasources.keys
123
132
  end
124
- end
133
+
134
+ def resolveHidden
135
+ windowNode = node.at_xpath("//windows/window[@name='#{@name}']")
136
+ @hidden = !windowNode.nil? && 'true' == windowNode['hidden']
137
+ end
138
+
139
+ end # class Worksheet
125
140
 
126
141
  class WorksheetDataSource
127
142
  # --
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: 3.7.5
4
+ version: 3.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Gerrard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-31 00:00:00.000000000 Z
11
+ date: 2018-08-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A sollection of Ruby classes designed for accessing and recording information
14
14
  about, and for manipulating, Tableau Workbooks and their contents.
@@ -27,12 +27,15 @@ files:
27
27
  - lib/twb/analysis/CalculatedFields/CSVEmitter.rb
28
28
  - lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb
29
29
  - lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb
30
+ - lib/twb/analysis/CalculatedFields/groupfieldsanalyzer.rb
30
31
  - lib/twb/analysis/DataSources/DataSourceFieldsCSVEmitter.rb
31
32
  - lib/twb/analysis/DataSources/DataSourceTableFieldsCSVEmitter.rb
32
33
  - lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb
33
34
  - lib/twb/analysis/DocumentedFieldsCSVEmitter.rb
34
35
  - lib/twb/analysis/DocumentedFieldsMarkdownEmitter.rb
35
36
  - lib/twb/analysis/Sheets/WorksheetDataStructureCSVEmitter.rb
37
+ - lib/twb/analysis/Sheets/analyzeDashboardSheets.rb
38
+ - lib/twb/analysis/Sheets/dashsheetsanalyzer.rb
36
39
  - lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb
37
40
  - lib/twb/analysis/Sheets/sheetfiltersanalyzer.rb
38
41
  - lib/twb/calculatedfield.rb