bookchef 0.1.6
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/.document +5 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +47 -0
- data/LICENSE.txt +20 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/bin/bookchef +29 -0
- data/lib/bookchef.rb +38 -0
- data/lib/bookchef/compilers/html.rb +30 -0
- data/lib/bookchef/compilers/pdf.rb +60 -0
- data/lib/bookchef/images/article_link.png +0 -0
- data/lib/bookchef/images/book_link.png +0 -0
- data/lib/bookchef/images/external_link.png +0 -0
- data/lib/bookchef/images/lib_link.png +0 -0
- data/lib/bookchef/images/manual_link.png +0 -0
- data/lib/bookchef/images/video_link.png +0 -0
- data/lib/bookchef/images/website_link.png +0 -0
- data/lib/bookchef/stylesheets/css/default.css +152 -0
- data/lib/bookchef/stylesheets/scss/default.scss +88 -0
- data/lib/bookchef/stylesheets/xslt/bookchef_to_html.xsl +238 -0
- data/lib/bookchef/templates/footer.html +26 -0
- data/lib/bookchef/tree_merger.rb +192 -0
- data/spec/fixtures/book/html_expected.html +101 -0
- data/spec/fixtures/book/main.xml +10 -0
- data/spec/fixtures/book/merge_expected.xml +78 -0
- data/spec/fixtures/book/section1/index.xml +20 -0
- data/spec/fixtures/book/section1/subsection.xml +23 -0
- data/spec/fixtures/book/section1/supersubsection/hello.xml +6 -0
- data/spec/fixtures/book/section1/supersubsection/index.xml +11 -0
- data/spec/fixtures/book/settings.xml +8 -0
- data/spec/lib/bookchef/compilers/html_spec.rb +24 -0
- data/spec/lib/bookchef/tree_merger_spec.rb +23 -0
- data/spec/spec_helper.rb +8 -0
- metadata +243 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
body { font-family: "Liberation Serif", "Times New Roman"; line-height: 150%; }
|
2
|
+
|
3
|
+
code, .code.inline { font-family: "Monaco"; font-size: 80%; background-color: #eee; }
|
4
|
+
code { display: block; clear: both; margin: 1em 0; padding: 0.5em; white-space: pre; line-height: 120%; }
|
5
|
+
|
6
|
+
@mixin end_of_section_block_container {
|
7
|
+
font-size: 80%; margin: 1em; border: dotted 1px #aaa; padding: 1em 1em 0 1em;
|
8
|
+
}
|
9
|
+
@mixin end_of_section_block {
|
10
|
+
margin-bottom: 1em;
|
11
|
+
}
|
12
|
+
|
13
|
+
p { margin: 0 0 0 0; text-indent: 1em; text-align: justify; }
|
14
|
+
span.name, span.filename, span.keyboard { font-family: "Monaco"; font-size: 80%; }
|
15
|
+
img { clear: both; display: block; margin: 2em 1em; width: 80%; page-break-inside: avoid; }
|
16
|
+
|
17
|
+
.footnotes {
|
18
|
+
@include end_of_section_block_container; page-break-inside: avoid;
|
19
|
+
.footnote { @include end_of_section_block; }
|
20
|
+
}
|
21
|
+
.references {
|
22
|
+
font-style: italic; @include end_of_section_block_container; page-break-inside: avoid;
|
23
|
+
img {margin: 0 0.5em 0 0; margin-bottom: -0.3em;display: inline; width: 16px; }
|
24
|
+
.reference { @include end_of_section_block; }
|
25
|
+
}
|
26
|
+
|
27
|
+
.footnotes, .references { font-size: 70%; line-height: 120%; }
|
28
|
+
|
29
|
+
h1 { page-break-inside: avoid; }
|
30
|
+
.chapter {
|
31
|
+
page-break-before: always;
|
32
|
+
h1 { font-size: 270%; line-height: 100%; }
|
33
|
+
.section {
|
34
|
+
margin-top: 2em;
|
35
|
+
h1 { font-size: 220%; }
|
36
|
+
.section {
|
37
|
+
margin-top: 1.7em;
|
38
|
+
h1 { font-size: 190%; }
|
39
|
+
.section {
|
40
|
+
margin-top: 1.5em;
|
41
|
+
h1 { font-size: 170%; }
|
42
|
+
.section {
|
43
|
+
margin-top: 1.3em;
|
44
|
+
h1 { font-size: 140%; }
|
45
|
+
.section {
|
46
|
+
margin-top: 1.1em;
|
47
|
+
h1 { font-size: 125%; }
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
p.frameDescription { font-style: italic; font-size: 80%; margin: 1.5em 0 -0.5em 0; text-indent: 0px; }
|
56
|
+
|
57
|
+
.cover {
|
58
|
+
page-break-after: always;
|
59
|
+
img { width: 100%; }
|
60
|
+
}
|
61
|
+
|
62
|
+
.tableOfContents {
|
63
|
+
page-break-after: always; font-size: 120%;
|
64
|
+
ul { list-style-type: none; margin: 0 0 0 0; padding: 0 0 0 0; }
|
65
|
+
}
|
66
|
+
|
67
|
+
table {
|
68
|
+
margin: 1.5em 1em; page-break-inside: avoid;
|
69
|
+
border-collapse: collapse;
|
70
|
+
td { vertical-align: top; }
|
71
|
+
td, th { border: solid 1px #aaa; padding: 0.5em; margin-top: 1.5em; font-size: 80%; }
|
72
|
+
}
|
73
|
+
|
74
|
+
ul, ol {
|
75
|
+
margin-left: 2em;
|
76
|
+
li { margin: 0.5em 0; }
|
77
|
+
}
|
78
|
+
|
79
|
+
sup { height: 0; line-height: 1; vertical-align: baseline; _vertical-align: bottom; position: relative; bottom: 1ex; }
|
80
|
+
|
81
|
+
.footer {
|
82
|
+
border-top: solid 1px #ccc;
|
83
|
+
paddign-top: 1em; font-size: 80%; line-height: 100%;
|
84
|
+
.text { float: left; width: 80%; color: #aaa; }
|
85
|
+
.info { float: right; width: 20%; text-align: right; font-weight: bold; }
|
86
|
+
}
|
87
|
+
|
88
|
+
.insertPageBreak { page-break-after: always; height: 1px; }
|
@@ -0,0 +1,238 @@
|
|
1
|
+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common">
|
2
|
+
<xsl:output indent="yes" omit-xml-declaration="yes"/>
|
3
|
+
|
4
|
+
<xsl:param name="gem_path">#{gem_path}</xsl:param>
|
5
|
+
|
6
|
+
<!-- Identity template -->
|
7
|
+
<xsl:template match="@* | node()">
|
8
|
+
<xsl:copy>
|
9
|
+
<xsl:apply-templates select="@* | node()"/>
|
10
|
+
</xsl:copy>
|
11
|
+
</xsl:template>
|
12
|
+
|
13
|
+
<xsl:template name="string-replace-all">
|
14
|
+
<xsl:param name="text" />
|
15
|
+
<xsl:param name="replace" />
|
16
|
+
<xsl:param name="by" />
|
17
|
+
<xsl:choose>
|
18
|
+
<xsl:when test="contains($text, $replace)">
|
19
|
+
<xsl:value-of select="substring-before($text,$replace)" />
|
20
|
+
<xsl:value-of select="$by" />
|
21
|
+
<xsl:call-template name="string-replace-all">
|
22
|
+
<xsl:with-param name="text" select="substring-after($text,$replace)" />
|
23
|
+
<xsl:with-param name="replace" select="$replace" />
|
24
|
+
<xsl:with-param name="by" select="$by" />
|
25
|
+
</xsl:call-template>
|
26
|
+
</xsl:when>
|
27
|
+
<xsl:otherwise>
|
28
|
+
<xsl:value-of select="$text" />
|
29
|
+
</xsl:otherwise>
|
30
|
+
</xsl:choose>
|
31
|
+
</xsl:template>
|
32
|
+
|
33
|
+
<xsl:template match="text()">
|
34
|
+
<xsl:variable name="mdash"><xsl:text disable-output-escaping="yes"><![CDATA[#mdash;]]></xsl:text></xsl:variable>
|
35
|
+
<xsl:call-template name="string-replace-all">
|
36
|
+
<xsl:with-param name="text" select="." />
|
37
|
+
<xsl:with-param name="replace" select='" - "'/>
|
38
|
+
<xsl:with-param name="by" select='$mdash' />
|
39
|
+
</xsl:call-template>
|
40
|
+
</xsl:template>
|
41
|
+
|
42
|
+
<xsl:template match="/book">
|
43
|
+
<html>
|
44
|
+
<head>
|
45
|
+
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
|
46
|
+
<link href="{$gem_path}/stylesheets/css/default.css" rel="stylesheet" type="text/css"/>
|
47
|
+
<xsl:copy-of select="/book/settings/*"/>
|
48
|
+
</head>
|
49
|
+
<body>
|
50
|
+
<xsl:apply-templates select="cover" mode="cover" />
|
51
|
+
<div class="tableOfContents">
|
52
|
+
<h2>Table of contents</h2>
|
53
|
+
<ul><xsl:apply-templates select="chapter" mode="table_of_contents" /></ul>
|
54
|
+
</div>
|
55
|
+
<xsl:apply-templates select="node()" />
|
56
|
+
</body>
|
57
|
+
</html>
|
58
|
+
</xsl:template>
|
59
|
+
|
60
|
+
<xsl:template match="cover" mode="cover">
|
61
|
+
<div class="cover"><xsl:apply-templates select="@* | node()" /></div>
|
62
|
+
</xsl:template>
|
63
|
+
<xsl:template match="cover">
|
64
|
+
</xsl:template>
|
65
|
+
|
66
|
+
<xsl:template match="InsertBookVersion">
|
67
|
+
<xsl:value-of select="/book/@version" />
|
68
|
+
</xsl:template>
|
69
|
+
|
70
|
+
<xsl:template match="/book/settings">
|
71
|
+
</xsl:template>
|
72
|
+
|
73
|
+
<xsl:template match="section/title">
|
74
|
+
<h1 id="{../@id}"><xsl:value-of select="." /></h1>
|
75
|
+
</xsl:template>
|
76
|
+
<xsl:template match="chapter/title">
|
77
|
+
<h1 id="{../@id}">Chapter <xsl:number count="chapter"/>. <xsl:value-of select="." /></h1>
|
78
|
+
</xsl:template>
|
79
|
+
|
80
|
+
<xsl:template match="li/title">
|
81
|
+
<b><xsl:value-of select="." /></b>
|
82
|
+
</xsl:template>
|
83
|
+
|
84
|
+
<xsl:template match="chapter">
|
85
|
+
<div class="chapter">
|
86
|
+
<xsl:apply-templates select="@* |node()" />
|
87
|
+
</div>
|
88
|
+
</xsl:template>
|
89
|
+
<xsl:template match="chapter/@id">
|
90
|
+
</xsl:template>
|
91
|
+
|
92
|
+
<xsl:template match="chapter" mode="table_of_contents">
|
93
|
+
<li>Chapter <xsl:number count="chapter"/>. <a href="#{@id}"><xsl:value-of select="./title"/></a></li>
|
94
|
+
</xsl:template>
|
95
|
+
|
96
|
+
<xsl:template match="section">
|
97
|
+
<div class="section">
|
98
|
+
<xsl:apply-templates select="@* |node()" />
|
99
|
+
</div>
|
100
|
+
</xsl:template>
|
101
|
+
<xsl:template match="section/@id">
|
102
|
+
</xsl:template>
|
103
|
+
|
104
|
+
<xsl:template match="pagebreak">
|
105
|
+
<div class="insertPageBreak"></div>
|
106
|
+
</xsl:template>
|
107
|
+
|
108
|
+
<xsl:template match="footnotes">
|
109
|
+
<div class="footnotes">
|
110
|
+
<xsl:apply-templates select="@* |node()" />
|
111
|
+
</div>
|
112
|
+
</xsl:template>
|
113
|
+
|
114
|
+
<xsl:template match="footnote">
|
115
|
+
<xsl:param name="id" select="./@id"/>
|
116
|
+
<div class="footnote" id="{$id}">
|
117
|
+
<sup><xsl:number count="footnote" level="single"/></sup><xsl:text> </xsl:text>
|
118
|
+
<xsl:apply-templates select="node()"/>
|
119
|
+
</div>
|
120
|
+
</xsl:template>
|
121
|
+
|
122
|
+
|
123
|
+
<xsl:template match="references">
|
124
|
+
<div class="references">
|
125
|
+
<xsl:apply-templates select="@* |node()" />
|
126
|
+
</div>
|
127
|
+
</xsl:template>
|
128
|
+
|
129
|
+
<xsl:template match="reference">
|
130
|
+
<xsl:param name="id" select="./@id"/>
|
131
|
+
<xsl:param name="type" select="./@type"/>
|
132
|
+
<xsl:param name="url" select="./@url"/>
|
133
|
+
<div class="reference" id="{$id}">
|
134
|
+
<img src="{$gem_path}/images/{$type}_link.png" />
|
135
|
+
[<xsl:number count="reference" level="single"/>]<xsl:text> </xsl:text>
|
136
|
+
<a href="{$url}"><xsl:value-of select="."/></a>
|
137
|
+
</div>
|
138
|
+
</xsl:template>
|
139
|
+
|
140
|
+
<xsl:template match="code">
|
141
|
+
<p class="frameDescription"><xsl:value-of select="./@description"/><xsl:text> </xsl:text></p>
|
142
|
+
<xsl:element name="{name()}">
|
143
|
+
<xsl:copy-of select="./node()"/>
|
144
|
+
</xsl:element>
|
145
|
+
</xsl:template>
|
146
|
+
|
147
|
+
<xsl:template match="table">
|
148
|
+
<p class="frameDescription"><xsl:value-of select="./@description"/><xsl:text> </xsl:text></p>
|
149
|
+
<table><xsl:apply-templates select="./node()" /></table>
|
150
|
+
</xsl:template>
|
151
|
+
|
152
|
+
<xsl:template match="code-inline" >
|
153
|
+
<span class="code inline"><xsl:apply-templates select="@* |node()" /></span>
|
154
|
+
</xsl:template>
|
155
|
+
|
156
|
+
<xsl:template match="name" >
|
157
|
+
<span class="name"><xsl:apply-templates select="@* |node()" /></span>
|
158
|
+
</xsl:template>
|
159
|
+
|
160
|
+
<xsl:template match="filename" >
|
161
|
+
<span class="filename"><xsl:apply-templates select="@* |node()" /></span>
|
162
|
+
</xsl:template>
|
163
|
+
|
164
|
+
<xsl:template match="keyboard" >
|
165
|
+
<span class="keyboard"><xsl:apply-templates select="@* |node()" /></span>
|
166
|
+
</xsl:template>
|
167
|
+
|
168
|
+
<xsl:template match="a[not(node())]">
|
169
|
+
<xsl:param name="href" select="./@href"/>
|
170
|
+
<xsl:param name="reference" select="./@reference"/>
|
171
|
+
|
172
|
+
<xsl:choose>
|
173
|
+
<xsl:when test="$href != ''">
|
174
|
+
<xsl:variable name="name"><xsl:value-of select='translate($href, "#", "")'/></xsl:variable>
|
175
|
+
<a href="{$href}"><xsl:value-of select="//*[@id=$name]/title"/></a>
|
176
|
+
</xsl:when>
|
177
|
+
<xsl:when test="$reference != ''">
|
178
|
+
<xsl:variable name="title"><xsl:value-of select='//reference[@id=$reference]'/></xsl:variable>
|
179
|
+
<xsl:variable name="url"><xsl:value-of select='//reference[@id=$reference]/@url'/></xsl:variable>
|
180
|
+
<a href="{$url}"><xsl:value-of select="$title"/></a>
|
181
|
+
</xsl:when>
|
182
|
+
</xsl:choose>
|
183
|
+
|
184
|
+
</xsl:template>
|
185
|
+
|
186
|
+
<xsl:template match="term" name="term">
|
187
|
+
<i><xsl:apply-templates select="@* |node()"/></i>
|
188
|
+
</xsl:template>
|
189
|
+
|
190
|
+
<xsl:template match="*[@reference]" >
|
191
|
+
<xsl:param name="href" select="./@reference"/>
|
192
|
+
<xsl:choose>
|
193
|
+
|
194
|
+
<xsl:when test="name() = 'span'">
|
195
|
+
<span class="referenceSelection">
|
196
|
+
<xsl:value-of select="."/>
|
197
|
+
</span>
|
198
|
+
</xsl:when>
|
199
|
+
|
200
|
+
<xsl:otherwise>
|
201
|
+
<xsl:variable name="reference_content">
|
202
|
+
<xsl:element name="{name()}">
|
203
|
+
<xsl:value-of select="."/>
|
204
|
+
</xsl:element>
|
205
|
+
</xsl:variable>
|
206
|
+
<xsl:apply-templates select="exslt:node-set($reference_content)"/>
|
207
|
+
</xsl:otherwise>
|
208
|
+
|
209
|
+
</xsl:choose>
|
210
|
+
|
211
|
+
<xsl:text> </xsl:text><a href="#{$href}">[<xsl:value-of select="./@number"/>]</a>
|
212
|
+
|
213
|
+
</xsl:template>
|
214
|
+
|
215
|
+
<xsl:template match="*[@footnote]" >
|
216
|
+
<xsl:param name="href" select="./@footnote"/>
|
217
|
+
|
218
|
+
<xsl:choose>
|
219
|
+
<xsl:when test="name() = 'span'">
|
220
|
+
<span class="footnoteSelection">
|
221
|
+
<xsl:value-of select="."/>
|
222
|
+
</span>
|
223
|
+
</xsl:when>
|
224
|
+
<xsl:otherwise>
|
225
|
+
<xsl:variable name="footnote_content">
|
226
|
+
<xsl:element name="{name()}">
|
227
|
+
<xsl:value-of select="."/>
|
228
|
+
</xsl:element>
|
229
|
+
</xsl:variable>
|
230
|
+
<xsl:apply-templates select="exslt:node-set($footnote_content)"/>
|
231
|
+
</xsl:otherwise>
|
232
|
+
</xsl:choose>
|
233
|
+
|
234
|
+
<a href="#{$href}"><sup><xsl:value-of select="./@number"/></sup></a>
|
235
|
+
|
236
|
+
</xsl:template>
|
237
|
+
|
238
|
+
</xsl:stylesheet>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<html>
|
2
|
+
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
5
|
+
<script type="text/javascript">
|
6
|
+
function subst() {
|
7
|
+
var vars={};
|
8
|
+
var x=document.location.search.substring(1).split('&');
|
9
|
+
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
|
10
|
+
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
|
11
|
+
for(var i in x) {
|
12
|
+
var y = document.getElementsByClassName(x[i]);
|
13
|
+
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
|
14
|
+
}
|
15
|
+
}
|
16
|
+
</script>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body onload="subst();">
|
20
|
+
<div class="footer">
|
21
|
+
<div class="text">#{footer_text}</div>
|
22
|
+
<div class="info"><span class="page"></span></div>
|
23
|
+
</div>
|
24
|
+
</body>
|
25
|
+
|
26
|
+
</html>
|
@@ -0,0 +1,192 @@
|
|
1
|
+
class BookChef
|
2
|
+
|
3
|
+
class TreeMerger
|
4
|
+
|
5
|
+
attr_reader :document, :version
|
6
|
+
|
7
|
+
class LinkLevelOutOfReach < Exception; end
|
8
|
+
|
9
|
+
def initialize(path, fn)
|
10
|
+
@path = File.expand_path(path)
|
11
|
+
@filename = fn
|
12
|
+
@document = File.read("#@path/#@filename").gsub(/<%(.*?)%>/, '<%\1%>')
|
13
|
+
@document = Nokogiri::XML.parse @document
|
14
|
+
insert_version_from_git_tag!
|
15
|
+
if File.exists?("#@path/settings.xml")
|
16
|
+
@settings = File.read("#@path/settings.xml")
|
17
|
+
@document.root << @settings
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
@documents = []
|
23
|
+
@document = process_level(@document)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save_to(fn)
|
27
|
+
f = File.open(fn, "w")
|
28
|
+
f.write @document.to_s
|
29
|
+
f.close
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def process_level(level_document, current_path="")
|
35
|
+
@documents << level_document
|
36
|
+
sourced_sections = level_document.xpath('//section[@src]|//chapter[@src]')
|
37
|
+
|
38
|
+
normalize_code! level_document
|
39
|
+
convert_links! level_document, current_path
|
40
|
+
make_image_paths_absolute! level_document, current_path
|
41
|
+
|
42
|
+
sourced_sections.each do |s|
|
43
|
+
current_fn = filename_or_index(s[:src])
|
44
|
+
current_dir = s[:src].sub(/\/?[^\/]*\.xml\Z/, '')
|
45
|
+
path = current_path
|
46
|
+
path += "/#{current_dir}" unless current_dir.empty?
|
47
|
+
full_current_path = "#{path}/#{current_fn}"
|
48
|
+
|
49
|
+
puts "processing #{full_current_path}"
|
50
|
+
assign_id_to_section! s, full_current_path
|
51
|
+
|
52
|
+
# Parse the sourced file
|
53
|
+
level_file = File.read("#@path#{full_current_path}")
|
54
|
+
level_file = BookChef.protect_special_chars(level_file)
|
55
|
+
sourced_document = Nokogiri::XML.parse(level_file)
|
56
|
+
convert_references_and_footnotes! sourced_document, full_current_path
|
57
|
+
|
58
|
+
# Now process it too, replacing all src-s with xml from sourced files
|
59
|
+
sourced_document = process_level(sourced_document, path)
|
60
|
+
|
61
|
+
# replace the contents of the tag with the actual sourced file
|
62
|
+
s.children = sourced_document.root.children
|
63
|
+
end unless sourced_sections.empty?
|
64
|
+
|
65
|
+
@documents.delete(level_document) and return level_document
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts links 'href' attr from relative to absolute path
|
69
|
+
# according to the sections 'name' attrs.
|
70
|
+
def convert_links!(document, current_path)
|
71
|
+
document.search("a").each do |link|
|
72
|
+
|
73
|
+
next if link[:href].nil? || link[:href] =~ /\Ahttps?:\/\//
|
74
|
+
link_path_arr = link[:href].split("/")
|
75
|
+
current_path_arr = current_path.split("/").reject { |i| i.empty? }
|
76
|
+
uplevels_count = (link_path_arr.map { |i| i if i == ".." }).compact.size
|
77
|
+
link_path_arr.delete_if { |i| i == ".." }
|
78
|
+
|
79
|
+
if uplevels_count > current_path_arr.size
|
80
|
+
raise LinkLevelOutOfReach, "for link #{link.to_s} in \"#{current_path}\""
|
81
|
+
end
|
82
|
+
|
83
|
+
current_path_arr = current_path_arr.reverse.drop(uplevels_count).reverse
|
84
|
+
link[:href] = "#/#{current_path_arr.join("/")}/#{path_with_filename(link_path_arr.join("/"))}".gsub(/\/+/, '/')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def convert_references_and_footnotes!(document, current_path)
|
89
|
+
|
90
|
+
# Search the document tree and find the closest file
|
91
|
+
# that contains <footnotes> and <references>
|
92
|
+
container_paths = { footnote: current_path.split("/"), reference: current_path.split("/") }
|
93
|
+
[:footnote, :reference].each do |container|
|
94
|
+
catch :break_inner_loop do
|
95
|
+
(@documents + [document]).reverse.each_with_index do |d,i|
|
96
|
+
throw :break_inner_loop if d.search("//#{container}s").size > 0
|
97
|
+
container_paths[container].pop if container_paths[container].pop == "index.xml"
|
98
|
+
container_paths["#{container}_file"] = "/index.xml"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
document.search("//footnote|//reference").each do |node|
|
104
|
+
node[:id] = current_path + "/#{node.name}_#{node[:id]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
document.search("//@footnote|//@reference").each do |node|
|
108
|
+
node.parent["number"] = node.value
|
109
|
+
node.parent[node.name] = container_paths[node.name.to_sym].join("/") +
|
110
|
+
(container_paths["#{node.name}_file"] || '') +
|
111
|
+
"/#{node.name}_#{node.value}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def make_image_paths_absolute!(document, current_path)
|
116
|
+
document.search("img").each do |img|
|
117
|
+
img[:src] = "file://" + @path + current_path + "/#{img[:src]}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sets section id like this: <section id="/section1/subsection_a/intro.xml">
|
122
|
+
def assign_id_to_section!(node, full_current_path)
|
123
|
+
node[:id] = full_current_path
|
124
|
+
node.remove_attribute("src")
|
125
|
+
end
|
126
|
+
|
127
|
+
# returns just the filename out of the full path
|
128
|
+
# For example, if the path is "/section1/subsection"
|
129
|
+
# it returns "index.xml"
|
130
|
+
def filename_or_index(path)
|
131
|
+
(path.match(/[^\/]*\.xml\Z/) || ["index.xml"])[0]
|
132
|
+
end
|
133
|
+
|
134
|
+
# returns full path attaching "index.xml" to the end of no file specified
|
135
|
+
# For example, if the path is "/section/subsection"
|
136
|
+
# it returns "/section/subsection/index.xml"
|
137
|
+
def path_with_filename(path)
|
138
|
+
if path.match(/[^\/]*\.xml\Z/)
|
139
|
+
path
|
140
|
+
else
|
141
|
+
path + "/index.xml"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def normalize_code!(document)
|
146
|
+
document.search("code").each do |c|
|
147
|
+
minimum_whitespace = nil
|
148
|
+
lines_arr = c.children.to_s.split("\n")
|
149
|
+
new_lines_arr = []
|
150
|
+
lines_arr.each_with_index do |l,i|
|
151
|
+
next if l =~ /\A\s*\Z/
|
152
|
+
match_size = l.match(/\A( )*/).to_s.size
|
153
|
+
minimum_whitespace = match_size if !minimum_whitespace || match_size < minimum_whitespace
|
154
|
+
end
|
155
|
+
lines_arr.each_with_index do |l,i|
|
156
|
+
next if l =~ /\A\s*\Z/ && (i == 0 || i == lines_arr.size-1)
|
157
|
+
l.sub!("\n", '')
|
158
|
+
l.sub!(/\A( ){#{minimum_whitespace}}/, '')
|
159
|
+
new_lines_arr << split_long_line(l, l.match(/\A( )*/).to_s.size)
|
160
|
+
end
|
161
|
+
c.content = new_lines_arr.compact.join("\n")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def split_long_line(line, leading_spaces_number=0)
|
166
|
+
if line.length > 70
|
167
|
+
lines = line[61..line.length-1].split(/[ .]/, 2)
|
168
|
+
line1 = line[0..60] + lines[0]
|
169
|
+
leading_spaces = (0..leading_spaces_number-1).map { ' ' }.join
|
170
|
+
line2 = leading_spaces.to_s + lines[1].to_s
|
171
|
+
line2 = split_long_line(line2, leading_spaces_number)
|
172
|
+
return "#{line1}\n#{line2}"
|
173
|
+
else
|
174
|
+
line
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def insert_version_from_git_tag!
|
179
|
+
|
180
|
+
`cd #{@path} && git tag`.split("\n").sort.reverse.each do |t|
|
181
|
+
if t =~ /\Av[0-9]/
|
182
|
+
@version = t.sub(/\Av/,'').rstrip
|
183
|
+
@document.root["version"] = t.sub(/\Av/,'').rstrip
|
184
|
+
return
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|