review 0.6.0
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/COPYING +515 -0
- data/ChangeLog +1278 -0
- data/README.rdoc +21 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/bin/review-check +190 -0
- data/bin/review-checkdep +63 -0
- data/bin/review-compile +165 -0
- data/bin/review-epubmaker +525 -0
- data/bin/review-index +108 -0
- data/bin/review-preproc +140 -0
- data/bin/review-validate +51 -0
- data/bin/review-vol +106 -0
- data/doc/format.re +486 -0
- data/doc/format.txt +434 -0
- data/doc/format_idg.txt +194 -0
- data/doc/format_sjis.txt +313 -0
- data/doc/sample.css +91 -0
- data/doc/sample.yaml +46 -0
- data/lib/lineinput.rb +155 -0
- data/lib/review/book.rb +580 -0
- data/lib/review/builder.rb +274 -0
- data/lib/review/compat.rb +22 -0
- data/lib/review/compiler.rb +483 -0
- data/lib/review/epubbuilder.rb +692 -0
- data/lib/review/ewbbuilder.rb +382 -0
- data/lib/review/exception.rb +21 -0
- data/lib/review/htmlbuilder.rb +370 -0
- data/lib/review/htmllayout.rb +19 -0
- data/lib/review/htmlutils.rb +27 -0
- data/lib/review/idgxmlbuilder.rb +1078 -0
- data/lib/review/index.rb +224 -0
- data/lib/review/latexbuilder.rb +420 -0
- data/lib/review/latexindex.rb +35 -0
- data/lib/review/latexutils.rb +52 -0
- data/lib/review/preprocessor.rb +520 -0
- data/lib/review/textutils.rb +19 -0
- data/lib/review/tocparser.rb +333 -0
- data/lib/review/tocprinter.rb +220 -0
- data/lib/review/topbuilder.rb +572 -0
- data/lib/review/unfold.rb +138 -0
- data/lib/review/volume.rb +66 -0
- data/lib/review.rb +4 -0
- data/review.gemspec +93 -0
- data/setup.rb +1587 -0
- data/test/test_epubbuilder.rb +73 -0
- data/test/test_helper.rb +2 -0
- data/test/test_htmlbuilder.rb +42 -0
- data/test/test_latexbuilder.rb +74 -0
- metadata +122 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# $Id: textutils.rb 2192 2005-11-13 11:55:42Z aamine $
|
2
|
+
|
3
|
+
module ReVIEW
|
4
|
+
|
5
|
+
module TextUtils
|
6
|
+
|
7
|
+
def detab(str, ts = 8)
|
8
|
+
add = 0
|
9
|
+
len = nil
|
10
|
+
str.gsub(/\t/) {
|
11
|
+
len = ts - ($`.size + add) % ts
|
12
|
+
add += len - 1
|
13
|
+
' ' * len
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,333 @@
|
|
1
|
+
#
|
2
|
+
# $Id: tocparser.rb 4268 2009-05-27 04:17:08Z kmuto $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2007 Minero Aoki
|
5
|
+
# 2008-2009 Minero Aoki, Kenshi Muto
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute or modify this program under the terms of
|
9
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'review/preprocessor'
|
14
|
+
require 'review/book'
|
15
|
+
require 'review/volume'
|
16
|
+
require 'forwardable'
|
17
|
+
|
18
|
+
module ReVIEW
|
19
|
+
|
20
|
+
class TOCParser
|
21
|
+
|
22
|
+
def TOCParser.parse(chap)
|
23
|
+
chap.open {|f|
|
24
|
+
stream = Preprocessor::Strip.new(f)
|
25
|
+
new.parse(stream, chap.id, chap.path).map {|root|
|
26
|
+
root.number = chap.number
|
27
|
+
root
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse(f, id, filename)
|
33
|
+
roots = []
|
34
|
+
path = []
|
35
|
+
|
36
|
+
while line = f.gets
|
37
|
+
case line
|
38
|
+
when /\A\s*\z/
|
39
|
+
;
|
40
|
+
when /\A(={2,})[\[\s]/
|
41
|
+
lev = $1.size
|
42
|
+
error! filename, f.lineno, "section level too deep: #{lev}" if lev > 5
|
43
|
+
if path.empty?
|
44
|
+
# missing chapter label
|
45
|
+
path.push Chapter.new(get_label(line), id, filename)
|
46
|
+
roots.push path.first
|
47
|
+
end
|
48
|
+
new = Section.new(lev, get_label(line))
|
49
|
+
until path.last.level < new.level
|
50
|
+
path.pop
|
51
|
+
end
|
52
|
+
path.last.add_child new
|
53
|
+
path.push new
|
54
|
+
|
55
|
+
when /\A= /
|
56
|
+
path.clear
|
57
|
+
path.push Chapter.new(get_label(line), id, filename)
|
58
|
+
roots.push path.first
|
59
|
+
|
60
|
+
when %r<\A//\w+(?:\[.*?\])*\{\s*\z>
|
61
|
+
if path.empty?
|
62
|
+
error! filename, f.lineno, 'list found before section label'
|
63
|
+
end
|
64
|
+
path.last.add_child(list = List.new)
|
65
|
+
beg = f.lineno
|
66
|
+
list.add line
|
67
|
+
while line = f.gets
|
68
|
+
break if %r<\A//\}> =~ line
|
69
|
+
list.add line
|
70
|
+
end
|
71
|
+
error! filename, beg, 'unterminated list' unless line
|
72
|
+
|
73
|
+
when %r<\A//\w>
|
74
|
+
;
|
75
|
+
else
|
76
|
+
#if path.empty?
|
77
|
+
# error! filename, f.lineno, 'text found before section label'
|
78
|
+
#end
|
79
|
+
next if path.empty?
|
80
|
+
path.last.add_child(par = Paragraph.new)
|
81
|
+
par.add line
|
82
|
+
while line = f.gets
|
83
|
+
break if /\A\s*\z/ =~ line
|
84
|
+
par.add line
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
roots
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_label(line)
|
93
|
+
line.strip.sub(/\A=+\s*/, '')
|
94
|
+
end
|
95
|
+
|
96
|
+
def error!(filename, lineno, msg)
|
97
|
+
raise "#{filename}:#{lineno}: #{msg}"
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
class Node
|
102
|
+
|
103
|
+
def initialize(children = [])
|
104
|
+
@children = children
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :children
|
108
|
+
|
109
|
+
def add_child(c)
|
110
|
+
@children.push c
|
111
|
+
end
|
112
|
+
|
113
|
+
def each_node(&block)
|
114
|
+
@children.each do |c|
|
115
|
+
yield c
|
116
|
+
c.each(&block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def each_child(&block)
|
121
|
+
@children.each(&block)
|
122
|
+
end
|
123
|
+
|
124
|
+
def chapter?
|
125
|
+
false
|
126
|
+
end
|
127
|
+
|
128
|
+
def each_section(&block)
|
129
|
+
@children.each do |n|
|
130
|
+
n.yield_section(&block)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def each_section_with_index
|
135
|
+
i = 0
|
136
|
+
each_section do |n|
|
137
|
+
yield n, i
|
138
|
+
i += 1
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def n_sections
|
143
|
+
cnt = 0
|
144
|
+
@children.each do |n|
|
145
|
+
n.yield_section { cnt += 1 }
|
146
|
+
end
|
147
|
+
cnt
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
class Section < Node
|
154
|
+
|
155
|
+
def initialize(level, label, path = nil)
|
156
|
+
super()
|
157
|
+
@level = level
|
158
|
+
@label = label
|
159
|
+
@filename = (path ? real_filename(path) : nil)
|
160
|
+
end
|
161
|
+
|
162
|
+
def real_filename(path)
|
163
|
+
if FileTest.symlink?(path)
|
164
|
+
File.basename(File.readlink(path))
|
165
|
+
else
|
166
|
+
File.basename(path)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
private :real_filename
|
170
|
+
|
171
|
+
attr_reader :level
|
172
|
+
attr_reader :label
|
173
|
+
|
174
|
+
def display_label
|
175
|
+
if @filename
|
176
|
+
@label + ' ' + @filename
|
177
|
+
else
|
178
|
+
@label
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def estimated_lines
|
183
|
+
@children.inject(0) {|sum, n| sum + n.estimated_lines }
|
184
|
+
end
|
185
|
+
|
186
|
+
def yield_section
|
187
|
+
yield self
|
188
|
+
end
|
189
|
+
|
190
|
+
def inspect
|
191
|
+
"\#<#{self.class} level=#{@level} #{@label}>"
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
class Chapter < Section
|
198
|
+
|
199
|
+
def initialize(label, id, path)
|
200
|
+
super 1, label, path
|
201
|
+
@chapter_id = id
|
202
|
+
@path = path
|
203
|
+
@volume = nil
|
204
|
+
@number = nil
|
205
|
+
end
|
206
|
+
|
207
|
+
attr_accessor :number
|
208
|
+
|
209
|
+
def chapter?
|
210
|
+
true
|
211
|
+
end
|
212
|
+
|
213
|
+
attr_reader :chapter_id
|
214
|
+
|
215
|
+
def volume
|
216
|
+
return @volume if @volume
|
217
|
+
return Volume.dummy unless @path
|
218
|
+
@volume = Volume.count_file(@path)
|
219
|
+
@volume.lines = estimated_lines()
|
220
|
+
@volume
|
221
|
+
end
|
222
|
+
|
223
|
+
def inspect
|
224
|
+
"\#<#{self.class} #{@filename}>"
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
class Paragraph < Node
|
231
|
+
|
232
|
+
def initialize
|
233
|
+
@bytes = 0
|
234
|
+
end
|
235
|
+
|
236
|
+
def inspect
|
237
|
+
"\#<#{self.class}>"
|
238
|
+
end
|
239
|
+
|
240
|
+
def add(line)
|
241
|
+
@bytes += line.strip.bytesize
|
242
|
+
end
|
243
|
+
|
244
|
+
def estimated_lines
|
245
|
+
(@bytes + 2) / ReVIEW.book.page_metric.text.n_columns + 1
|
246
|
+
end
|
247
|
+
|
248
|
+
def yield_section
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
class List < Node
|
255
|
+
|
256
|
+
def initialize
|
257
|
+
@lines = 0
|
258
|
+
end
|
259
|
+
|
260
|
+
def inspect
|
261
|
+
"\#<#{self.class}>"
|
262
|
+
end
|
263
|
+
|
264
|
+
def add(line)
|
265
|
+
@lines += 1
|
266
|
+
end
|
267
|
+
|
268
|
+
def estimated_lines
|
269
|
+
@lines + 2
|
270
|
+
end
|
271
|
+
|
272
|
+
def yield_section
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
module TOCRoot
|
281
|
+
def level
|
282
|
+
0
|
283
|
+
end
|
284
|
+
|
285
|
+
def chapter?
|
286
|
+
false
|
287
|
+
end
|
288
|
+
|
289
|
+
def each_section_with_index
|
290
|
+
idx = -1
|
291
|
+
each_section do |node|
|
292
|
+
yield node, (idx += 1)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def each_section(&block)
|
297
|
+
each_chapter do |chap|
|
298
|
+
yield chap.toc
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def n_sections
|
303
|
+
chapters.size
|
304
|
+
end
|
305
|
+
|
306
|
+
def estimated_lines
|
307
|
+
chapters.inject(0) {|sum, chap| sum + chap.toc.estimated_lines }
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
class Book # reopen
|
312
|
+
include TOCRoot
|
313
|
+
end
|
314
|
+
|
315
|
+
class ChapterSet # reopen
|
316
|
+
include TOCRoot
|
317
|
+
end
|
318
|
+
|
319
|
+
class Part
|
320
|
+
include TOCRoot
|
321
|
+
end
|
322
|
+
|
323
|
+
class Chapter # reopen
|
324
|
+
def toc
|
325
|
+
@toc ||= TOCParser.parse(self)
|
326
|
+
unless @toc.size == 1
|
327
|
+
$stderr.puts "warning: chapter #{title} contains more than 1 chapter"
|
328
|
+
end
|
329
|
+
@toc.first
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
#
|
2
|
+
# $Id: tocprinter.rb 4309 2009-07-19 04:15:02Z aamine $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2007 Minero Aoki
|
5
|
+
# 2008-2009 Minero Aoki, Kenshi Muto
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute or modify this program under the terms of
|
9
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
+
# For details of LGPL, see the file "COPYING".
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'review/htmlutils'
|
14
|
+
require 'review/htmllayout'
|
15
|
+
require 'nkf'
|
16
|
+
|
17
|
+
module ReVIEW
|
18
|
+
|
19
|
+
class TOCPrinter
|
20
|
+
|
21
|
+
def TOCPrinter.default_upper_level
|
22
|
+
99 # no one use 99 level nest
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(print_upper, param)
|
26
|
+
@print_upper = print_upper
|
27
|
+
@param = param
|
28
|
+
end
|
29
|
+
|
30
|
+
def print?(level)
|
31
|
+
level <= @print_upper
|
32
|
+
end
|
33
|
+
|
34
|
+
def nkffilter(line)
|
35
|
+
inc = ""
|
36
|
+
outc = "-w"
|
37
|
+
if @param["inencoding"] =~ /^EUC$/
|
38
|
+
inc = "-E"
|
39
|
+
elsif @param["inencoding"] =~ /^SJIS$/
|
40
|
+
inc = "-S"
|
41
|
+
elsif @param["inencoding"] =~ /^JIS$/
|
42
|
+
inc = "-J"
|
43
|
+
end
|
44
|
+
|
45
|
+
if @param["outencoding"] =~ /^EUC$/
|
46
|
+
outc = "-e"
|
47
|
+
elsif @param["outencoding"] =~ /^SJIS$/
|
48
|
+
outc = "-s"
|
49
|
+
elsif @param["outencoding"] =~ /^JIS$/
|
50
|
+
outc = "-j"
|
51
|
+
end
|
52
|
+
|
53
|
+
NKF.nkf("#{inc} #{outc}", line)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class TextTOCPrinter < TOCPrinter
|
59
|
+
def print_book(book)
|
60
|
+
print_children book
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def print_children(node)
|
66
|
+
return unless print?(node.level + 1)
|
67
|
+
node.each_section_with_index do |section, idx|
|
68
|
+
print_node idx+1, section
|
69
|
+
print_children section
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def print_node(number, node)
|
74
|
+
if node.chapter?
|
75
|
+
vol = node.volume
|
76
|
+
printf "%3s %3dKB %6dC %5dL %s (%s)\n",
|
77
|
+
chapnumstr(node.number),
|
78
|
+
vol.kbytes, vol.chars, vol.lines,
|
79
|
+
nkffilter(node.label), node.chapter_id
|
80
|
+
else
|
81
|
+
printf "%17s %5dL %s\n",
|
82
|
+
'', node.estimated_lines,
|
83
|
+
nkffilter(" #{' ' * (node.level - 1)}#{number} #{node.label}")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def chapnumstr(n)
|
88
|
+
n ? sprintf('%2d.', n) : ' '
|
89
|
+
end
|
90
|
+
|
91
|
+
def volume_columns(level, volstr)
|
92
|
+
cols = ["", "", "", nil]
|
93
|
+
cols[level - 1] = volstr
|
94
|
+
cols[0, 3] # does not display volume of level-4 section
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
class HTMLTOCPrinter < TOCPrinter
|
101
|
+
|
102
|
+
include HTMLUtils
|
103
|
+
|
104
|
+
def print_book(book)
|
105
|
+
return unless print?(1)
|
106
|
+
html = ""
|
107
|
+
book.each_part do |part|
|
108
|
+
html << h1(part.name) if part.name
|
109
|
+
part.each_section do |chap|
|
110
|
+
if chap.number
|
111
|
+
name = "chap#{chap.number}"
|
112
|
+
label = "第#{chap.number}章 #{chap.label}"
|
113
|
+
html << h2(a_name(escape_html(name), escape_html(label)))
|
114
|
+
else
|
115
|
+
label = "#{chap.label}"
|
116
|
+
html << h2(escape_html(label))
|
117
|
+
end
|
118
|
+
return unless print?(2)
|
119
|
+
if print?(3)
|
120
|
+
html << chap_sections_to_s(chap)
|
121
|
+
else
|
122
|
+
html << chapter_to_s(chap)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
puts HTMLLayout.new(html, "目次", File.join(book.basedir, "layouts", "layout.erb")).result
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def chap_sections_to_s(chap)
|
132
|
+
res = []
|
133
|
+
res << "<ol>"
|
134
|
+
chap.each_section do |sec|
|
135
|
+
res << li(escape_html(sec.label))
|
136
|
+
end
|
137
|
+
res << "</ol>"
|
138
|
+
return res.join("\n")
|
139
|
+
end
|
140
|
+
|
141
|
+
def print_chapter_to_s(chap)
|
142
|
+
res = []
|
143
|
+
chap.each_section do |sec|
|
144
|
+
res << h3(escape_html(sec.label))
|
145
|
+
next unless print?(4)
|
146
|
+
next if sec.n_sections == 0
|
147
|
+
res << "<ul>"
|
148
|
+
sec.each_section do |node|
|
149
|
+
res << li(escape_html(node.label))
|
150
|
+
end
|
151
|
+
res << "</ul>"
|
152
|
+
end
|
153
|
+
return res.join("\n")
|
154
|
+
end
|
155
|
+
|
156
|
+
def h1(label)
|
157
|
+
"<h1>#{label}</h1>"
|
158
|
+
end
|
159
|
+
|
160
|
+
def h2(label)
|
161
|
+
"<h2>#{label}</h2>"
|
162
|
+
end
|
163
|
+
|
164
|
+
def h3(label)
|
165
|
+
"<h3>#{label}</h3>"
|
166
|
+
end
|
167
|
+
|
168
|
+
def li(content)
|
169
|
+
"<li>#{content}</li>"
|
170
|
+
end
|
171
|
+
|
172
|
+
def a_name(name, label)
|
173
|
+
%Q(<a name="#{name}">#{label}</a>)
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
class IDGTOCPrinter < TOCPrinter
|
179
|
+
def print_book(book)
|
180
|
+
puts %Q(<?xml version="1.0" encoding="UTF-8"?>)
|
181
|
+
puts nkffilter(%Q(<doc xmlns:aid='http://ns.adobe.com/AdobeInDesign/4.0/'><title aid:pstyle="h0">1 パート1</title><?dtp level="0" section="第1部 パート1"?>)) # FIXME: 部タイトルを取るには? & 部ごとに結果を分けるには?
|
182
|
+
puts %Q(<ul aid:pstyle='ul-partblock'>)
|
183
|
+
print_children book
|
184
|
+
puts %Q(</ul></doc>)
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def print_children(node)
|
190
|
+
return unless print?(node.level + 1)
|
191
|
+
node.each_section_with_index do |sec, idx|
|
192
|
+
print_node idx+1, sec
|
193
|
+
print_children sec
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
LABEL_LEN = 54
|
198
|
+
|
199
|
+
def print_node(seq, node)
|
200
|
+
if node.chapter?
|
201
|
+
vol = node.volume
|
202
|
+
printf "<li aid:pstyle='ul-part'>%s</li>\n",
|
203
|
+
nkffilter("#{chapnumstr(node.number)}#{node.label}")
|
204
|
+
else
|
205
|
+
printf "<li>%-#{LABEL_LEN}s\n",
|
206
|
+
nkffilter(" #{' ' * (node.level - 1)}#{seq} #{node.label}</li>")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def chapnumstr(n)
|
211
|
+
n ? nkffilter(sprintf('第%d章 ', n)) : ''
|
212
|
+
end
|
213
|
+
|
214
|
+
def volume_columns(level, volstr)
|
215
|
+
cols = ["", "", "", nil]
|
216
|
+
cols[level - 1] = volstr
|
217
|
+
cols[0, 3]
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|