twb 0.0.31 → 0.0.33

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.
Files changed (45) hide show
  1. data/bg.cmd +5 -0
  2. data/lib/twb.rb +7 -2
  3. data/lib/twb/dashboard.rb +7 -7
  4. data/lib/twb/datasource.rb +38 -9
  5. data/lib/twb/docdashboard.rb +123 -0
  6. data/lib/twb/field.rb +39 -0
  7. data/lib/twb/hashtohtml.rb +39 -0
  8. data/lib/twb/htmllistcollapsible.rb +154 -0
  9. data/lib/twb/localfield.rb +42 -0
  10. data/lib/twb/metadatafield.rb +55 -0
  11. data/lib/twb/util/UpLeftArrowsNav.png +0 -0
  12. data/lib/twb/util/hashtohtml.rb +45 -0
  13. data/lib/twb/util/htmllistcollapsible.rb +195 -0
  14. data/lib/twb/window.rb +31 -0
  15. data/lib/twb/workbook.rb +77 -12
  16. data/lib/twb/worksheet.rb +29 -1
  17. data/test/No Content.injected.twb +82 -0
  18. data/test/No Content.twb +68 -0
  19. data/test/No Dashboards.injected.twb +618 -0
  20. data/test/No Dashboards.twb +604 -0
  21. data/test/Special Documentation.html +198 -0
  22. data/test/TableauDocInlineCSS.html +165 -0
  23. data/test/UpLeftArrowsNav.png +0 -0
  24. data/test/Web Page Dashboards.injected.twb +1361 -0
  25. data/test/Web Page Dashboards.twb +1347 -0
  26. data/test/collapsibleList.html +198 -0
  27. data/test/testDocDashboard.rb +53 -0
  28. data/test/testDocDashboardCreate.rb +33 -0
  29. data/test/testHTMLList.rb +23 -0
  30. data/test/testTwbGem.rb +67 -0
  31. data/testTwbGem.rb +23 -9
  32. data/testTwbWrite.rb +22 -0
  33. data/twb-0.0.32.gem +0 -0
  34. metadata +29 -12
  35. data/twb-0.0.1.gem +0 -0
  36. data/twb-0.0.2.gem +0 -0
  37. data/twb-0.0.21.gem +0 -0
  38. data/twb-0.0.22.gem +0 -0
  39. data/twb-0.0.23.gem +0 -0
  40. data/twb-0.0.24.gem +0 -0
  41. data/twb-0.0.25.gem +0 -0
  42. data/twb-0.0.26.gem +0 -0
  43. data/twb-0.0.27.gem +0 -0
  44. data/twb-0.0.29.gem +0 -0
  45. data/twb-0.0.30.gem +0 -0
