class Twb::Workbook

A Tableau Workbook and its parts.

Attributes

actions[R]
base[R]
build[R]
dashboards[R]
dataSourceNamesMap[R]
datasource[R]
datasourceNames[R]
datasourceUINames[R]
datasources[R]
dir[R]
modtime[R]
name[R]
ndoc[R]
node[R]
orphanDataSources[R]
parameters[R]
platform[R]
storyboards[R]
type[R]
valid[R]
version[R]
workbooknode[R]
worksheets[R]

Public Class Methods

new(twbWithDir) click to toggle source

Creates a Workbook from its file name.

Parameters:

twbWithDir

The Workbook's file name, the Workbook can be a TWB or TWBX file.
# File lib/twb/workbook.rb, line 46
def initialize twbWithDir
  raise ArgumentError.new("ERROR in Workbok creation: '#{twbWithDir}' must be a String, is a #{twbWithDir.class} \n ")        unless twbWithDir.is_a? String
  raise ArgumentError.new("ERROR in Workbok creation: '#{twbWithDir}' must have an extension of .twb or .twbx \n ")           unless twbWithDir.upcase.end_with?(".TWB", ".TWBX")
  raise ArgumentError.new("ERROR in Workbok creation: '#{twbWithDir}' must must be a file, is a Directory\\Folder \n ")           if File.directory?(twbWithDir)
  raise ArgumentError.new("ERROR in Workbok creation: '#{twbWithDir}' cannot be found, must be a Tableau Workbook file. \n ") unless File.file?(twbWithDir)
  @valid = false
  if File.file?(twbWithDir) then
    @name    = File.basename(twbWithDir)
    @dir     = File.dirname(File.expand_path(twbWithDir))
    @modtime = File.new(twbWithDir).mtime.strftime("%Y-%m-%d %H:%M:%S")
    case File.extname(twbWithDir)
      when '.twb'  then processTWB(twbWithDir)
      when '.twbx' then processTWBX(twbWithDir)
    end
  end
end

Public Instance Methods

actionNames() click to toggle source
# File lib/twb/workbook.rb, line 103
def actionNames
  @actions.keys
end
addDocDashboard(docDashboard) click to toggle source

Add a new Documentation Dashboard to the TWB. Ensure that the TWB has a <dashboards> node (it may not). Make sure that the new Doc Dashboard's name doesn't conflict with an existing Dashboard - increment the incoming name if necessary. Add Doc Dashboard's <dashboard> and <window> nodes to the TWB; there's always a <windows> node in the TWB.

# File lib/twb/workbook.rb, line 135
def addDocDashboard docDashboard
  ensureDashboardsNodeExists
  ensureWindowsNodeExists
  title = getNewDashboardTitle(docDashboard.title)
  docDashboard.title=(title) unless title == docDashboard.title
  @dashesNode.add_child(docDashboard.dashnode)
  @windowsnode.add_child(docDashboard.winnode)
end
dashboard(name) click to toggle source
# File lib/twb/workbook.rb, line 95
def dashboard name
  @dashboards[name]
end
dashboardNames() click to toggle source
# File lib/twb/workbook.rb, line 91
def dashboardNames
  @dashboards.keys
end
id() click to toggle source
# File lib/twb/workbook.rb, line 63
def id
    @id ||= @id = @name.hash
end
release() click to toggle source
# File lib/twb/workbook.rb, line 71
def release
  @build ||= loadBuild
end
storyboard(name) click to toggle source
# File lib/twb/workbook.rb, line 127
def storyboard name
  @storyboards[name]
end
storyboardNames() click to toggle source
# File lib/twb/workbook.rb, line 123
def storyboardNames
  @storyboards.keys
end
worksheet(name) click to toggle source
# File lib/twb/workbook.rb, line 79
def worksheet name
  @worksheets[name]
end
worksheetNames() click to toggle source
# File lib/twb/workbook.rb, line 83
def worksheetNames
  @worksheets.keys
end
write(name=@name) click to toggle source

Write the TWB to a file, with an optional name. Can be used to write over the existing TWB (dangerous), or to a new file (preferred).

