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.
- 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
|
|