@@ -0,0 +1,42 @@
1
+ # Copyright (C) 2014, 2015 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
+
18
+ module Twb
19
+
20
+ # Assumption: A field can only be either a MetadataField or a LocalField, not both in a given Workbook data connection.
21
+
22
+ class LocalField
23
+
24
+ attr_reader :type, :node, :name, :datatype, :role, :type, :hidden, :caption, :aggregation, :uiname
25
+
26
+ def initialize fieldNode
27
+ @node = fieldNode
28
+ @type = 'local'
29
+ @name = @node.attr('name')
30
+ @datatype = @node.attr('datatype')
31
+ @role = @node.attr('role')
32
+ @type = @node.attr('type')
33
+ @hidden = @node.attr('hidden')
34
+ @caption = @node.attr('caption')
35
+ @aggregation = @node.attr('aggregation')
36
+ @uiname = if @caption.nil? || @caption == '' then @name else @caption end
37
+ return self
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright (C) 2014, 2015 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
+
18
+ module Twb
19
+
20
+ # Assumption: A field can only be either a MetadataField or a LocalField, not both in a given Workbook data connection.
21
+
22
+ class MetadataField
23
+
24
+ attr_reader :node, :aggregation, :containsnull, :localname, :localtype, :ordinal, :parentname, :precision, :remotealias, :remotename, :remotetype, :width, :name
25
+
26
+ def initialize fieldNode
27
+ @node = fieldNode
28
+ @aggregation = load 'aggregation'
29
+ @containsnull = load 'contains-null'
30
+ @localname = load 'local-name'
31
+ @localtype = load 'local-type'
32
+ @ordinal = load 'ordinal'
33
+ @parentname = load 'parent-name'
34
+ @precision = load 'precision'
35
+ @remotealias = load 'remote-alias'
36
+ @remotename = load 'remote-name'
37
+ @name = @remotename
38
+ @remotetype = load 'remote-type'
39
+ @width = load 'width'
40
+ return self
41
+ end
42
+
43
+ def load nodeName
44
+ node = @node.at_xpath(nodeName)
45
+ val = if node.nil? then node else node.text end
46
+ # puts "==== MD node:'#{nodeName}' \t nil?'#{node.nil?}' \t == val:#{val} \t = '#{node}' "
47
+ return val
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+
55
+
Binary file
@@ -0,0 +1,45 @@
1
+ class HashToHTMLList
2
+
3
+ def initialize(hash)
4
+ @hash = hash
5
+ @indent = " "
6
+ @tag_space = ""
7
+ @level = 0
8
+ @out = []
9
+ end
10
+
11
+ def append(tag,value=nil)
12
+ str = @indent * @level + "#{tag}"
13
+ str += @tag_space + "<a>" + value + "</a>" unless value.nil?
14
+ str += "\n"
15
+ @out << str
16
+ end
17
+
18
+ def ul(hash)
19
+ open_tag('ul') { li(hash) }
20
+ end
21
+
22
+ def li(collection)
23
+ @level += 1
24
+ collection.each do |key,value|
25
+ open_tag('li',key) { ul(value) if value.is_a?(Hash) || value.is_a?(Array) }
26
+ end
27
+ @level -= 1
28
+ end
29
+
30
+ def list
31
+ ul(@hash)
32
+ @out.join
33
+ end
34
+
35
+ def open_tag(tag,value=nil,&block)
36
+ append("<#{tag}>",value)
37
+ yield if block_given?
38
+ append("</#{tag}>")
39
+ end
40
+
41
+ def to_s
42
+ @out
43
+ end
44
+
45
+ end
@@ -0,0 +1,195 @@
1
+ # Copyright (C) 2014, 2015 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 'fileutils'
18
+ require_relative 'hashtohtml'
19
+
20
+ module Twb
21
+
22
+ class HTMLListCollapsible
23
+
24
+ @@doc = Nokogiri::HTML::Document.parse <<-COLLAPSIBLELIST
25
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
26
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
27
+ <head>
28
+ <title>Tableau Documentation</title>
29
+
30
+ <style type="text/css">
31
+ body, a {
32
+ color: #3B4C56;
33
+ font-family: sans-serif;
34
+ font-size: 14px;
35
+ text-decoration: none;
36
+ }
37
+ #pgtitle
38
+ {
39
+ margin: 0px 0px 20px;
40
+ font-size: 14pt;
41
+ text-align: center;
42
+ }
43
+ a{
44
+ cursor:pointer;
45
+ }
46
+ .tree ul {
47
+ list-style: none outside none;
48
+ }
49
+ .tree li a {
50
+ line-height: 25px;
51
+ }
52
+ .tree > ul > li > a {
53
+ color: #3B4C56;
54
+ display: block;
55
+ font-weight: normal;
56
+ position: relative;
57
+ text-decoration: none;
58
+ }
59
+ .tree li.parent > a {
60
+ padding: 0 0 0 28px;
61
+ }
62
+ .tree li.parent > a:before {
63
+ background-image: url("UpLeftArrowsNav.png");
64
+ background-position: 20px center;
65
+ content: "";
66
+ display: block;
67
+ height: 20px;
68
+ left: 0;
69
+ position: absolute;
70
+ top: 2px;
71
+ vertical-align: middle;
72
+ width: 20px;
73
+ }
74
+ .tree ul li.active > a:before {
75
+ background-position: 0 center;
76
+ }
77
+ .tree ul li ul {
78
+ border-left: 1px solid #D9DADB;
79
+ display: none;
80
+ margin: 0 0 0 12px;
81
+ overflow: hidden;
82
+ padding: 0 0 0 25px;
83
+ }
84
+ .tree ul li ul li {
85
+ position: relative;
86
+ }
87
+ .tree ul li ul li:before {
88
+ border-bottom: 1px dashed #E2E2E3;
89
+ content: "";
90
+ left: -20px;
91
+ position: absolute;
92
+ top: 12px;
93
+ width: 15px;
94
+ }
95
+ #wrapper {
96
+ margin: 0 auto;
97
+ width: 300px;
98
+ }
99
+ </style>
100
+
101
+ <script src="http://code.jquery.com/jquery-1.7.2.min.js" type="text/javascript" > </script>
102
+
103
+ <script type="text/javascript">
104
+ $( document ).ready( function( ) {
105
+ $( '.tree li' ).each( function() {
106
+ if( $( this ).children( 'ul' ).length > 0 ) {
107
+ $( this ).addClass( 'parent' );
108
+ }
109
+ });
110
+
111
+ $( '.tree li.parent > a' ).click( function( ) {
112
+ $( this ).parent().toggleClass( 'active' );
113
+ $( this ).parent().children( 'ul' ).slideToggle( 'fast' );
114
+ });
115
+
116
+ $( '#all' ).click( function() {
117
+
118
+ $( '.tree li' ).each( function() {
119
+ $( this ).toggleClass( 'active' );
120
+ $( this ).children( 'ul' ).slideToggle( 'fast' );
121
+ });
122
+ });
123
+
124
+ $( '.tree li' ).each( function() {
125
+ $( this ).toggleClass( 'active' );
126
+ $( this ).children( 'ul' ).slideToggle( 'fast' );
127
+ });
128
+
129
+ });
130
+
131
+ </script>
132
+
133
+ </head>
134
+ <body>
135
+ <div id="pgtitle">
136
+ Expandable nested list.
137
+ </div>
138
+ <div id="wrapper">
139
+ <div class="tree">
140
+ <button id="all">Toggle all</button>
141
+ <ul>
142
+ </ul>
143
+ </div>
144
+ </div>
145
+
146
+ </body>
147
+ </html>
148
+ COLLAPSIBLELIST
149
+
150
+ def initialize(hash)
151
+ @htmldoc = @@doc
152
+ @list = HashToHTMLList.new(hash).list
153
+ ul = @htmldoc.at_xpath('//ul')
154
+ ul.replace(@list)
155
+ end
156
+
157
+ def title=(str)
158
+ title = @htmldoc.at_xpath('//div[@id="pgtitle"]')
159
+ title.content = str if title
160
+ end
161
+
162
+ def html
163
+ @htmldoc
164
+ end
165
+
166
+ # Write the HTML to a file using the provided name.
167
+ def write(name='collapsibleList.html')
168
+ $f = File.open(name,'w')
169
+ if $f
170
+ $f.puts @htmldoc
171
+ $f.close
172
+ end
173
+ installNavImageFile
174
+ end
175
+
176
+ def installNavImageFile
177
+ puts "looking for nav controls image"
178
+ # puts " __FILE__ #{__FILE__}" #File.expand_path(File.dirname(_FILE_))
179
+ puts " Dir.pwd #{Dir.pwd}"
180
+ puts " File.dirname(__FILE__) #{File.dirname(__FILE__)}"
181
+ puts " __FILE__ #{__FILE__}"
182
+ navimage = File.dirname(__FILE__) + "/UpLeftArrowsNav.png"
183
+ puts " filemask: #{navimage}"
184
+ cnt = 0
185
+ Dir.glob(navimage) do |twb|
186
+ puts twb
187
+ cnt += 1
188
+ end
189
+ puts " found #{cnt} files"
190
+ FileUtils.cp(navimage, Dir.pwd)
191
+ end
192
+
193
+ end
194
+
195
+ end
data/lib/twb/window.rb ADDED
@@ -0,0 +1,31 @@
1
+ # Copyright (C) 2014, 2015 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
+
18
+ module Twb
19
+
20
+ class Window
21
+
22
+ attr_reader :node, :name
23
+
24
+ def initialize node
25
+ @node = node
26
+ @name = @node.attr('name')
27
+ end
28
+
29
+ end
30
+
31
+ end
data/lib/twb/workbook.rb CHANGED
@@ -24,7 +24,7 @@ module Twb
24
24
 
