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
data/lib/lineinput.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
#
|
2
|
+
# $Id: lineinput.rb 2226 2006-04-15 03:05:09Z aamine $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2005 Minero Aoki
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute/modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
#
|
10
|
+
|
11
|
+
class LineInput
|
12
|
+
|
13
|
+
def initialize(f)
|
14
|
+
@input = f
|
15
|
+
@buf = []
|
16
|
+
@lineno = 0
|
17
|
+
@eof_p = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"\#<#{self.class} file=#{@f.inspect} line=#{lineno()}>"
|
22
|
+
end
|
23
|
+
|
24
|
+
def eof?
|
25
|
+
@eof_p
|
26
|
+
end
|
27
|
+
|
28
|
+
def lineno
|
29
|
+
@lineno
|
30
|
+
end
|
31
|
+
|
32
|
+
def gets
|
33
|
+
unless @buf.empty?
|
34
|
+
@lineno += 1
|
35
|
+
return @buf.pop
|
36
|
+
end
|
37
|
+
return nil if @eof_p # to avoid ARGF blocking.
|
38
|
+
line = @input.gets
|
39
|
+
@eof_p = true unless line
|
40
|
+
@lineno += 1
|
41
|
+
line
|
42
|
+
end
|
43
|
+
|
44
|
+
def ungets(line)
|
45
|
+
return unless line
|
46
|
+
@lineno -= 1
|
47
|
+
@buf.push line
|
48
|
+
line
|
49
|
+
end
|
50
|
+
|
51
|
+
def peek
|
52
|
+
line = gets()
|
53
|
+
ungets line if line
|
54
|
+
line
|
55
|
+
end
|
56
|
+
|
57
|
+
def next?
|
58
|
+
peek() ? true : false
|
59
|
+
end
|
60
|
+
|
61
|
+
def skip_blank_lines
|
62
|
+
n = 0
|
63
|
+
while line = gets()
|
64
|
+
unless line.strip.empty?
|
65
|
+
ungets line
|
66
|
+
return n
|
67
|
+
end
|
68
|
+
n += 1
|
69
|
+
end
|
70
|
+
n
|
71
|
+
end
|
72
|
+
|
73
|
+
def gets_if(re)
|
74
|
+
line = gets()
|
75
|
+
if not line or not (re =~ line)
|
76
|
+
ungets line
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
line
|
80
|
+
end
|
81
|
+
|
82
|
+
def gets_unless(re)
|
83
|
+
line = gets()
|
84
|
+
if not line or re =~ line
|
85
|
+
ungets line
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
line
|
89
|
+
end
|
90
|
+
|
91
|
+
def each
|
92
|
+
while line = gets()
|
93
|
+
yield line
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def while_match(re)
|
98
|
+
while line = gets()
|
99
|
+
unless re =~ line
|
100
|
+
ungets line
|
101
|
+
return
|
102
|
+
end
|
103
|
+
yield line
|
104
|
+
end
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def getlines_while(re)
|
109
|
+
buf = []
|
110
|
+
while_match(re) do |line|
|
111
|
+
buf.push line
|
112
|
+
end
|
113
|
+
buf
|
114
|
+
end
|
115
|
+
|
116
|
+
alias span getlines_while # from Haskell
|
117
|
+
|
118
|
+
def until_match(re)
|
119
|
+
while line = gets()
|
120
|
+
if re =~ line
|
121
|
+
ungets line
|
122
|
+
return
|
123
|
+
end
|
124
|
+
yield line
|
125
|
+
end
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def getlines_until(re)
|
130
|
+
buf = []
|
131
|
+
until_match(re) do |line|
|
132
|
+
buf.push line
|
133
|
+
end
|
134
|
+
buf
|
135
|
+
end
|
136
|
+
|
137
|
+
alias break getlines_until # from Haskell
|
138
|
+
|
139
|
+
def until_terminator(re)
|
140
|
+
while line = gets()
|
141
|
+
return if re =~ line # discard terminal line
|
142
|
+
yield line
|
143
|
+
end
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def getblock(term_re)
|
148
|
+
buf = []
|
149
|
+
until_terminator(term_re) do |line|
|
150
|
+
buf.push line
|
151
|
+
end
|
152
|
+
buf
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
data/lib/review/book.rb
ADDED
@@ -0,0 +1,580 @@
|
|
1
|
+
#
|
2
|
+
# $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2008 Minero Aoki
|
5
|
+
# 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/index'
|
14
|
+
require 'review/volume'
|
15
|
+
require 'review/exception'
|
16
|
+
require 'review/compat'
|
17
|
+
require 'forwardable'
|
18
|
+
require 'nkf'
|
19
|
+
|
20
|
+
module ReVIEW
|
21
|
+
|
22
|
+
@default_book = nil
|
23
|
+
|
24
|
+
def ReVIEW.book
|
25
|
+
@default_book ||= Book.load_default
|
26
|
+
end
|
27
|
+
|
28
|
+
class Book
|
29
|
+
|
30
|
+
def Book.load_default
|
31
|
+
%w( . .. ../.. ).each do |basedir|
|
32
|
+
if File.file?("#{basedir}/PARAMS") or File.file?("#{basedir}/CHAPS")
|
33
|
+
return load(basedir)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
new('.')
|
37
|
+
end
|
38
|
+
|
39
|
+
def Book.load(dir)
|
40
|
+
update_rubyenv dir
|
41
|
+
if File.file?("#{dir}/PARAMS")
|
42
|
+
then new(dir, Parameters.load("#{dir}/PARAMS"))
|
43
|
+
else new(dir)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def setParameter(param)
|
48
|
+
@param = param
|
49
|
+
end
|
50
|
+
|
51
|
+
@basedir_seen = {}
|
52
|
+
|
53
|
+
def Book.update_rubyenv(dir)
|
54
|
+
return if @basedir_seen.key?(dir)
|
55
|
+
if File.directory?("#{dir}/lib/review")
|
56
|
+
$LOAD_PATH.unshift "#{dir}/lib"
|
57
|
+
end
|
58
|
+
if File.file?("#{dir}/review-ext.rb")
|
59
|
+
Kernel.load File.expand_path("#{dir}/review-ext.rb")
|
60
|
+
end
|
61
|
+
@basedir_seen[dir] = true
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(basedir, parameters = Parameters.default)
|
65
|
+
@basedir = basedir
|
66
|
+
@parameters = parameters
|
67
|
+
@parts = nil
|
68
|
+
@chapter_index = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
extend Forwardable
|
72
|
+
def_delegators '@parameters',
|
73
|
+
:chapter_file,
|
74
|
+
:part_file,
|
75
|
+
:bib_file,
|
76
|
+
:index_file,
|
77
|
+
:reject_file,
|
78
|
+
:nocode_file,
|
79
|
+
:predef_file,
|
80
|
+
:postdef_file,
|
81
|
+
:ext,
|
82
|
+
:image_dir,
|
83
|
+
:image_types,
|
84
|
+
:page_metric
|
85
|
+
|
86
|
+
def no_part?
|
87
|
+
false
|
88
|
+
end
|
89
|
+
|
90
|
+
def parts
|
91
|
+
@parts ||= read_parts()
|
92
|
+
end
|
93
|
+
|
94
|
+
def part(n)
|
95
|
+
parts.detect {|part| part.number == n }
|
96
|
+
end
|
97
|
+
|
98
|
+
def each_part(&block)
|
99
|
+
parts.each(&block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def chapters
|
103
|
+
parts().map {|p| p.chapters }.flatten
|
104
|
+
end
|
105
|
+
|
106
|
+
def each_chapter(&block)
|
107
|
+
chapters.each(&block)
|
108
|
+
end
|
109
|
+
|
110
|
+
def chapter_index
|
111
|
+
@chapter_index ||= ChapterIndex.new(chapters())
|
112
|
+
@chapter_index.setParameter(@param)
|
113
|
+
@chapter_index
|
114
|
+
end
|
115
|
+
|
116
|
+
def chapter(id)
|
117
|
+
chapter_index()[id]
|
118
|
+
end
|
119
|
+
|
120
|
+
def volume
|
121
|
+
Volume.sum(chapters.map {|chap| chap.volume })
|
122
|
+
end
|
123
|
+
|
124
|
+
def read_CHAPS
|
125
|
+
File.read("#{@basedir}/#{chapter_file}")
|
126
|
+
rescue Errno::ENOENT
|
127
|
+
Dir.glob("#{@basedir}/*#{ext()}").sort.join("\n")
|
128
|
+
end
|
129
|
+
|
130
|
+
def read_PART
|
131
|
+
@read_PART ||= File.read("#{@basedir}/#{part_file}")
|
132
|
+
end
|
133
|
+
|
134
|
+
def part_exist?
|
135
|
+
File.exist?("#{@basedir}/#{part_file}")
|
136
|
+
end
|
137
|
+
|
138
|
+
def read_bib
|
139
|
+
File.read("#{@basedir}/#{bib_file}")
|
140
|
+
end
|
141
|
+
|
142
|
+
def bib_exist?
|
143
|
+
File.exist?("#{@basedir}/#{bib_file}")
|
144
|
+
end
|
145
|
+
|
146
|
+
def prefaces
|
147
|
+
if File.file?("#{@basedir}/#{predef_file}")
|
148
|
+
begin
|
149
|
+
return mkpart_from_namelistfile("#{@basedir}/#{predef_file}")
|
150
|
+
rescue FileNotFound => err
|
151
|
+
raise FileNotFound, "preface #{err.message}"
|
152
|
+
end
|
153
|
+
else
|
154
|
+
mkpart_from_namelist(%w(preface))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def postscripts
|
159
|
+
if File.file?("#{@basedir}/#{postdef_file}")
|
160
|
+
begin
|
161
|
+
return mkpart_from_namelistfile("#{@basedir}/#{postdef_file}")
|
162
|
+
rescue FileNotFound => err
|
163
|
+
raise FileNotFound, "postscript #{err.message}"
|
164
|
+
end
|
165
|
+
else
|
166
|
+
mkpart_from_namelist(%w(appendix postscript))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def basedir
|
171
|
+
@basedir
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def read_parts
|
177
|
+
list = parse_chapters
|
178
|
+
if pre = prefaces
|
179
|
+
list.unshift pre
|
180
|
+
end
|
181
|
+
if post = postscripts
|
182
|
+
list.push post
|
183
|
+
end
|
184
|
+
list
|
185
|
+
end
|
186
|
+
|
187
|
+
def parse_chapters
|
188
|
+
part = 0
|
189
|
+
num = 0
|
190
|
+
chap = read_CHAPS()\
|
191
|
+
.strip.lines.map {|line| line.strip }.join("\n").split(/\n{2,}/)\
|
192
|
+
.map {|part_chunk|
|
193
|
+
chaps = part_chunk.split.map {|chapid|
|
194
|
+
Chapter.new(self, (num += 1), chapid, "#{@basedir}/#{chapid}")
|
195
|
+
}
|
196
|
+
if part_exist? && read_PART.split("\n").size >= part
|
197
|
+
Part.new((part += 1), chaps, read_PART.split("\n")[part-1])
|
198
|
+
else
|
199
|
+
Part.new((part += 1), chaps)
|
200
|
+
end
|
201
|
+
}
|
202
|
+
return chap
|
203
|
+
end
|
204
|
+
|
205
|
+
def mkpart_from_namelistfile(path)
|
206
|
+
mkpart(File.read(path).split.map {|name| mkchap(name) })
|
207
|
+
end
|
208
|
+
|
209
|
+
def mkpart_from_namelist(names)
|
210
|
+
mkpart(names.map {|n| mkchap_ifexist(n) }.compact)
|
211
|
+
end
|
212
|
+
|
213
|
+
def mkpart(chaps)
|
214
|
+
chaps.empty? ? nil : Part.new(nil, chaps)
|
215
|
+
end
|
216
|
+
|
217
|
+
def mkchap(name)
|
218
|
+
name += ext unless File.extname(name) == ext
|
219
|
+
path = "#{@basedir}/#{name}"
|
220
|
+
raise FileNotFound, "file not exist: #{path}" unless File.file?(path)
|
221
|
+
Chapter.new(self, nil, name, path)
|
222
|
+
end
|
223
|
+
|
224
|
+
def mkchap_ifexist(id)
|
225
|
+
name = "#{id}#{ext()}"
|
226
|
+
path = "#{@basedir}/#{name}"
|
227
|
+
File.file?(path) ? Chapter.new(self, nil, name, path) : nil
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
class ChapterSet
|
234
|
+
|
235
|
+
def ChapterSet.for_argv
|
236
|
+
if ARGV.empty?
|
237
|
+
new([Chapter.for_stdin])
|
238
|
+
else
|
239
|
+
for_pathes(ARGV)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def ChapterSet.for_pathes(pathes)
|
244
|
+
new(Chapter.intern_pathes(pathes))
|
245
|
+
end
|
246
|
+
|
247
|
+
def initialize(chapters)
|
248
|
+
@chapters = chapters
|
249
|
+
end
|
250
|
+
|
251
|
+
def no_part?
|
252
|
+
true
|
253
|
+
end
|
254
|
+
|
255
|
+
attr_reader :chapters
|
256
|
+
|
257
|
+
def each_chapter(&block)
|
258
|
+
@chapters.each(&block)
|
259
|
+
end
|
260
|
+
|
261
|
+
def ext
|
262
|
+
'.re'
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
class Parameters
|
269
|
+
|
270
|
+
def Parameters.default
|
271
|
+
new()
|
272
|
+
end
|
273
|
+
|
274
|
+
def Parameters.load(path)
|
275
|
+
mod = Module.new
|
276
|
+
mod.module_eval File.read(path), path
|
277
|
+
new(
|
278
|
+
:chapter_file => const_get_safe(mod, :CHAPS_FILE),
|
279
|
+
:part_file => const_get_safe(mod, :PART_FILE),
|
280
|
+
:bib_file => const_get_safe(mod, :BIB_FILE),
|
281
|
+
:index_file => const_get_safe(mod, :INDEX_FILE),
|
282
|
+
:reject_file => const_get_safe(mod, :REJECT_FILE) ||
|
283
|
+
const_get_safe(mod, :WORDS_FILE),
|
284
|
+
:nocode_file => const_get_safe(mod, :NOCODE_FILE),
|
285
|
+
:predef_file => const_get_safe(mod, :PREDEF_FILE),
|
286
|
+
:postdef_file => const_get_safe(mod, :POSTDEF_FILE),
|
287
|
+
:ext => const_get_safe(mod, :EXT),
|
288
|
+
:image_dir => const_get_safe(mod, :IMAGE_DIR),
|
289
|
+
:image_types => const_get_safe(mod, :IMAGE_TYPES),
|
290
|
+
:page_metric => get_page_metric(mod)
|
291
|
+
)
|
292
|
+
end
|
293
|
+
|
294
|
+
def Parameters.get_page_metric(mod)
|
295
|
+
if paper = const_get_safe(mod, :PAPER)
|
296
|
+
unless PageMetric.respond_to?(paper.downcase)
|
297
|
+
raise ConfigError, "unknown paper size: #{paper}"
|
298
|
+
end
|
299
|
+
return PageMetric.send(paper.downcase)
|
300
|
+
end
|
301
|
+
PageMetric.new(const_get_safe(mod, :LINES_PER_PAGE_list) || 46,
|
302
|
+
const_get_safe(mod, :COLUMNS_list) || 80,
|
303
|
+
const_get_safe(mod, :LINES_PER_PAGE_text) || 30,
|
304
|
+
const_get_safe(mod, :COLUMNS_text) || 74) # 37zw
|
305
|
+
end
|
306
|
+
|
307
|
+
def Parameters.const_get_safe(mod, name)
|
308
|
+
return nil unless mod.const_defined?(name)
|
309
|
+
mod.const_get(name)
|
310
|
+
end
|
311
|
+
private_class_method :const_get_safe
|
312
|
+
|
313
|
+
def initialize(params = {})
|
314
|
+
@chapter_file = params[:chapter_file] || 'CHAPS'
|
315
|
+
@part_file = params[:part_file] || 'CHAPS'
|
316
|
+
@index_file = params[:index_file] || 'INDEX'
|
317
|
+
@reject_file = params[:reject_file] || 'REJECT'
|
318
|
+
@nocode_file = params[:nocode_file] || 'NOCODE'
|
319
|
+
@predef_file = params[:predef_file] || 'PREDEF'
|
320
|
+
@postdef_file = params[:postdef_file] || 'POSTDEF'
|
321
|
+
@page_metric = params[:page_metric] || PageMetric.a5
|
322
|
+
@ext = params[:ext] || '.re'
|
323
|
+
@image_dir = params[:image_dir] || 'images'
|
324
|
+
@image_types = unify_exts(params[:image_types] ||
|
325
|
+
%w( eps tif tiff png bmp jpg jpeg gif svg ))
|
326
|
+
@bib_file = params[:bib_file] || "bib#{@ext}"
|
327
|
+
end
|
328
|
+
|
329
|
+
def unify_exts(list)
|
330
|
+
list.map {|ext| (ext[0] == '.') ? ext : ".#{ext}" }
|
331
|
+
end
|
332
|
+
private :unify_exts
|
333
|
+
|
334
|
+
def self.path_param(name)
|
335
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
336
|
+
def #{name}
|
337
|
+
"\#{@basedir}/\#{@#{name}}"
|
338
|
+
end
|
339
|
+
End
|
340
|
+
end
|
341
|
+
|
342
|
+
path_param :chapter_file
|
343
|
+
path_param :part_file
|
344
|
+
path_param :bib_file
|
345
|
+
path_param :index_file
|
346
|
+
path_param :reject_file
|
347
|
+
path_param :nocode_file
|
348
|
+
path_param :predef_file
|
349
|
+
path_param :postdef_file
|
350
|
+
attr_reader :ext
|
351
|
+
path_param :image_dir
|
352
|
+
attr_reader :image_types
|
353
|
+
attr_reader :page_metric
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
class PageMetric
|
359
|
+
|
360
|
+
MetricData = Struct.new(:n_lines, :n_columns)
|
361
|
+
|
362
|
+
def PageMetric.a5
|
363
|
+
new(46, 80, 30, 74, 1)
|
364
|
+
end
|
365
|
+
|
366
|
+
def PageMetric.b5
|
367
|
+
new(46, 80, 30, 74, 2)
|
368
|
+
end
|
369
|
+
|
370
|
+
def initialize(list_lines, list_columns, text_lines, text_columns, page_per_kbyte)
|
371
|
+
@list = MetricData.new(list_lines, list_columns)
|
372
|
+
@text = MetricData.new(text_lines, text_columns)
|
373
|
+
@page_per_kbyte = page_per_kbyte
|
374
|
+
end
|
375
|
+
|
376
|
+
attr_reader :list
|
377
|
+
attr_reader :text
|
378
|
+
attr_reader :page_per_kbyte
|
379
|
+
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
class Part
|
384
|
+
|
385
|
+
def initialize(number, chapters, name="")
|
386
|
+
@number = number
|
387
|
+
@chapters = chapters
|
388
|
+
@name = name
|
389
|
+
end
|
390
|
+
|
391
|
+
attr_reader :number
|
392
|
+
attr_reader :chapters
|
393
|
+
attr_reader :name
|
394
|
+
|
395
|
+
def each_chapter(&block)
|
396
|
+
@chapters.each(&block)
|
397
|
+
end
|
398
|
+
|
399
|
+
def volume
|
400
|
+
Volume.sum(@chapters.map {|chap| chap.volume })
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
class Chapter
|
407
|
+
|
408
|
+
def Chapter.intern_pathes(pathes)
|
409
|
+
books = {}
|
410
|
+
pathes.map {|path|
|
411
|
+
basedir = File.dirname(path)
|
412
|
+
book = (books[File.expand_path(basedir)] ||= Book.load(basedir))
|
413
|
+
begin
|
414
|
+
book.chapter(File.basename(path, '.*'))
|
415
|
+
rescue KeyError => err
|
416
|
+
raise FileNotFound, "no such file: #{path}"
|
417
|
+
end
|
418
|
+
}
|
419
|
+
end
|
420
|
+
|
421
|
+
def Chapter.for_stdin
|
422
|
+
new(nil, nil, '-', nil, $stdin)
|
423
|
+
end
|
424
|
+
|
425
|
+
def Chapter.for_path(number, path)
|
426
|
+
new(nil, number, File.basename(path), path)
|
427
|
+
end
|
428
|
+
|
429
|
+
def initialize(book, number, name, path, io = nil)
|
430
|
+
@book = book
|
431
|
+
@number = number
|
432
|
+
@name = name
|
433
|
+
@path = path
|
434
|
+
@io = io
|
435
|
+
@title = nil
|
436
|
+
@content = nil
|
437
|
+
@list_index = nil
|
438
|
+
@table_index = nil
|
439
|
+
@footnote_index = nil
|
440
|
+
@image_index = nil
|
441
|
+
end
|
442
|
+
|
443
|
+
def setParameter(param)
|
444
|
+
@param = param
|
445
|
+
end
|
446
|
+
|
447
|
+
def env
|
448
|
+
@book
|
449
|
+
end
|
450
|
+
|
451
|
+
def inspect
|
452
|
+
"\#<#{self.class} #{@number} #{@path}>"
|
453
|
+
end
|
454
|
+
|
455
|
+
attr_reader :book
|
456
|
+
attr_reader :number
|
457
|
+
attr_reader :path
|
458
|
+
|
459
|
+
def dirname
|
460
|
+
return nil unless @path
|
461
|
+
File.dirname(@path)
|
462
|
+
end
|
463
|
+
|
464
|
+
def basename
|
465
|
+
return nil unless @path
|
466
|
+
File.basename(@path)
|
467
|
+
end
|
468
|
+
|
469
|
+
def name
|
470
|
+
File.basename(@name, '.*')
|
471
|
+
end
|
472
|
+
|
473
|
+
alias id name
|
474
|
+
|
475
|
+
def title
|
476
|
+
@title = ""
|
477
|
+
open {|f|
|
478
|
+
f.each_line {|l|
|
479
|
+
if l =~ /\A=+/
|
480
|
+
@title = l.sub(/\A=+/, '').strip
|
481
|
+
break
|
482
|
+
end
|
483
|
+
}
|
484
|
+
}
|
485
|
+
if @param["inencoding"] =~ /^EUC$/
|
486
|
+
@title = NKF.nkf("-E -w", @title)
|
487
|
+
elsif @param["inencoding"] =~ /^SJIS$/
|
488
|
+
@title = NKF.nkf("-S -w", @title)
|
489
|
+
elsif @param["inencoding"] =~ /^JIS$/
|
490
|
+
@title = NKF.nkf("-J -w", @title)
|
491
|
+
else
|
492
|
+
@title = NKF.nkf("-w", @title)
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def size
|
497
|
+
File.size(path())
|
498
|
+
end
|
499
|
+
|
500
|
+
def volume
|
501
|
+
@volume ||= Volume.count_file(path())
|
502
|
+
end
|
503
|
+
|
504
|
+
def open(&block)
|
505
|
+
return (block_given?() ? yield(@io) : @io) if @io
|
506
|
+
File.open(path(), &block)
|
507
|
+
end
|
508
|
+
|
509
|
+
def content
|
510
|
+
if @param["inencoding"] =~ /^EUC$/i
|
511
|
+
@content = NKF.nkf("-E -w", File.read(path()))
|
512
|
+
elsif @param["inencoding"] =~ /^SJIS$/i
|
513
|
+
@content = NKF.nkf("-S -w", File.read(path()))
|
514
|
+
elsif @param["inencoding"] =~ /^JIS$/i
|
515
|
+
@content = NKF.nkf("-J -w", File.read(path()))
|
516
|
+
else
|
517
|
+
@content = NKF.nkf("-w", File.read(path())) # auto detect
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def lines
|
522
|
+
# FIXME: we cannot duplicate Enumerator on ruby 1.9 HEAD
|
523
|
+
(@lines ||= content().lines.to_a).dup
|
524
|
+
end
|
525
|
+
|
526
|
+
def list(id)
|
527
|
+
list_index()[id]
|
528
|
+
end
|
529
|
+
|
530
|
+
def list_index
|
531
|
+
@list_index ||= ListIndex.parse(lines())
|
532
|
+
@list_index.setParameter(@param)
|
533
|
+
@list_index
|
534
|
+
end
|
535
|
+
|
536
|
+
def table(id)
|
537
|
+
table_index()[id]
|
538
|
+
end
|
539
|
+
|
540
|
+
def table_index
|
541
|
+
@table_index ||= TableIndex.parse(lines())
|
542
|
+
@table_index.setParameter(@param)
|
543
|
+
@table_index
|
544
|
+
end
|
545
|
+
|
546
|
+
def footnote(id)
|
547
|
+
footnote_index()[id]
|
548
|
+
end
|
549
|
+
|
550
|
+
def footnote_index
|
551
|
+
@footnote_index ||= FootnoteIndex.parse(lines())
|
552
|
+
@footnote_index.setParameter(@param)
|
553
|
+
@footnote_index
|
554
|
+
end
|
555
|
+
|
556
|
+
def image(id)
|
557
|
+
image_index()[id]
|
558
|
+
end
|
559
|
+
|
560
|
+
def image_index
|
561
|
+
@image_index ||= ImageIndex.parse(lines(), id(),
|
562
|
+
"#{book.basedir}#{@book.image_dir}",
|
563
|
+
@book.image_types)
|
564
|
+
@image_index.setParameter(@param)
|
565
|
+
@image_index
|
566
|
+
end
|
567
|
+
|
568
|
+
def bibpaper(id)
|
569
|
+
bibpaper_index()[id]
|
570
|
+
end
|
571
|
+
|
572
|
+
def bibpaper_index
|
573
|
+
raise FileNotFound, "no such bib file: #{@book.bib_file}" unless @book.bib_exist?
|
574
|
+
@bibpaper_index ||= BibpaperIndex.parse(@book.read_bib.lines.to_a)
|
575
|
+
@bibpaper_index.setParameter(@param)
|
576
|
+
@bibpaper_index
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
end
|