xpub 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +161 -0
- data/Rakefile +2 -0
- data/bin/xpub +74 -0
- data/lib/xpub.rb +5 -0
- data/lib/xpub/dsl/book.rb +261 -0
- data/lib/xpub/dsl/builder.rb +370 -0
- data/lib/xpub/dsl/page.rb +159 -0
- data/lib/xpub/dsl/src_file.rb +139 -0
- data/lib/xpub/version.rb +3 -0
- data/skel/.gitignore +2 -0
- data/skel/Xpub +68 -0
- data/skel/output/.gitkeep +0 -0
- data/skel/src/.gitkeep +0 -0
- data/skel/src/sample.md +47 -0
- data/skel/src/sample1.jpg +0 -0
- data/skel/theme/default/epub/epub.css +204 -0
- data/skel/theme/default/epub/metadata.dat.erb +43 -0
- data/skel/theme/default/epub/pandoc-filter.rb +206 -0
- data/skel/theme/default/epub/template.html +57 -0
- data/skel/theme/default/latex/pandoc-filter.rb +269 -0
- data/skel/theme/default/latex/template.tex +376 -0
- data/skel/tmp/.gitkeep +0 -0
- data/xpub.gemspec +25 -0
- metadata +113 -0
@@ -0,0 +1,370 @@
|
|
1
|
+
module Xpub
|
2
|
+
class CallBook
|
3
|
+
class CallBuilder
|
4
|
+
attr_reader :name, :theme, :output
|
5
|
+
|
6
|
+
def initialize name, book
|
7
|
+
@name = name
|
8
|
+
@book = book
|
9
|
+
@theme = "default"
|
10
|
+
end
|
11
|
+
|
12
|
+
def output output
|
13
|
+
@output = output
|
14
|
+
end
|
15
|
+
|
16
|
+
def theme theme
|
17
|
+
@theme = theme
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
raise "This method is not implement."
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate
|
25
|
+
if @book.src_files.count == 0
|
26
|
+
raise "src_file is empty."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def src_path file
|
31
|
+
"#{Dir::getwd}/src/#{file}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def tmp_path file
|
35
|
+
"#{Dir::getwd}/tmp/#{file}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def output_path file
|
39
|
+
"#{Dir::getwd}/output/#{file}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def copy_to_tmp files
|
43
|
+
files.each { |file|
|
44
|
+
pn = Pathname.new tmp_path(file.file)
|
45
|
+
FileUtils.mkdir_p(pn.dirname) unless FileTest.exist?(pn.dirname)
|
46
|
+
|
47
|
+
unless FileTest.exist?(tmp_path(file.file)) && File::mtime(src_path(file.file)) <= File::mtime(tmp_path(file.file))
|
48
|
+
puts "copy #{file.file} to tmp/".color :white
|
49
|
+
FileUtils.copy_entry(src_path(file.file), tmp_path(file.file))
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def cmd_exec cmd, args, option
|
55
|
+
|
56
|
+
cmd_line = cmd + " " + args.map { |arg|
|
57
|
+
Shellwords.shellescape(arg)
|
58
|
+
}.join(" ")
|
59
|
+
puts cmd_line.color :cyan
|
60
|
+
stdout, stderr, status = Open3.capture3 cmd_line
|
61
|
+
if option[:v] || status != 0
|
62
|
+
puts stdout.color :green
|
63
|
+
end
|
64
|
+
if status != 0
|
65
|
+
puts stderr.color :red
|
66
|
+
puts "error!".color :red
|
67
|
+
exit
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class CallEpubBuilder < CallBuilder
|
73
|
+
def initialize name, book
|
74
|
+
@vars = []
|
75
|
+
@meta = []
|
76
|
+
@template = "template.html"
|
77
|
+
@filter = "pandoc-filter.rb"
|
78
|
+
@stylesheet = "epub.css"
|
79
|
+
@metadata = "metadata.dat"
|
80
|
+
@page_progression_direction = "rtl"
|
81
|
+
@cover_image = nil
|
82
|
+
|
83
|
+
if book.title != ""
|
84
|
+
@vars << ["title", book.title]
|
85
|
+
end
|
86
|
+
super name, book
|
87
|
+
end
|
88
|
+
|
89
|
+
def page_progression_direction param
|
90
|
+
@page_progression_direction = param
|
91
|
+
end
|
92
|
+
|
93
|
+
def template param
|
94
|
+
@template = param
|
95
|
+
end
|
96
|
+
|
97
|
+
def filter param
|
98
|
+
@filter = param
|
99
|
+
end
|
100
|
+
|
101
|
+
def stylesheet param
|
102
|
+
@stylesheet = param
|
103
|
+
end
|
104
|
+
|
105
|
+
def metadata param
|
106
|
+
@metadata = param
|
107
|
+
end
|
108
|
+
|
109
|
+
def cover_image param
|
110
|
+
@cover_image = param
|
111
|
+
end
|
112
|
+
|
113
|
+
def meta_option
|
114
|
+
result = []
|
115
|
+
@meta.concat([["page-progression-direction", @page_progression_direction]]).each { |m|
|
116
|
+
result << "-M"
|
117
|
+
result << "#{m[0]}=#{m[1]}"
|
118
|
+
}
|
119
|
+
result
|
120
|
+
end
|
121
|
+
|
122
|
+
def vars_option
|
123
|
+
result = []
|
124
|
+
@vars.concat([[:book_name, @book.name]]).each { |v|
|
125
|
+
result << "-V"
|
126
|
+
result << "#{v[0]}=#{v[1]}"
|
127
|
+
}
|
128
|
+
result
|
129
|
+
end
|
130
|
+
|
131
|
+
def template_option
|
132
|
+
"--template=#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@template}"
|
133
|
+
end
|
134
|
+
|
135
|
+
def filter_option
|
136
|
+
"--filter=#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@filter}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def stylesheet_option
|
140
|
+
"--epub-stylesheet=#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@stylesheet}"
|
141
|
+
end
|
142
|
+
|
143
|
+
def metadata_option
|
144
|
+
"--epub-metadata=" + metadata_path
|
145
|
+
end
|
146
|
+
|
147
|
+
def metadata_path
|
148
|
+
tmp_path("#{@book.name}.#{@metadata}")
|
149
|
+
end
|
150
|
+
|
151
|
+
def metadata_template_path
|
152
|
+
"#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@metadata}.erb"
|
153
|
+
end
|
154
|
+
|
155
|
+
def epub_path
|
156
|
+
output_path(@book.name) + '.epub'
|
157
|
+
end
|
158
|
+
|
159
|
+
def json_path
|
160
|
+
tmp_path(@book.name) + '.json'
|
161
|
+
end
|
162
|
+
|
163
|
+
def _build_resource files, option
|
164
|
+
copy_to_tmp files
|
165
|
+
end
|
166
|
+
|
167
|
+
def pandoc_cmd
|
168
|
+
"pandoc"
|
169
|
+
end
|
170
|
+
|
171
|
+
def pandoc_option option
|
172
|
+
option = [
|
173
|
+
"--epub-chapter-level=1",
|
174
|
+
"--toc",
|
175
|
+
"-f",
|
176
|
+
"markdown_phpextra+hard_line_breaks+raw_html",
|
177
|
+
"-s",
|
178
|
+
template_option,
|
179
|
+
filter_option,
|
180
|
+
stylesheet_option,
|
181
|
+
metadata_option
|
182
|
+
]
|
183
|
+
if @cover_image
|
184
|
+
option << "--epub-cover-image=" + src_path(@cover_image)
|
185
|
+
end
|
186
|
+
option
|
187
|
+
end
|
188
|
+
|
189
|
+
def build_epub_metadata option
|
190
|
+
f = open metadata_template_path
|
191
|
+
erb = ERB.new f.read, nil, "-"
|
192
|
+
f.close
|
193
|
+
f = open metadata_path, "w"
|
194
|
+
f.write erb.result(binding)
|
195
|
+
f.close
|
196
|
+
end
|
197
|
+
|
198
|
+
def build option
|
199
|
+
build_epub_metadata option
|
200
|
+
|
201
|
+
if option['pandoc-json-output']
|
202
|
+
cmd_exec "cd #{tmp_path ""};"+ pandoc_cmd, ["-o", json_path, "-t", "json"].concat(pandoc_option option).concat(vars_option).concat(meta_option).concat(@book.src_files.map{ |f| f.full_path }), option
|
203
|
+
end
|
204
|
+
cmd_exec "cd #{tmp_path ""};"+ pandoc_cmd, ["-o", epub_path, "-t", "epub3"].concat(pandoc_option option).concat(vars_option).concat(meta_option).concat(@book.src_files.map{ |f| f.full_path }), option
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class CallLatexBuilder < CallBuilder
|
209
|
+
attr_reader :template
|
210
|
+
|
211
|
+
def initialize name, book
|
212
|
+
@vars = []
|
213
|
+
@template = "template.tex"
|
214
|
+
@filter = "pandoc-filter.rb"
|
215
|
+
@hyoushi = []
|
216
|
+
@urahyoushi = []
|
217
|
+
super name, book
|
218
|
+
end
|
219
|
+
|
220
|
+
def documentclass param
|
221
|
+
@vars << [:documentclass, param]
|
222
|
+
end
|
223
|
+
|
224
|
+
def classoption param
|
225
|
+
@vars << [:classoption, param]
|
226
|
+
end
|
227
|
+
|
228
|
+
def prepartname param
|
229
|
+
@vars << [:prepartname, param]
|
230
|
+
end
|
231
|
+
|
232
|
+
def postpartname param
|
233
|
+
@vars << [:postpartname, param]
|
234
|
+
end
|
235
|
+
|
236
|
+
def prechaptername param
|
237
|
+
@vars << [:prechaptername, param]
|
238
|
+
end
|
239
|
+
|
240
|
+
def postchaptername param
|
241
|
+
@vars << [:postchaptername, param]
|
242
|
+
end
|
243
|
+
|
244
|
+
def template param
|
245
|
+
@template = param
|
246
|
+
end
|
247
|
+
|
248
|
+
def filter param
|
249
|
+
@filter = param
|
250
|
+
end
|
251
|
+
|
252
|
+
def vars_option
|
253
|
+
result = []
|
254
|
+
@vars.concat([[:book_name, @book.name]]).each { |v|
|
255
|
+
result << "-V"
|
256
|
+
result << "#{v[0]}=#{v[1]}"
|
257
|
+
}
|
258
|
+
result
|
259
|
+
end
|
260
|
+
|
261
|
+
def template_option
|
262
|
+
"--template=#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@template}"
|
263
|
+
end
|
264
|
+
|
265
|
+
def filter_option
|
266
|
+
"--filter=#{Dir::getwd}/theme/#{@theme}/#{@name}/#{@filter}"
|
267
|
+
end
|
268
|
+
|
269
|
+
def tex_path
|
270
|
+
tmp_path(@book.name) + '.tex'
|
271
|
+
end
|
272
|
+
|
273
|
+
def json_path
|
274
|
+
tmp_path(@book.name) + '.json'
|
275
|
+
end
|
276
|
+
|
277
|
+
def dvi_path
|
278
|
+
tmp_path(@book.name) + '.dvi'
|
279
|
+
end
|
280
|
+
|
281
|
+
def pdf_path
|
282
|
+
if @output
|
283
|
+
output_path(@output) + '.pdf'
|
284
|
+
else
|
285
|
+
output_path(@book.name) + '.pdf'
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def extractbb_cmd
|
290
|
+
"extractbb"
|
291
|
+
end
|
292
|
+
|
293
|
+
def _build_resource files, option
|
294
|
+
copy_to_tmp files
|
295
|
+
files.each { |file|
|
296
|
+
xbb = File.dirname(tmp_path(file.file)) + "/" + File.basename(tmp_path(file.file), ".*") + ".xbb"
|
297
|
+
unless FileTest.exist?(xbb) && File::mtime(tmp_path(file.file)) <= File::mtime(xbb)
|
298
|
+
cmd_exec extractbb_cmd, [tmp_path(file.file)], option
|
299
|
+
end
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
def build_resource option
|
304
|
+
_build_resource @book.resource_files, option
|
305
|
+
end
|
306
|
+
|
307
|
+
def pandoc_cmd
|
308
|
+
"pandoc"
|
309
|
+
end
|
310
|
+
|
311
|
+
def pandoc_option option
|
312
|
+
[
|
313
|
+
"--chapters",
|
314
|
+
"-f",
|
315
|
+
"markdown_phpextra+hard_line_breaks+raw_tex",
|
316
|
+
"-s",
|
317
|
+
template_option,
|
318
|
+
filter_option
|
319
|
+
]
|
320
|
+
end
|
321
|
+
|
322
|
+
def latex_cmd
|
323
|
+
"uplatex"
|
324
|
+
end
|
325
|
+
|
326
|
+
def dvipdfm_cmd
|
327
|
+
"dvipdfmx"
|
328
|
+
end
|
329
|
+
|
330
|
+
def build option
|
331
|
+
if option['pandoc-json-output']
|
332
|
+
cmd_exec pandoc_cmd, ["-o", json_path, "-t", "json"].concat(pandoc_option option).concat(vars_option).concat(@book.src_files.map{ |f| f.full_path }), option
|
333
|
+
end
|
334
|
+
cmd_exec pandoc_cmd, ["-o", tex_path, "-t", "latex"].concat(pandoc_option option).concat(vars_option).concat(@book.src_files.map{ |f| f.full_path }), option
|
335
|
+
|
336
|
+
build_resource option
|
337
|
+
|
338
|
+
f = open(tmp_path(@book.name + ".before_body.tex"), "w") do |io|
|
339
|
+
io.puts @hyoushi.map { |h| h.latex @book, self} .join()
|
340
|
+
end
|
341
|
+
|
342
|
+
f = open(tmp_path(@book.name + ".after_body.tex"), "w") do |io|
|
343
|
+
io.puts @urahyoushi.map { |h| h.latex @book, self }.join()
|
344
|
+
end
|
345
|
+
cmd_exec latex_cmd, ["-output-directory=#{tmp_path ""}", tex_path], option
|
346
|
+
cmd_exec latex_cmd, ["-output-directory=#{tmp_path ""}", tex_path], option
|
347
|
+
unless FileTest.exist?(pdf_path) && (File::mtime(dvi_path) <= File::mtime(pdf_path))
|
348
|
+
cmd_exec "cd #{Shellwords.shellescape(tmp_path "")};#{dvipdfm_cmd}", ["-o", pdf_path, dvi_path], option
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
def epub_builder name, &block
|
353
|
+
call = CallEpubBuilder.new name, self
|
354
|
+
if block
|
355
|
+
call.instance_eval &block
|
356
|
+
end
|
357
|
+
call.validate
|
358
|
+
@builders << call
|
359
|
+
end
|
360
|
+
|
361
|
+
def latex_builder name, &block
|
362
|
+
call = CallLatexBuilder.new name, self
|
363
|
+
if block
|
364
|
+
call.instance_eval &block
|
365
|
+
end
|
366
|
+
call.validate
|
367
|
+
@builders << call
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Xpub
|
2
|
+
class CallBook
|
3
|
+
class CallLatexBuilder
|
4
|
+
class CallLatexOp
|
5
|
+
def initialize name, book, builder
|
6
|
+
@name = name
|
7
|
+
@book = book
|
8
|
+
@builder = builder
|
9
|
+
end
|
10
|
+
def validate
|
11
|
+
end
|
12
|
+
|
13
|
+
def template_path
|
14
|
+
"#{Dir::getwd}/theme/#{@builder.theme}/#{@name}/#{@metadata}.erb"
|
15
|
+
end
|
16
|
+
|
17
|
+
def latex book, builder
|
18
|
+
f = open template_path
|
19
|
+
erb = ERB.new f.read, nil, "-"
|
20
|
+
f.close
|
21
|
+
erb.result(binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class CallImgPageLatexOp < CallLatexOp
|
27
|
+
def initialize name, book, builder
|
28
|
+
@topoffset = "0in"
|
29
|
+
@leftoffset = "0in"
|
30
|
+
super name, book, builder
|
31
|
+
end
|
32
|
+
|
33
|
+
def topoffset param
|
34
|
+
@topoffset = param
|
35
|
+
end
|
36
|
+
|
37
|
+
def leftoffset param
|
38
|
+
@leftoffset = param
|
39
|
+
end
|
40
|
+
|
41
|
+
def file param
|
42
|
+
@file = param
|
43
|
+
end
|
44
|
+
|
45
|
+
def latex book, builder
|
46
|
+
<<"EOS"
|
47
|
+
\\enlargethispage{200truemm}%
|
48
|
+
\\thispagestyle{empty}%
|
49
|
+
\\vspace*{-1truein}
|
50
|
+
\\vspace*{-\\hoffset}
|
51
|
+
\\vspace*{-\\oddsidemargin}
|
52
|
+
\\vspace*{#{@leftoffset}}
|
53
|
+
\\noindent\\hspace*{-1in}\\hspace*{-\\voffset}\\hspace*{-\\topmargin}\\hspace*{-\\headheight}\\hspace*{-\\headsep}\\hspace*{#{@topoffset}}
|
54
|
+
\\includegraphics[width=\\paperheight,height=\\paperwidth]{#{@file}}
|
55
|
+
\\clearpage\n
|
56
|
+
EOS
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class CallEmptyPageLatexOp < CallLatexOp
|
61
|
+
def initialize name, book, builder
|
62
|
+
@no_page_number = false
|
63
|
+
super name, book, builder
|
64
|
+
end
|
65
|
+
|
66
|
+
def no_page_number
|
67
|
+
@no_page_number = true
|
68
|
+
end
|
69
|
+
|
70
|
+
def latex book, builder
|
71
|
+
(@no_page_number ? "\\thispagestyle{empty}" : "") + " \\clearpage\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class CallInnerTitlePageLatexOp < CallLatexOp
|
76
|
+
def initialize name, book, builder
|
77
|
+
super name, book, builder
|
78
|
+
end
|
79
|
+
|
80
|
+
def latex book, builder
|
81
|
+
<<"EOS"
|
82
|
+
\\makeatletter
|
83
|
+
{
|
84
|
+
\\thispagestyle{empty}%
|
85
|
+
\\if@twocolumn\\@restonecoltrue\\onecolumn
|
86
|
+
\\else\\@restonecolfalse\\newpage\\fi
|
87
|
+
\\begin{minipage}<y>[c]{\\textheight}
|
88
|
+
\\begin{center}
|
89
|
+
\\vspace*{2.5cm}
|
90
|
+
{\\bf \\Huge #{book.title}}
|
91
|
+
\\end{center}
|
92
|
+
\\vspace*{0.5cm}
|
93
|
+
\\begin{center}
|
94
|
+
{\\bf \\Large #{book.subtitle}}
|
95
|
+
\\end{center}
|
96
|
+
\\vspace*{1.5cm}
|
97
|
+
\\begin{center}
|
98
|
+
{\\Large #{book.creators.map { |c| c.name }.join " "}}
|
99
|
+
\\end{center}
|
100
|
+
\\vspace*{1.5cm}
|
101
|
+
\\begin{flushleft}
|
102
|
+
#{book.description}
|
103
|
+
\\end{flushleft}
|
104
|
+
\\end{minipage}
|
105
|
+
\\if@restonecol\\twocolumn\\else\\newpage\\fi
|
106
|
+
}%
|
107
|
+
\\makeatother
|
108
|
+
EOS
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def hyoushi_image_page name, &block
|
113
|
+
call = CallImgPageLatexOp.new name, @book, self
|
114
|
+
if block
|
115
|
+
call.instance_eval &block
|
116
|
+
end
|
117
|
+
call.validate
|
118
|
+
@hyoushi << call
|
119
|
+
end
|
120
|
+
|
121
|
+
def hyoushi_empty_page name, &block
|
122
|
+
call = CallEmptyPageLatexOp.new name, @book, self
|
123
|
+
if block
|
124
|
+
call.instance_eval &block
|
125
|
+
end
|
126
|
+
call.validate
|
127
|
+
@hyoushi << call
|
128
|
+
end
|
129
|
+
|
130
|
+
def hyoushi_inner_title_page name, &block
|
131
|
+
call = CallInnerTitlePageLatexOp.new name, @book, self
|
132
|
+
if block
|
133
|
+
call.instance_eval &block
|
134
|
+
end
|
135
|
+
call.validate
|
136
|
+
@hyoushi << call
|
137
|
+
end
|
138
|
+
|
139
|
+
def urahyoushi_image_page name, &block
|
140
|
+
call = CallImgPageLatexOp.new name, @book, self
|
141
|
+
if block
|
142
|
+
call.instance_eval &block
|
143
|
+
end
|
144
|
+
call.validate
|
145
|
+
@urahyoushi << call
|
146
|
+
end
|
147
|
+
|
148
|
+
def urahyoushi_empty_page name, &block
|
149
|
+
call = CallEmptyPageLatexOp.new name, @book, self
|
150
|
+
if block
|
151
|
+
call.instance_eval &block
|
152
|
+
end
|
153
|
+
call.validate
|
154
|
+
@urahyoushi << call
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|