25
25
  attr_reader :name, :dir, :modtime, :version, :build, :ndoc, :datasources, :dashboards, :storyboards, :worksheets
26
26
 
27
- # Creates a Workbook, from it's file name.
27
+ # Creates a Workbook, from its file name.
28
28
  #
29
29
  # == Parameters:
30
30
  # twbWithDir
@@ -35,17 +35,20 @@ module Twb
35
35
  @name = File.basename(twbWithDir)
36
36
  @dir = File.dirname(File.expand_path(twbWithDir))
37
37
  @modtime = File.new(twbWithDir).mtime
38
- @ndoc = Nokogiri::XML(open(twbWithDir))
38
+ @ndoc = Nokogiri::XML(open(twbWithDir))
39
+ @wbnode = @ndoc.at_xpath('//workbook')
39
40
  @version = @ndoc.xpath('/workbook/@version')
40
41
  @build = @ndoc.xpath('/workbook/comment()').text.gsub(/^[^0-9]+/,'').strip
41
42
  loaddatasources
43
+ loadWorksheets
42
44
  loadDashboards
43
45
  loadStoryboards
44
- loadWorksheets
46
+ loadWindows
45
47
  return true
46
48
  end
47
49
 
48
50
  def loaddatasources
51
+ @dataSources = @ndoc.at_xpath('//workbook/datasources')
49
52
  @datasources = {}
50
53
  @datasourceNodes = @ndoc.xpath('//workbook/datasources/datasource').to_a
51
54
  @datasourceNodes.each do |node|