# File lib/twb/workbook.rb, line 146
def write(name=@name)
  case @type
  when :twb 
    writeTwb(name)
  when :twbx 
    writeTwbx(name)
  else
    emit  "Cannot write this Workbook - it has an invalid type: #{@type}"
    raise "Cannot write this Workbook - it has an invalid type: #{@type}"
  end
end
writeAppend(str) click to toggle source

Write the TWB to a file, appending the base name with the provided string. Intended for use when making adjustments to the TWB without overwriting the original.

# File lib/twb/workbook.rb, line 160
def writeAppend(str)
  newName = @name.sub(/[.]twb$/,'') + str.gsub(/^[.]*/,'.') + '.twb'
  write newName
end

Private Instance Methods

ensureDashboardsNodeExists() click to toggle source

Make sure that the TWB has a <dashboards> node. It's possible for a TWB to have no dashboards, and therefore no <dashboards> node.

# File lib/twb/workbook.rb, line 311
def ensureDashboardsNodeExists
  if @dashesNode.nil?
    @dashesNode = Nokogiri::XML::Node.new "dashboards", @ndoc
    # TODO fix this @dataSourcesNode.add_next_sibling(@dashesNode)
  end
end
ensureWindowsNodeExists() click to toggle source
# File lib/twb/workbook.rb, line 318
def ensureWindowsNodeExists
  if @windowsnode.nil?
    @windowsnode = Nokogiri::XML::Node.new "windows", @ndoc
    # TODO fix this @dataSourcesNode.add_next_sibling(@windowsnode)
  end
end
getNewDashboardTitle(t) click to toggle source
# File lib/twb/workbook.rb, line 325
def getNewDashboardTitle(t)
  title = t
  if @datasources.include?(title)
    inc = 0
    loop do
      inc+=1
      title = t + ' ' + inc.to_s
      if !@datasources.include?(title)
        break
      end
    end
  end
  return title
end
identifyOrphandatasoUrceS() click to toggle source
# File lib/twb/workbook.rb, line 286
def identifyOrphandatasoUrceS
  sheetDataSources = Set.new
  @worksheets.values.each do |sheet|
    sheet.datasources.each do |ds|
        sheetDataSources << ds.uiname
    end
  end
  @orphanDataSources = @datasourceUINames - sheetDataSources
end
loadActions() click to toggle source
# File lib/twb/workbook.rb, line 277
def loadActions
  @actions = {}
  actionNodes = @ndoc.xpath("//workbook/actions/action")
  actionNodes.each do |anode|
    action = Twb::Action.new(anode, @workbooknode)
    @actions[action.uiname] = action
  end
end
loadBuild() click to toggle source
# File lib/twb/workbook.rb, line 197
def loadBuild
  # - earlier Version, need to confirm when source-build began
  #   @build   = @ndoc.xpath('/workbook/comment()').text.gsub(/^[^0-9]+/,'').strip
  @build = if !@ndoc.at_xpath('/workbook/@source-build').nil?
               @ndoc.at_xpath('/workbook/@source-build').text
           else 
               if @ndoc.at_xpath('/workbook/comment()').nil?
                  'not found'
               else
                  @ndoc.at_xpath('/workbook/comment()').text.gsub(/^[^0-9]+/,'').strip
              end
           end
end
loadDashboards() click to toggle source
# File lib/twb/workbook.rb, line 246
def loadDashboards
  @dashesNode = @ndoc.at_xpath('//workbook/dashboards')
  @dashboards = {}
  dashes = @ndoc.xpath('//workbook/dashboards/dashboard').to_a
  dashes.each do |node|
    unless node.attr('type') == 'storyboard' then
      dashboard = Twb::Dashboard.new(node, @worksheets)
      @dashboards[dashboard.name] = dashboard
    end
  end
end
loadParameters() click to toggle source
# File lib/twb/workbook.rb, line 340
def loadParameters
  @parameters = {}
  paramsDS = ndoc.at_xpath('./workbook/datasources/datasource[@name="Parameters"]')
  unless paramsDS.nil?
    paramNodes = paramsDS.xpath('.//column')
    paramNodes.each do |pn|
      parameter = Twb::Parameter.new pn
      @parameters[parameter.name] = parameter
    end
  end
  return @parameters
