review-retrovert 0.2.2 → 0.9.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 +4 -4
- data/.github/workflows/retrovert.yml +39 -0
- data/.gitignore +2 -2
- data/.ruby-version +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +68 -2
- data/README.md +6 -3
- data/lib/review/retrovert/cli.rb +2 -0
- data/lib/review/retrovert/converter.rb +255 -16
- data/lib/review/retrovert/version.rb +1 -1
- data/review-retrovert.gemspec +1 -1
- data/testdata/mybook/.gitignore +7 -0
- data/testdata/mybook/README.md +43 -0
- data/testdata/mybook/Rakefile +16 -0
- data/testdata/mybook/catalog.yml +33 -0
- data/testdata/mybook/config-starter.yml +139 -0
- data/testdata/mybook/config.yml +375 -0
- data/testdata/mybook/contents/00-preface.re +83 -0
- data/testdata/mybook/contents/01-install.re +272 -0
- data/testdata/mybook/contents/02-tutorial.re +1008 -0
- data/testdata/mybook/contents/03-syntax.re +2613 -0
- data/testdata/mybook/contents/04-customize.re +728 -0
- data/testdata/mybook/contents/05-faq.re +328 -0
- data/testdata/mybook/contents/06-bestpractice.re +971 -0
- data/testdata/mybook/contents/91-compare.re +18 -0
- data/testdata/mybook/contents/92-filelist.re +119 -0
- data/testdata/mybook/contents/93-background.re +267 -0
- data/testdata/mybook/contents/99-postface.re +38 -0
- data/testdata/mybook/css/normalize.css +349 -0
- data/testdata/mybook/css/webstyle.css +514 -0
- data/testdata/mybook/images/03-syntax/favicon-16x16.png +0 -0
- data/testdata/mybook/images/03-syntax/figure_heretop.png +0 -0
- data/testdata/mybook/images/03-syntax/tw-icon1.jpg +0 -0
- data/testdata/mybook/images/03-syntax/tw-icon2.jpg +0 -0
- data/testdata/mybook/images/03-syntax/tw-icon3.jpg +0 -0
- data/testdata/mybook/images/03-syntax/tw-icon4.jpg +0 -0
- data/testdata/mybook/images/04-customize/caption_pagebreak.png +0 -0
- data/testdata/mybook/images/04-customize/chaptitlepage_sample.png +0 -0
- data/testdata/mybook/images/05-faq/codeblock_rpadding1.png +0 -0
- data/testdata/mybook/images/05-faq/codeblock_rpadding2.png +0 -0
- data/testdata/mybook/images/06-bestpractice/figure_heretop.png +0 -0
- data/testdata/mybook/images/06-bestpractice/font_beramono.png +0 -0
- data/testdata/mybook/images/06-bestpractice/heading_design1.png +0 -0
- data/testdata/mybook/images/06-bestpractice/heading_design2.png +0 -0
- data/testdata/mybook/images/06-bestpractice/margin_book.png +0 -0
- data/testdata/mybook/images/06-bestpractice/multiline-title.png +0 -0
- data/testdata/mybook/images/06-bestpractice/preface_numbered.png +0 -0
- data/testdata/mybook/images/06-bestpractice/program_border.png +0 -0
- data/testdata/mybook/images/06-bestpractice/sechead_design_4.png +0 -0
- data/testdata/mybook/images/06-bestpractice/titlepage-samples.png +0 -0
- data/testdata/mybook/images/93-background/bug913.png +0 -0
- data/testdata/mybook/images/93-background/slide2.png +0 -0
- data/testdata/mybook/images/cover_a5.pdf +0 -0
- data/testdata/mybook/images/cover_b5.pdf +0 -0
- data/testdata/mybook/images/tw-icon.jpg +0 -0
- data/testdata/mybook/layouts/layout.epub.erb +29 -0
- data/testdata/mybook/layouts/layout.html5.erb +106 -0
- data/testdata/mybook/layouts/layout.tex.erb +546 -0
- data/testdata/mybook/lib/hooks/beforetexcompile.rb +55 -0
- data/testdata/mybook/lib/ruby/review-builder.rb +503 -0
- data/testdata/mybook/lib/ruby/review-cli.rb +58 -0
- data/testdata/mybook/lib/ruby/review-compiler.rb +523 -0
- data/testdata/mybook/lib/ruby/review-epubmaker.rb +606 -0
- data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +661 -0
- data/testdata/mybook/lib/ruby/review-latexbuilder.rb +782 -0
- data/testdata/mybook/lib/ruby/review-maker.rb +235 -0
- data/testdata/mybook/lib/ruby/review-monkeypatch.rb +91 -0
- data/testdata/mybook/lib/ruby/review-pdfmaker.rb +468 -0
- data/testdata/mybook/lib/ruby/review-textbuilder.rb +36 -0
- data/testdata/mybook/lib/ruby/review-tocparser.rb +285 -0
- data/testdata/mybook/lib/ruby/review-webmaker.rb +433 -0
- data/testdata/mybook/lib/tasks/mytasks.rake +31 -0
- data/testdata/mybook/lib/tasks/review.rake +142 -0
- data/testdata/mybook/lib/tasks/review.rake.orig +72 -0
- data/testdata/mybook/lib/tasks/starter.rake +326 -0
- data/testdata/mybook/locale.yml +6 -0
- data/testdata/mybook/review-ext.rb +206 -0
- data/testdata/mybook/sty/jumoline.sty +310 -0
- data/testdata/mybook/sty/mycolophon.sty +81 -0
- data/testdata/mybook/sty/mystyle.sty +8 -0
- data/testdata/mybook/sty/mytextsize.sty +61 -0
- data/testdata/mybook/sty/mytitlepage.sty +103 -0
- data/testdata/mybook/sty/reviewmacro.sty +60 -0
- data/testdata/mybook/sty/starter-codeblock.sty +332 -0
- data/testdata/mybook/sty/starter-color.sty +79 -0
- data/testdata/mybook/sty/starter-font.sty +112 -0
- data/testdata/mybook/sty/starter-heading.sty +514 -0
- data/testdata/mybook/sty/starter-note.sty +127 -0
- data/testdata/mybook/sty/starter-section.sty +262 -0
- data/testdata/mybook/sty/starter-toc.sty +72 -0
- data/testdata/mybook/sty/starter.sty +554 -0
- data/testdata/mybook/style.css +597 -0
- metadata +100 -3
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
###
|
4
|
+
### ReVIEW::TEXTBuilderクラスを拡張する
|
5
|
+
###
|
6
|
+
|
7
|
+
require 'review/textbuilder'
|
8
|
+
|
9
|
+
|
10
|
+
module ReVIEW
|
11
|
+
|
12
|
+
defined?(TEXTBuilder) or raise "internal error: TEXTBuilder not found."
|
13
|
+
|
14
|
+
|
15
|
+
class TEXTBuilder
|
16
|
+
|
17
|
+
## ファイル名
|
18
|
+
def inline_file(str)
|
19
|
+
on_inline_file { escape(str) }
|
20
|
+
end
|
21
|
+
def on_inline_file
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
|
25
|
+
## ユーザ入力
|
26
|
+
def inline_userinput(str)
|
27
|
+
on_inline_input { escape(str) }
|
28
|
+
end
|
29
|
+
def on_inline_userinput
|
30
|
+
yield
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2008-2017 Minero Aoki, Kenshi Muto
|
3
|
+
# 2002-2007 Minero Aoki
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute or modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'review/preprocessor'
|
12
|
+
require 'review/book'
|
13
|
+
require 'review/textbuilder'
|
14
|
+
|
15
|
+
module ReVIEW
|
16
|
+
|
17
|
+
|
18
|
+
class TOCParser
|
19
|
+
|
20
|
+
def self.parse(chap)
|
21
|
+
f = StringIO.new(chap.content, 'r:BOM|utf-8')
|
22
|
+
stream = Preprocessor::Strip.new(f)
|
23
|
+
parser = self.new
|
24
|
+
return parser.parse(stream, chap).map {|root|
|
25
|
+
root.number = chap.number
|
26
|
+
root
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.chapter_node(chap)
|
31
|
+
toc = self.parse(chap)
|
32
|
+
if toc.size != 1
|
33
|
+
$stderr.puts "warning: chapter #{toc.join} contains more than 1 chapter"
|
34
|
+
end
|
35
|
+
toc.first
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse(stream, chap)
|
39
|
+
f = stream
|
40
|
+
roots = [] # list of chapters
|
41
|
+
node_stack = []
|
42
|
+
filename = chap.path
|
43
|
+
while (line = f.gets)
|
44
|
+
case line
|
45
|
+
when /\A\#@\+\+\+$/
|
46
|
+
beg = f.lineno
|
47
|
+
line = f.gets() while line && line !~ /\A\#@---$/
|
48
|
+
line or
|
49
|
+
error! filename, beg, 'unterminated list'
|
50
|
+
next
|
51
|
+
when /\A\#@/
|
52
|
+
# do nothing
|
53
|
+
next
|
54
|
+
when /\A\s*\z/
|
55
|
+
# do nothing
|
56
|
+
next
|
57
|
+
when /\A(={2,})[\[\s\{]/
|
58
|
+
lev = $1.size
|
59
|
+
lev <= 6 or
|
60
|
+
error! filename, f.lineno, "section level too deep: #{lev}"
|
61
|
+
label = get_label(line)
|
62
|
+
if node_stack.empty?
|
63
|
+
# missing chapter label
|
64
|
+
dummy_chapter = Chapter.new(label, chap)
|
65
|
+
node_stack.push dummy_chapter
|
66
|
+
roots.push dummy_chapter
|
67
|
+
end
|
68
|
+
next if label.start_with?('[/') # ex) "[/column]"
|
69
|
+
sec = Section.new(lev, label.gsub(/\A\{.*?\}\s?/, ''))
|
70
|
+
node_stack.pop until node_stack.last.level < sec.level
|
71
|
+
node_stack.last.add_child sec
|
72
|
+
node_stack.push sec
|
73
|
+
|
74
|
+
when /\A=[^=]/
|
75
|
+
label = get_label(line)
|
76
|
+
node_stack.clear
|
77
|
+
new_chapter = Chapter.new(label, chap)
|
78
|
+
node_stack.push new_chapter
|
79
|
+
roots.push new_chapter
|
80
|
+
|
81
|
+
when %r{\A//\w+(?:\[.*?\])*\{\s*\z}
|
82
|
+
! node_stack.empty? or
|
83
|
+
error! filename, f.lineno, 'list found before section label'
|
84
|
+
node_stack.last.add_child(list = List.new)
|
85
|
+
beg = f.lineno
|
86
|
+
list.add line
|
87
|
+
while (line = f.gets) && ! line.start_with?('//}')
|
88
|
+
list.add line
|
89
|
+
end
|
90
|
+
line or
|
91
|
+
error! filename, beg, 'unterminated list'
|
92
|
+
|
93
|
+
when /\A\/\/\w/
|
94
|
+
# do nothing
|
95
|
+
next
|
96
|
+
else
|
97
|
+
# if node_stack.empty?
|
98
|
+
# error! filename, f.lineno, 'text found before section label'
|
99
|
+
# end
|
100
|
+
next if node_stack.empty?
|
101
|
+
node_stack.last.add_child(par = Paragraph.new(chap))
|
102
|
+
par.add line
|
103
|
+
while (line = f.gets) && line !~ /\A\s*\z/
|
104
|
+
par.add line
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
roots
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_label(line)
|
113
|
+
line = line.strip.sub(/\A=+\s*/, '')
|
114
|
+
compile_label(line)
|
115
|
+
end
|
116
|
+
|
117
|
+
def compile_label(line)
|
118
|
+
b = ReVIEW::TEXTBuilder.new
|
119
|
+
dummy_book = ReVIEW::Book::Base.load
|
120
|
+
dummy_chapter = ReVIEW::Book::Chapter.new(dummy_book, 1, '-', nil, StringIO.new)
|
121
|
+
dummy_loc = Location.new('', StringIO.new)
|
122
|
+
b.bind(ReVIEW::Compiler.new(b), dummy_chapter, dummy_loc)
|
123
|
+
b.compile_inline(line)
|
124
|
+
end
|
125
|
+
|
126
|
+
def error!(filename, lineno, msg)
|
127
|
+
raise "#{filename}:#{lineno}: #{msg}"
|
128
|
+
end
|
129
|
+
|
130
|
+
# class Node
|
131
|
+
# def initialize(children = [])
|
132
|
+
# @children = children
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# attr_reader :children
|
136
|
+
#
|
137
|
+
# def add_child(c)
|
138
|
+
# @children.push c
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# def each_node(&block)
|
142
|
+
# @children.each do |c|
|
143
|
+
# yield c
|
144
|
+
# c.each(&block)
|
145
|
+
# end
|
146
|
+
# end
|
147
|
+
#
|
148
|
+
# def each_child(&block)
|
149
|
+
# @children.each(&block)
|
150
|
+
# end
|
151
|
+
#
|
152
|
+
# def chapter?
|
153
|
+
# false
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# def each_section(&block)
|
157
|
+
# @children.each { |n| n.yield_section(&block) }
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# def each_section_with_index
|
161
|
+
# i = 0
|
162
|
+
# each_section do |n|
|
163
|
+
# yield n, i
|
164
|
+
# i += 1
|
165
|
+
# end
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# def section_size
|
169
|
+
# cnt = 0
|
170
|
+
# @children.each { |n| n.yield_section { cnt += 1 } }
|
171
|
+
# cnt
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# class Section < Node
|
176
|
+
# def initialize(level, label, path = nil)
|
177
|
+
# super()
|
178
|
+
# @level = level
|
179
|
+
# @label = label
|
180
|
+
# @filename = path ? real_filename(path) : nil
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# def real_filename(path)
|
184
|
+
# if FileTest.symlink?(path)
|
185
|
+
# File.basename(File.readlink(path))
|
186
|
+
# else
|
187
|
+
# File.basename(path)
|
188
|
+
# end
|
189
|
+
# end
|
190
|
+
# private :real_filename
|
191
|
+
#
|
192
|
+
# attr_reader :level
|
193
|
+
# attr_reader :label
|
194
|
+
#
|
195
|
+
# def estimated_lines
|
196
|
+
# @children.inject(0) { |sum, n| sum + n.estimated_lines }
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# def yield_section
|
200
|
+
# yield self
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# def inspect
|
204
|
+
# "#<#{self.class} level=#{@level} #{@label}>"
|
205
|
+
# end
|
206
|
+
# end
|
207
|
+
#
|
208
|
+
# class Chapter < Section
|
209
|
+
# def initialize(label, chap)
|
210
|
+
# super 1, label, chap.path
|
211
|
+
# @chapter = chap
|
212
|
+
# @chapter_id = chap.id
|
213
|
+
# @path = chap.path
|
214
|
+
# @page_metric = chap.book.page_metric
|
215
|
+
# @volume = nil
|
216
|
+
# @number = nil
|
217
|
+
# end
|
218
|
+
#
|
219
|
+
# attr_accessor :number
|
220
|
+
#
|
221
|
+
# def chapter?
|
222
|
+
# true
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# attr_reader :chapter_id
|
226
|
+
#
|
227
|
+
# def volume
|
228
|
+
# return @volume if @volume
|
229
|
+
# @volume = @chapter.volume
|
230
|
+
# @volume.lines = estimated_lines
|
231
|
+
# @volume
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
# def inspect
|
235
|
+
# "#<#{self.class} #{@filename}>"
|
236
|
+
# end
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# class Paragraph < Node
|
240
|
+
# def initialize(chap)
|
241
|
+
# @bytes = 0
|
242
|
+
# @page_metric = chap.book.page_metric
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# def inspect
|
246
|
+
# "#<#{self.class}>"
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# def add(line)
|
250
|
+
# @bytes += line.strip.bytesize
|
251
|
+
# end
|
252
|
+
#
|
253
|
+
# def estimated_lines
|
254
|
+
# (@bytes + 2) / @page_metric.text.n_columns + 1
|
255
|
+
# end
|
256
|
+
#
|
257
|
+
# def yield_section
|
258
|
+
# end
|
259
|
+
# end
|
260
|
+
#
|
261
|
+
# class List < Node
|
262
|
+
# def initialize
|
263
|
+
# @lines = 0
|
264
|
+
# end
|
265
|
+
#
|
266
|
+
# def inspect
|
267
|
+
# "#<#{self.class}>"
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# def add(_line)
|
271
|
+
# @lines += 1
|
272
|
+
# end
|
273
|
+
#
|
274
|
+
# def estimated_lines
|
275
|
+
# @lines + 2
|
276
|
+
# end
|
277
|
+
#
|
278
|
+
# def yield_section
|
279
|
+
# end
|
280
|
+
# end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
end
|
@@ -0,0 +1,433 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
###
|
4
|
+
### ReVIEW::WEBMakerクラスを書き直す
|
5
|
+
### (でも元がひどすぎるので書き直すにも限界がある)
|
6
|
+
###
|
7
|
+
|
8
|
+
require 'pathname'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'erb'
|
11
|
+
require 'review/converter'
|
12
|
+
require 'review/htmlbuilder'
|
13
|
+
require 'review/template'
|
14
|
+
require 'review/webmaker'
|
15
|
+
require_relative './review-maker'
|
16
|
+
|
17
|
+
|
18
|
+
module ReVIEW
|
19
|
+
|
20
|
+
remove_const :WEBMaker
|
21
|
+
|
22
|
+
|
23
|
+
class WEBMaker < Maker
|
24
|
+
|
25
|
+
SCRIPT_NAME = "review-webmaker"
|
26
|
+
|
27
|
+
def initialize(*args)
|
28
|
+
super
|
29
|
+
@config['htmlext'] = 'html'
|
30
|
+
@docroot = @config['docroot'] || 'webroot'
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate()
|
34
|
+
remove_old_files()
|
35
|
+
FileUtils.mkdir_p(@docroot)
|
36
|
+
#
|
37
|
+
@book = ReVIEW::Book.load(@basedir)
|
38
|
+
@book.config = @config
|
39
|
+
#
|
40
|
+
copy_stylesheet()
|
41
|
+
copy_frontmatter()
|
42
|
+
build_body()
|
43
|
+
copy_backmatter()
|
44
|
+
#
|
45
|
+
imagedir = @config['imagedir']
|
46
|
+
destdir = "#{@docroot}/#{imagedir}"
|
47
|
+
copy_images(imagedir, destdir)
|
48
|
+
#
|
49
|
+
copy_resources('covers', destdir)
|
50
|
+
copy_resources('adv', destdir)
|
51
|
+
copy_resources(@config['fontdir'], "#{@docroot}/fonts", @config['font_ext'])
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_body()
|
55
|
+
base_path = Pathname.new(@basedir)
|
56
|
+
@converter = ReVIEW::Converter.new(@book, new_builder())
|
57
|
+
@book.parts.each do |part|
|
58
|
+
if part.name.present?
|
59
|
+
if part.file?
|
60
|
+
build_chap(part, base_path, true)
|
61
|
+
else
|
62
|
+
htmlfile = "part_#{part.number}.#{@config['htmlext']}"
|
63
|
+
build_part(part, htmlfile)
|
64
|
+
# title = ReVIEW::I18n.t('part', part.number)
|
65
|
+
# title += ReVIEW::I18n.t('chapter_postfix') + part.name.strip unless part.name.strip.empty?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
part.chapters.each do |chap|
|
69
|
+
build_chap(chap, base_path, false)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def new_builder()
|
75
|
+
builder = ReVIEW::WEBBuilder.new()
|
76
|
+
builder.starter_config = @starter_config
|
77
|
+
return builder
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_renderer()
|
81
|
+
return WEBRenderer.new(@config, @book, @basedir, @starter_config)
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_part(part, htmlfile)
|
85
|
+
new_renderer().render_part(part, File.join(@docroot, htmlfile))
|
86
|
+
end
|
87
|
+
|
88
|
+
def build_chap(chap, base_path, ispart)
|
89
|
+
filename = \
|
90
|
+
if ispart.present?
|
91
|
+
chap.path
|
92
|
+
else
|
93
|
+
Pathname.new(chap.path).relative_path_from(base_path).to_s
|
94
|
+
end
|
95
|
+
chapter_id = filename.sub(/\.re\Z/, '')
|
96
|
+
htmlfile = "#{chapter_id}.#{@config['htmlext']}"
|
97
|
+
#
|
98
|
+
if @config['params'].present?
|
99
|
+
warn "'params:' in config.yml is obsoleted."
|
100
|
+
end
|
101
|
+
#
|
102
|
+
begin
|
103
|
+
@converter.convert(filename, File.join(@docroot, htmlfile))
|
104
|
+
rescue => ex
|
105
|
+
warn "compile error in #{filename} (#{ex.class})"
|
106
|
+
warn ex.message
|
107
|
+
generate_errorpage(ex, filename, htmlfile)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def remove_old_files()
|
112
|
+
math_dir = "./#{@config['imagedir']}/_review_math"
|
113
|
+
FileUtils.rm_rf(math_dir) if @config['imgmath'] && Dir.exist?(math_dir)
|
114
|
+
FileUtils.rm_rf(@docroot)
|
115
|
+
end
|
116
|
+
|
117
|
+
def copy_images(srcdir, destdir)
|
118
|
+
copy_resources(srcdir, destdir, nil)
|
119
|
+
end
|
120
|
+
|
121
|
+
def copy_resources(srcdir, destdir, allow_exts=nil)
|
122
|
+
if srcdir && File.exist?(srcdir)
|
123
|
+
FileUtils.mkdir_p(destdir)
|
124
|
+
allow_exts ||= @config['image_ext']
|
125
|
+
ok = allow_exts && ! allow_exts.empty?
|
126
|
+
ext_rexp = ok ? /\.(#{allow_exts.join('|')})\Z/i : nil
|
127
|
+
_recursive_copy_files(srcdir, destdir, ext_rexp)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def _recursive_copy_files(srcdir, destdir, ext_rexp)
|
132
|
+
Dir.open(srcdir) do |dir|
|
133
|
+
dir.each do |fname|
|
134
|
+
next if fname.start_with?('.')
|
135
|
+
srcpath = "#{srcdir}/#{fname}"
|
136
|
+
if File.directory?(srcpath)
|
137
|
+
destpath = "#{destdir}/#{fname}"
|
138
|
+
_recursive_copy_files(srcpath, destpath, ext_rexp)
|
139
|
+
elsif ext_rexp.nil? || fname =~ ext_rexp
|
140
|
+
FileUtils.mkdir_p(destdir)
|
141
|
+
FileUtils.cp(srcpath, destdir)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def copy_stylesheet()
|
148
|
+
cssdir = File.join(@docroot, "css")
|
149
|
+
Dir.mkdir(cssdir) unless File.directory?(cssdir)
|
150
|
+
[@config['stylesheet']].flatten.compact.each do |x|
|
151
|
+
FileUtils.cp("css/#{x}", cssdir)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def copy_frontmatter()
|
156
|
+
generate_indexpage('index.html')
|
157
|
+
#
|
158
|
+
if @config['titlepage']
|
159
|
+
destfile = "titlepage.#{@config['htmlext']}"
|
160
|
+
if @config['titlefile']
|
161
|
+
FileUtils.cp(@config['titlefile'], "#{@docroot}/#{destfile}")
|
162
|
+
else
|
163
|
+
generate_titlepage(destfile)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
#
|
167
|
+
_copy_file(@config['creditfile'])
|
168
|
+
_copy_file(@config['originaltitlefile'])
|
169
|
+
end
|
170
|
+
|
171
|
+
def generate_errorpage(ex, filename, htmlfile)
|
172
|
+
s = new_renderer().render_exception(ex, filename)
|
173
|
+
File.write(File.join(@docroot, htmlfile), s)
|
174
|
+
end
|
175
|
+
|
176
|
+
def generate_indexpage(htmlfile)
|
177
|
+
s = new_renderer().render_indexpage()
|
178
|
+
File.write(File.join(@docroot, htmlfile), s)
|
179
|
+
rescue => ex
|
180
|
+
generate_errorpage(ex, nil, htmlfile)
|
181
|
+
end
|
182
|
+
|
183
|
+
def generate_titlepage(htmlfile)
|
184
|
+
s = new_renderer().render_titlepage()
|
185
|
+
File.write(File.join(@docroot, htmlfile), s)
|
186
|
+
end
|
187
|
+
|
188
|
+
def copy_backmatter()
|
189
|
+
conf = @config
|
190
|
+
ext = conf['htmlext']
|
191
|
+
_copy_file(conf['profile'])
|
192
|
+
_copy_file(conf['advfile'])
|
193
|
+
_copy_file(conf['colophon'], "colophon.#{ext}") if conf['colophon'].is_a?(String)
|
194
|
+
_copy_file(conf['backcover'])
|
195
|
+
end
|
196
|
+
|
197
|
+
def _copy_file(srcfile, destfile=nil)
|
198
|
+
if srcfile && File.exist?(srcfile)
|
199
|
+
destfile ||= File.basename(srcfile)
|
200
|
+
FileUtils.cp(srcfile, File.join(@docroot, destfile))
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
class WEBBuilder < HTMLBuilder
|
208
|
+
|
209
|
+
def layoutfile
|
210
|
+
"layouts/layout.html5.erb"
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
class WEBRenderer < BaseRenderer
|
217
|
+
|
218
|
+
def initialize(*args)
|
219
|
+
super
|
220
|
+
@language = @config['language']
|
221
|
+
@stylesheets = @config['stylesheet']
|
222
|
+
end
|
223
|
+
|
224
|
+
def layout_template_name()
|
225
|
+
#if @config['htmlversion'].to_i == 5
|
226
|
+
# 'web/html/layout-html5.html.erb'
|
227
|
+
#else
|
228
|
+
# 'web/html/layout-xhtml1.html.erb'
|
229
|
+
#end
|
230
|
+
"layout.html5.erb"
|
231
|
+
end
|
232
|
+
|
233
|
+
def render_exception(error, textfile)
|
234
|
+
@error = error
|
235
|
+
@textfile = textfile
|
236
|
+
#
|
237
|
+
return render()
|
238
|
+
end
|
239
|
+
|
240
|
+
def render_part(part)
|
241
|
+
part_name = part.name.strip
|
242
|
+
#
|
243
|
+
sb = ""
|
244
|
+
sb << "<div class=\"part\">\n"
|
245
|
+
sb << "<h1 class=\"part-number\">#{i18n('part', part.number)}</h1>\n"
|
246
|
+
sb << "<h2 class=\"part-title\">#{part_name}</h2>\n" if part_name.present?
|
247
|
+
sb << "</div>\n"
|
248
|
+
@body = sb
|
249
|
+
#
|
250
|
+
return render()
|
251
|
+
end
|
252
|
+
|
253
|
+
def render_indexpage()
|
254
|
+
if @config['coverimage']
|
255
|
+
imgfile = File.join(@config['imagedir'], @config['coverimage'])
|
256
|
+
else
|
257
|
+
imgfile = nil
|
258
|
+
end
|
259
|
+
#
|
260
|
+
sb = ""
|
261
|
+
if imgfile
|
262
|
+
sb << " <div id=\"cover-image\" class=\"cover-image\">\n"
|
263
|
+
sb << " <img src=\"#{imgfile}\" class=\"max\"/>\n"
|
264
|
+
sb << " </div>\n"
|
265
|
+
end
|
266
|
+
@body = sb
|
267
|
+
@toc = ReVIEW::WEBTOCPrinter.book_to_html(@book, nil)
|
268
|
+
@next = @book.chapters[0]
|
269
|
+
@next_title = @next ? @next.title : ''
|
270
|
+
#
|
271
|
+
return render()
|
272
|
+
end
|
273
|
+
|
274
|
+
def render_titlepage()
|
275
|
+
author = @config['aut'] ? _join_names(@config.names_of('aut')) : nil
|
276
|
+
publisher = @config['pbl'] ? _join_names(@config.names_of('pbl')) : nil
|
277
|
+
#
|
278
|
+
sb = ""
|
279
|
+
sb << "<div class=\"titlepage\">\n"
|
280
|
+
sb << "<h1 class=\"tp-title\">#{h @config.name_of('booktitle')}</h1>\n"
|
281
|
+
sb << "<h2 class=\"tp-author\">#{author}</h2>\n" if author
|
282
|
+
sb << "<h3 class=\"tp-publisher\">#{publisher}</h3>\n" if publisher
|
283
|
+
sb << "</div>\n"
|
284
|
+
@body = sb
|
285
|
+
#
|
286
|
+
return render()
|
287
|
+
end
|
288
|
+
|
289
|
+
private
|
290
|
+
|
291
|
+
def _join_names(names)
|
292
|
+
sep = i18n('names_splitter')
|
293
|
+
return [names].flatten.join(sep)
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
class WEBTOCPrinter
|
300
|
+
|
301
|
+
def self.book_to_html(book, current_chapter)
|
302
|
+
printer = self.new(nil, nil, nil)
|
303
|
+
arr = printer.handle_book(book, current_chapter)
|
304
|
+
html = printer.render_html(arr)
|
305
|
+
return html
|
306
|
+
end
|
307
|
+
|
308
|
+
def render_html(arr)
|
309
|
+
tag, attr, children = arr
|
310
|
+
tag == "book" or raise "internal error: tag=#{tag.inspect}"
|
311
|
+
buf = "<ul class=\"toc toc-1\">\n"
|
312
|
+
children.each do |child|
|
313
|
+
_render_li(child, buf, 1)
|
314
|
+
end
|
315
|
+
buf << "</ul>\n"
|
316
|
+
return buf
|
317
|
+
end
|
318
|
+
|
319
|
+
def parse_inline(str)
|
320
|
+
builder = HTMLBuilder.new
|
321
|
+
builder.instance_variable_set('@book', @_book)
|
322
|
+
@compiler ||= Compiler.new(builder)
|
323
|
+
return @compiler.text(str)
|
324
|
+
end
|
325
|
+
|
326
|
+
def _render_li(arr, buf, n)
|
327
|
+
tag, attr, children = arr
|
328
|
+
case tag
|
329
|
+
when "part"
|
330
|
+
buf << "<li class=\"toc-part\">#{parse_inline(attr[:label])}\n"
|
331
|
+
buf << " <ul class=\"toc toc-#{n+1}\">\n"
|
332
|
+
children.each {|child| _render_li(child, buf, n+1) }
|
333
|
+
buf << " </ul>\n"
|
334
|
+
buf << "</li>\n"
|
335
|
+
when "chapter"
|
336
|
+
buf << " <li class=\"toc-chapter\"><a href=\"#{h attr[:path]}\">#{parse_inline(attr[:label])}</a>"
|
337
|
+
if children && !children.empty?
|
338
|
+
buf << "\n <ul class=\"toc toc-#{n+1}\">\n"
|
339
|
+
children.each {|child| _render_li(child, buf, n+1) }
|
340
|
+
buf << " </ul>\n"
|
341
|
+
buf << " </li>\n"
|
342
|
+
else
|
343
|
+
buf << "</li>\n"
|
344
|
+
end
|
345
|
+
when "section"
|
346
|
+
buf << " <li class=\"toc-section\"><a href=\"##{attr[:anchor]}\">#{parse_inline(attr[:label])}</a></li>\n"
|
347
|
+
end
|
348
|
+
buf
|
349
|
+
end
|
350
|
+
|
351
|
+
def handle_book(book, current_chapter)
|
352
|
+
@_book = book
|
353
|
+
children = []
|
354
|
+
book.each_part do |part|
|
355
|
+
if part.number
|
356
|
+
children << handle_part(part, current_chapter)
|
357
|
+
else
|
358
|
+
part.each_chapter do |chap|
|
359
|
+
children << handle_chapter(chap, current_chapter)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
#
|
364
|
+
attrs = {
|
365
|
+
title: book.config['booktitle'],
|
366
|
+
subtitle: book.config['subtitle'],
|
367
|
+
}
|
368
|
+
return ["book", attrs, children]
|
369
|
+
end
|
370
|
+
|
371
|
+
def handle_part(part, current_chapter)
|
372
|
+
children = []
|
373
|
+
part.each_chapter do |chap|
|
374
|
+
children << handle_chapter(chap, current_chapter)
|
375
|
+
end
|
376
|
+
#
|
377
|
+
attrs = {
|
378
|
+
number: part.number,
|
379
|
+
title: part.title,
|
380
|
+
#label: "#{I18n.t('part_short', part.number)} #{part.title}",
|
381
|
+
label: "#{I18n.t('part', part.number)} #{part.title}",
|
382
|
+
}
|
383
|
+
return ["part", attrs, children]
|
384
|
+
end
|
385
|
+
|
386
|
+
def handle_chapter(chap, current_chapter)
|
387
|
+
children = []
|
388
|
+
if current_chapter.nil? || chap == current_chapter
|
389
|
+
chap.headline_index.each do |sec|
|
390
|
+
next if sec.number.present? && sec.number.length >= 2
|
391
|
+
children << handle_section(sec, chap)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
#
|
395
|
+
chap_node = TOCParser.chapter_node(chap)
|
396
|
+
ext = chap.book.config['htmlext'] || 'html'
|
397
|
+
path = chap.path.sub(/\.re\z/, ".#{ext}")
|
398
|
+
label = if chap_node.number && chap.on_chaps?
|
399
|
+
"#{I18n.t('chapter_short', chap.number)} #{chap.title}"
|
400
|
+
else
|
401
|
+
chap.title
|
402
|
+
end
|
403
|
+
#
|
404
|
+
attrs = {
|
405
|
+
number: chap_node.number,
|
406
|
+
title: chap.title,
|
407
|
+
label: label,
|
408
|
+
path: path,
|
409
|
+
}
|
410
|
+
return ["chapter", attrs, children]
|
411
|
+
end
|
412
|
+
|
413
|
+
def handle_section(sec, chap)
|
414
|
+
if chap.number && sec.number.length > 0
|
415
|
+
number = [chap.number] + sec.number
|
416
|
+
label = "#{number.join('.')} #{sec.caption}"
|
417
|
+
else
|
418
|
+
number = nil
|
419
|
+
label = sec.caption
|
420
|
+
end
|
421
|
+
attrs = {
|
422
|
+
number: number,
|
423
|
+
title: sec.caption,
|
424
|
+
label: label,
|
425
|
+
anchor: "h#{number ? number.join('-') : ''}",
|
426
|
+
}
|
427
|
+
return ["section", attrs, []]
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
|
433
|
+
end
|