@@ -55,12 +58,22 @@ module Twb
55
58
  return true
56
59
  end
57
60
 
61
+ def loadWorksheets
62
+ @worksheets = {}
63
+ sheets = @ndoc.xpath('//workbook/worksheets/worksheet' ).to_a
64
+ sheets.each do |node|
65
+ sheet = Twb::Worksheet.new(node)
66
+ @worksheets[sheet.name] = sheet
67
+ end
68
+ end
69
+
58
70
  def loadDashboards
71
+ @dashesNode = @ndoc.at_xpath('//workbook/dashboards')
59
72
  @dashboards = {}
60
73
  dashes = @ndoc.xpath('//workbook/dashboards/dashboard' ).to_a
61
74
  dashes.each do |node|
62
75
  unless node.attr('type') == 'storyboard' then
63
- dashboard = Twb::Dashboard.new(node)
76
+ dashboard = Twb::Dashboard.new(node, @worksheets)
64
77
  @dashboards[dashboard.name] = dashboard
65
78
  end
66
79
  end
@@ -75,12 +88,13 @@ module Twb
75
88
  end
76
89
  end
77
90
 
78
- def loadWorksheets
79
- @worksheets = {}
80
- sheets = @ndoc.xpath('//workbook/worksheets/worksheet' ).to_a
81
- sheets.each do |node|
82
- sheet = Twb::Worksheet.new(node)
83
- @worksheets[sheet.name] = sheet
91
+ def loadWindows
92
+ @windowsnode = @ndoc.at_xpath("//workbook/windows")
93
+ @windows = {}
94
+ windows = @ndoc.xpath("//workbook/windows/window[@name]")
95
+ windows.each do |node|
96
+ window = Twb::Window.new(node)
97
+ @windows[window.name] = window
84
98
  end
85
99
  end
86
100
 
@@ -101,7 +115,6 @@ module Twb
101
115
  @worksheets.values
102
116
  end
103
117
 
104
-
105
118
  def datasourceNames
106
119
  @datasources.keys
107
120
  end
@@ -118,7 +131,6 @@ module Twb
118
131
  @worksheets.keys
119
132
  end
120
133
 
121
-
122
134
  def datasource name
123
135
  @datasources[name]
124
136
  end
@@ -134,6 +146,59 @@ module Twb
134
146
  def worksheet name
135
147
  @worksheets[name]
136
148
  end
149
+
150
+ # Make sure that the TWB has a <dashboards> node.
151
+ # It's possible for a TWB to have no dashboards, and therefore no <dashboards> node.
152
+ def ensureDashboardsNodeExists
153
+ if @dashesNode.nil?
154
+ @dashesNode = Nokogiri::XML::Node.new "dashboards", @ndoc
155
+ @dataSources.add_next_sibling(@dashesNode)
156
+ end
157
+ end
158
+
159
+ # Add a new Documentation Dashboard to the TWB.
160
+ # Ensure that the TWB has a <dashboards> node (it may not).
161
+ # Make sure that the new Doc Dashboard's name doesn't conflict with an existing Dashboard - increment the incoming name if necessary.
162
+ # Add Doc Dashboard's <dashboard> and <window> nodes to the TWB; there's always a <windows> node in the TWB.
163
+ def addDocDashboard docDashboard
164
+ ensureDashboardsNodeExists
165
+ title = getNewDashboardTitle(docDashboard.title)
166
+ docDashboard.title=(title) unless title == docDashboard.title
167
+ @dashesNode.add_child(docDashboard.dashnode)
168
+ @windowsnode.add_child(docDashboard.winnode)
169
+ end
170
+
171
+ def getNewDashboardTitle(t)
172
+ title = t
173
+ if @datasources.include?(title)
174
+ inc = 0
175
+ loop do
176
+ inc+=1
177
+ title = t + ' ' + inc.to_s
178
+ if !@datasources.include?(title)
179
+ break
180
+ end
181
+ end
182
+ end
183
+ return title
184
+ end
185
+
186
+ # Write the TWB to a file, with an optional name.
187
+ # Can be used to write over the existing TWB (dangerous), or to a new file (preferred).
188
+ def write(name=@name)
189
+ $f = File.open(name,'w')
190
+ if $f
191
+ $f.puts @ndoc
192
+ $f.close
193
+ end
194
+ end
195
+
196
+ # Write the TWB to a file, appending the base name with the provided string.
197
+ # Intended for use when making adjustments to the TWB without overwriting the original.
198
+ def writeAppend(str)
199
+ newName = @name.sub(/[.]twb$/,'') + str.gsub(/^[.]*/,'.') + '.twb'
200
+ write newName
201
+ end
137
202
 
138
203
  end
139
204