end
loadStoryboards() click to toggle source
# File lib/twb/workbook.rb, line 258
def loadStoryboards
  @storyboards = {}
  boards = @ndoc.xpath("//workbook/dashboards/dashboard[@type='storyboard']" ).to_a
  boards.each do |node|
    sheet = Twb::Storyboard.new(node)
    @storyboards[sheet.name] = sheet
  end
end
loadWindows() click to toggle source
# File lib/twb/workbook.rb, line 267
def loadWindows
  @windowsnode = @ndoc.at_xpath("//workbook/windows")
  @windows = {}
  windows  = @ndoc.xpath("//workbook/windows/window[@name]")
  windows.each do |node|
    window = Twb::Window.new(node)
    @windows[window.name] = window
  end
end
loadWorksheets() click to toggle source
# File lib/twb/workbook.rb, line 232
def loadWorksheets
  @worksheets  = {}
  hiddenSheets = []
  @ndoc.xpath('//workbook/windows/window[@hidden="true"]').each do |hs|
    hiddenSheets << hs['name']
  end
  sheets = @ndoc.xpath('//workbook/worksheets/worksheet' ).to_a
  sheets.each do |node|
    sheet = Twb::Worksheet.new(node, self)
    sheet.hidden = hiddenSheets.include? sheet.name 
    @worksheets[sheet.name] = sheet
  end
end
loaddatasources() click to toggle source
# File lib/twb/workbook.rb, line 211
def loaddatasources
  # puts "LOAD DATA SOURCES"
  # @dataSourcesNode = @ndoc.at_xpath('//workbook/datasources')
  @datasources        = Set.new
  @datasourceNames    = SortedSet.new
  @datasourceUINames  = SortedSet.new
  @dataSourceNamesMap = {}
  datasourceNodes     = @ndoc.xpath('//workbook/datasources/datasource')
  # puts "DATASOURCENODES : #{@datasourceNodes.length}"
  datasourceNodes.each do |node|
    datasource = Twb::DataSource.new(node,self)
    @datasources << datasource
    @datasourceNames    << datasource.name
    @datasourceNames    << datasource.uiname
    @datasourceUINames  << datasource.uiname
    @dataSourceNamesMap[datasource.name]   = datasource 
    @dataSourceNamesMap[datasource.uiname] = datasource 
  end
  # puts "DATASOURCES    : #{@datasources.length}"
end
processDoc() click to toggle source
# File lib/twb/workbook.rb, line 182
def processDoc
  @node         = @ndoc.at_xpath('//workbook')
  @workbooknode = @node
  @version      = @node.nil? ? nil : @node["version"]
  @platform     = @node.nil? ? nil : @node["source-platform"].nil? ? nil : @node["source-platform"].capitalize
  @base         = @node.nil? ? nil : @node["base"]
  loaddatasources
  loadWorksheets
  loadDashboards
  loadStoryboards
  loadWindows
  loadActions
  @valid = true
end
processTWB(twbFile) click to toggle source
# File lib/twb/workbook.rb, line 176
def processTWB(twbFile)
  @ndoc = Nokogiri::XML(open(twbFile))
  @type = :twb
  processDoc
end
processTWBX(twbxWithDir) click to toggle source
# File lib/twb/workbook.rb, line 167
def processTWBX(twbxWithDir)
  Zip::File.open(twbxWithDir) do |zip_file|
    twb   = zip_file.glob('*.twb').first
    @ndoc = Nokogiri::XML(twb.get_input_stream)
    @type = :twbx
    processDoc
  end
end
writeTwb(name=@name) click to toggle source
# File lib/twb/workbook.rb, line 296
def writeTwb(name=@name)
  $f = File.open(name,'w')
  if $f
      $f.puts @ndoc
      $f.close
  end
  return name
end
writeTwbx(name=@name) click to toggle source
# File lib/twb/workbook.rb, line 305
def writeTwbx(name=@name)
    emit  "Writing the Workbook, need implementation"
end