twb 0.0.31 → 0.0.33
Sign up to get free protection for your applications and to get access to all the features.
- data/bg.cmd +5 -0
- data/lib/twb.rb +7 -2
- data/lib/twb/dashboard.rb +7 -7
- data/lib/twb/datasource.rb +38 -9
- data/lib/twb/docdashboard.rb +123 -0
- data/lib/twb/field.rb +39 -0
- data/lib/twb/hashtohtml.rb +39 -0
- data/lib/twb/htmllistcollapsible.rb +154 -0
- data/lib/twb/localfield.rb +42 -0
- data/lib/twb/metadatafield.rb +55 -0
- data/lib/twb/util/UpLeftArrowsNav.png +0 -0
- data/lib/twb/util/hashtohtml.rb +45 -0
- data/lib/twb/util/htmllistcollapsible.rb +195 -0
- data/lib/twb/window.rb +31 -0
- data/lib/twb/workbook.rb +77 -12
- data/lib/twb/worksheet.rb +29 -1
- data/test/No Content.injected.twb +82 -0
- data/test/No Content.twb +68 -0
- data/test/No Dashboards.injected.twb +618 -0
- data/test/No Dashboards.twb +604 -0
- data/test/Special Documentation.html +198 -0
- data/test/TableauDocInlineCSS.html +165 -0
- data/test/UpLeftArrowsNav.png +0 -0
- data/test/Web Page Dashboards.injected.twb +1361 -0
- data/test/Web Page Dashboards.twb +1347 -0
- data/test/collapsibleList.html +198 -0
- data/test/testDocDashboard.rb +53 -0
- data/test/testDocDashboardCreate.rb +33 -0
- data/test/testHTMLList.rb +23 -0
- data/test/testTwbGem.rb +67 -0
- data/testTwbGem.rb +23 -9
- data/testTwbWrite.rb +22 -0
- data/twb-0.0.32.gem +0 -0
- metadata +29 -12
- data/twb-0.0.1.gem +0 -0
- data/twb-0.0.2.gem +0 -0
- data/twb-0.0.21.gem +0 -0
- data/twb-0.0.22.gem +0 -0
- data/twb-0.0.23.gem +0 -0
- data/twb-0.0.24.gem +0 -0
- data/twb-0.0.25.gem +0 -0
- data/twb-0.0.26.gem +0 -0
- data/twb-0.0.27.gem +0 -0
- data/twb-0.0.29.gem +0 -0
- 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
|
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
|
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
|
-
|
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
|
79
|
-
@
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
|