review 2.4.0 → 2.5.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +20 -5
- data/.travis.yml +2 -1
- data/NEWS.ja.md +93 -0
- data/NEWS.md +77 -0
- data/README.md +1 -1
- data/bin/review +38 -12
- data/bin/review-compile +106 -88
- data/bin/review-epubmaker +6 -1
- data/bin/review-init +21 -1
- data/bin/review-textmaker +16 -0
- data/doc/config.yml.sample +6 -1
- data/doc/format.ja.md +23 -0
- data/doc/format.md +20 -2
- data/doc/quickstart.ja.md +8 -4
- data/doc/quickstart.md +11 -8
- data/lib/review/book/base.rb +29 -18
- data/lib/review/book/index.rb +10 -5
- data/lib/review/builder.rb +58 -33
- data/lib/review/catalog.rb +30 -0
- data/lib/review/compiler.rb +53 -19
- data/lib/review/configure.rb +15 -14
- data/lib/review/epubmaker.rb +15 -4
- data/lib/review/htmlbuilder.rb +56 -24
- data/lib/review/idgxmlbuilder.rb +17 -7
- data/lib/review/latexbuilder.rb +113 -38
- data/lib/review/markdownbuilder.rb +12 -5
- data/lib/review/md2inaobuilder.rb +3 -1
- data/lib/review/pdfmaker.rb +23 -9
- data/lib/review/plaintextbuilder.rb +683 -0
- data/lib/review/rstbuilder.rb +30 -10
- data/lib/review/textmaker.rb +158 -0
- data/lib/review/textutils.rb +10 -1
- data/lib/review/topbuilder.rb +32 -417
- data/lib/review/version.rb +1 -1
- data/lib/review/webmaker.rb +29 -8
- data/review.gemspec +3 -4
- data/templates/html/layout-xhtml1.html.erb +0 -2
- data/templates/latex/layout.tex.erb +6 -4
- data/templates/web/html/layout-xhtml1.html.erb +0 -2
- data/test/book_test_helper.rb +1 -0
- data/test/run_test.rb +1 -1
- data/test/sample-book/src/Rakefile +19 -3
- data/test/syntax-book/Rakefile +19 -3
- data/test/test_catalog.rb +45 -0
- data/test/test_compiler.rb +8 -2
- data/test/test_htmlbuilder.rb +22 -0
- data/test/test_idgxmlbuilder.rb +22 -0
- data/test/test_index.rb +31 -0
- data/test/test_latexbuilder.rb +48 -16
- data/test/test_plaintextbuilder.rb +390 -0
- data/test/test_textutils.rb +2 -0
- data/test/test_topbuilder.rb +23 -1
- metadata +13 -7
data/bin/review-epubmaker
CHANGED
@@ -33,11 +33,16 @@ rescue OptionParser::ParseError => err
|
|
33
33
|
exit 1
|
34
34
|
end
|
35
35
|
|
36
|
-
if ARGV.size < 1
|
36
|
+
if ARGV.size < 1
|
37
37
|
puts opts.help
|
38
38
|
exit 1
|
39
39
|
end
|
40
40
|
|
41
|
+
unless File.exist?(ARGV[0])
|
42
|
+
@logger.error "#{File.basename($PROGRAM_NAME, '.*')}: #{ARGV[0]} not found."
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
|
41
46
|
yaml_file = ARGV[0]
|
42
47
|
bookname = ARGV[1]
|
43
48
|
rv.produce(yaml_file, bookname)
|
data/bin/review-init
CHANGED
@@ -29,6 +29,7 @@ def main
|
|
29
29
|
opts.on('-f', '--force', 'generate files (except *.re) if directory has already existed.') { @force = true }
|
30
30
|
opts.on('-l', '--locale', 'generate locale.yml file.') { @locale = true }
|
31
31
|
opts.on('', '--epub-version VERSION', 'define EPUB version') { |version| @epub_version = version }
|
32
|
+
opts.on('', '--without-doc', "don't generate doc files") { @without_doc = true }
|
32
33
|
begin
|
33
34
|
opts.parse!
|
34
35
|
rescue OptionParser::ParseError => err
|
@@ -57,6 +58,7 @@ def main
|
|
57
58
|
generate_locale(dir) if @locale
|
58
59
|
generate_rakefile(dir)
|
59
60
|
generate_gemfile(dir)
|
61
|
+
generate_doc(dir) unless @without_doc
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
@@ -130,7 +132,18 @@ def generate_texmacro(dir)
|
|
130
132
|
end
|
131
133
|
|
132
134
|
def generate_rakefile(dir)
|
133
|
-
FileUtils.
|
135
|
+
FileUtils.mkdir_p dir + '/lib/tasks'
|
136
|
+
|
137
|
+
File.open(dir + '/Rakefile', 'w') do |file|
|
138
|
+
file.write <<-EOS
|
139
|
+
Dir.glob('lib/tasks/*.rake').each do |file|
|
140
|
+
load(file)
|
141
|
+
end
|
142
|
+
EOS
|
143
|
+
end
|
144
|
+
|
145
|
+
FileUtils.cp @review_dir + '/test/sample-book/src/Rakefile',
|
146
|
+
dir + '/lib/tasks/review.rake'
|
134
147
|
end
|
135
148
|
|
136
149
|
def generate_locale(dir)
|
@@ -148,4 +161,11 @@ EOS
|
|
148
161
|
end
|
149
162
|
end
|
150
163
|
|
164
|
+
def generate_doc(dir)
|
165
|
+
docdir = dir + '/doc'
|
166
|
+
FileUtils.mkdir_p docdir
|
167
|
+
md_files = Dir.glob(@review_dir + '/doc/*.md').map.to_a
|
168
|
+
FileUtils.cp md_files, docdir
|
169
|
+
end
|
170
|
+
|
151
171
|
main if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (c) 2018 Kenshi Muto
|
3
|
+
#
|
4
|
+
# This program is free software.
|
5
|
+
# You can distribute or modify this program under the terms of
|
6
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
7
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'pathname'
|
11
|
+
bindir = Pathname.new(__FILE__).realpath.dirname
|
12
|
+
$LOAD_PATH.unshift((bindir + '../lib').realpath)
|
13
|
+
|
14
|
+
require 'review/textmaker'
|
15
|
+
|
16
|
+
ReVIEW::TEXTMaker.execute(*ARGV)
|
data/doc/config.yml.sample
CHANGED
@@ -314,9 +314,14 @@ pdfmaker:
|
|
314
314
|
# 渡される引数1=作業用展開ディレクトリ、引数2=呼び出しを実行したディレクトリ
|
315
315
|
# hook_afterdvipdf: null
|
316
316
|
#
|
317
|
-
# 画像のscale=X.X
|
317
|
+
# 画像のscale=X.Xという指定を画像拡大縮小率からページ最大幅の相対倍率に変換する
|
318
318
|
# image_scale2width: true
|
319
319
|
#
|
320
|
+
# PDFやIllustratorファイル(.ai)の画像のBoudingBoxの抽出に指定のボックスを採用する
|
321
|
+
# cropbox(デフォルト), mediabox, artbox, trimbox, bleedboxから選択する。
|
322
|
+
# Illustrator CC以降のIllustratorファイルに対してはmediaboxを指定する必要がある
|
323
|
+
# bbox: mediabox
|
324
|
+
#
|
320
325
|
# 奥付を作成するか。trueを指定するとデフォルトの奥付、ファイル名を指定するとそれがcolophon.htmlとしてコピーされる
|
321
326
|
colophon: true
|
322
327
|
# pdfmaker:階層を使うものはここまで
|
data/doc/format.ja.md
CHANGED
@@ -337,6 +337,12 @@ V1 --> V6 --|
|
|
337
337
|
* `<id>` は //image[〜] の最初に入れた「〜」のことです(つまり、ID に日本語や空白交じりの文字を使ってしまうと、後で画像ファイル名の名前付けに苦労することになります!)。
|
338
338
|
* `<ext>` は Re:VIEW が自動で判別する拡張子です。ビルダによってサポートおよび優先する拡張子は異なります。
|
339
339
|
|
340
|
+
各ビルダでは、以下の拡張子から最初に発見した画像ファイルが使われます。
|
341
|
+
|
342
|
+
* HTMLBuilder (EPUBMaker、WEBMaker)、MARKDOWNBuilder: .png、.jpg、.jpeg、.gif、.svg
|
343
|
+
* LATEXBuilder (PDFMaker): .ai、.eps、.pdf、.tif、.tiff、.png、.bmp、.jpg、.jpeg、.gif
|
344
|
+
* それ以外のビルダ: .ai、.psd、.eps、.pdf、.tif、.tiff、.png、.bmp、.jpg、.jpeg、.gif、.svg
|
345
|
+
|
340
346
|
### インラインの画像挿入
|
341
347
|
|
342
348
|
段落途中などに画像を貼り込むには、インライン命令の `@<icon>{識別子}` を使います。ファイルの探索ルールは同じです。
|
@@ -569,6 +575,23 @@ LaTeX の数式が正常に整形されるかどうかは処理系に依存し
|
|
569
575
|
|
570
576
|
段落の行頭字下げを制御するタグとして、`//noindent` があります。HTML では `noindent` が `class` 属性に設定されます。
|
571
577
|
|
578
|
+
## 空行
|
579
|
+
|
580
|
+
1行ぶんの空行を明示して入れるには、`//blankline` を使います。
|
581
|
+
|
582
|
+
例:
|
583
|
+
|
584
|
+
```
|
585
|
+
この下に1行の空行が入る
|
586
|
+
|
587
|
+
//blankline
|
588
|
+
|
589
|
+
この下に2行の空行が入る
|
590
|
+
|
591
|
+
//blankline
|
592
|
+
//blankline
|
593
|
+
```
|
594
|
+
|
572
595
|
## 見出し参照
|
573
596
|
章に対する参照は、次の3つのインライン命令を利用できます。章 ID は、各章のファイル名から拡張子を除いたものです。たとえば `advanced.re` であれば `advanced` が章 ID です。
|
574
597
|
|
data/doc/format.md
CHANGED
@@ -380,6 +380,12 @@ The order of finding image is as follows. The first matched one is used.
|
|
380
380
|
* ``<id>`` is the ID of the first argument of `//image`. You should use only printable ASCII characters as ID.
|
381
381
|
* ``<ext>`` is file extensions of Re:VIEW. They are different by the builder you use.
|
382
382
|
|
383
|
+
For each builder, image files are searched in order of the following extensions, and the first hit file is adopted.
|
384
|
+
|
385
|
+
* HTMLBuilder (EPUBMaker, WEBMaker), MARKDOWNBuilder: .png, .jpg, .jpeg, .gif, .svg
|
386
|
+
* LATEXBuilder (PDFMaker): .ai, .eps, .pdf, .tif, .tiff, .png, .bmp, .jpg, .jpeg, .gif
|
387
|
+
* Other builders: .ai, .psd, .eps, .pdf, .tif, .tiff, .png, .bmp, .jpg, .jpeg, .gif, .svg
|
388
|
+
|
383
389
|
### Inline Images
|
384
390
|
|
385
391
|
When you want to use images in paragraph, you can use the inline command `@<icon>{ID}`. The order of finding images are same as `//image`.
|
@@ -610,12 +616,24 @@ Usage:
|
|
610
616
|
|
611
617
|
`//noindent` is a tag for spacing.
|
612
618
|
|
613
|
-
|
614
619
|
* `//noindent` : ingore indentation immediately following line. (in HTML, add `noindent` class)
|
615
620
|
|
621
|
+
## Blank line
|
622
|
+
|
623
|
+
`//blankline` put an empty line.
|
624
|
+
|
625
|
+
Usage:
|
626
|
+
|
627
|
+
```
|
628
|
+
Insert one blank line below.
|
616
629
|
|
617
|
-
|
630
|
+
//blankline
|
618
631
|
|
632
|
+
Insert two blank line below.
|
633
|
+
|
634
|
+
//blankline
|
635
|
+
//blankline
|
636
|
+
```
|
619
637
|
|
620
638
|
## Referring headings
|
621
639
|
|
data/doc/quickstart.ja.md
CHANGED
@@ -113,17 +113,19 @@ review-init コマンドによらず、独自に作業フォルダを作成し
|
|
113
113
|
|
114
114
|
テキストファイルの文字エンコーディングには、UTF-8 を使用してください。
|
115
115
|
|
116
|
-
### PDF 化と EPUB
|
116
|
+
### PDF 化と EPUB 化、プレインテキスト化
|
117
117
|
|
118
|
-
review-pdfmaker コマンドで PDF ブックの作成、review-epubmaker コマンドで EPUB
|
118
|
+
review-pdfmaker コマンドで PDF ブックの作成、review-epubmaker コマンドで EPUB ファイルの作成、review-textmaker コマンドでプレインテキストの作成ができます。
|
119
119
|
|
120
120
|
PDF を作成するには、TeXLive2012 以上の環境が必要です。EPUB を作成するには、rubyzip gem あるいは zip コマンドが必要です(MathML も使いたいときには、 [MathML ライブラリ](http://www.hinet.mydns.jp/?mathml.rb)も必要です)。
|
121
121
|
|
122
122
|
いずれのコマンドも、必要な設定情報を記した YAML 形式ファイルを引数に指定して実行します。review-init コマンドで作成した環境には、デフォルトで config.yml として用意されているので、これを利用します。
|
123
123
|
|
124
124
|
```bash
|
125
|
-
$ review-pdfmaker config.yml
|
126
|
-
$ review-epubmaker config.yml
|
125
|
+
$ review-pdfmaker config.yml ←PDFの作成
|
126
|
+
$ review-epubmaker config.yml ←EPUBの作成
|
127
|
+
$ review-textmaker config.yml ←テキストの作成(装飾情報あり)
|
128
|
+
$ review-textmaker -n config.yml ←テキストの作成(装飾情報なし)
|
127
129
|
```
|
128
130
|
|
129
131
|
rake コマンドを利用できるなら、次のように実行することもできます。
|
@@ -131,6 +133,8 @@ rake コマンドを利用できるなら、次のように実行することも
|
|
131
133
|
```bash
|
132
134
|
$ rake pdf ←PDFの作成
|
133
135
|
$ rake epub ←EPUBの作成
|
136
|
+
$ rake text ←テキストの作成(装飾情報あり)
|
137
|
+
$ rake plaintext ←テキストの作成(装飾情報なし)
|
134
138
|
```
|
135
139
|
|
136
140
|
config.yml のサンプルについては以下を参照してください。
|
data/doc/quickstart.md
CHANGED
@@ -115,28 +115,31 @@ The web site of Re:VIEW is @<tt>{https://reviewml.org/}.
|
|
115
115
|
|
116
116
|
You should use UTF-8 as encodings in text files.
|
117
117
|
|
118
|
-
### generating PDF and
|
118
|
+
### generating PDF, EPUB, and plain-text
|
119
119
|
|
120
|
-
You can generate a PDF file with `review-pdfmaker` command. Also you can generate an EPUB file with `review-epubmaker` command.
|
120
|
+
You can generate a PDF file with `review-pdfmaker` command. Also you can generate an EPUB file with `review-epubmaker` command, and can generate an plain-text file with 'review-textmaker' command.
|
121
121
|
|
122
122
|
To generate PDF, you should install TeXLive 2012 or later. To generate EPUB, you should install zip command.
|
123
123
|
When you want to use MathML, you should install [MathML library](http://www.hinet.mydns.jp/?mathml.rb)
|
124
124
|
|
125
|
-
|
125
|
+
Each maker need `config.yml`, configuration YAML files. `review-init` command generates `config.yml` in default.
|
126
126
|
|
127
127
|
```bash
|
128
|
-
$ review-pdfmaker config.yml
|
129
|
-
$ review-epubmaker config.yml
|
128
|
+
$ review-pdfmaker config.yml ## generate PDF
|
129
|
+
$ review-epubmaker config.yml ## generate EPUB
|
130
|
+
$ review-textmaker config.yml ## generate text with decoration
|
131
|
+
$ review-textmaker -n config.yml ## generate text without decoration
|
130
132
|
```
|
131
133
|
|
132
134
|
You also can generate them with Rake.
|
133
135
|
|
134
136
|
```bash
|
135
|
-
$ rake pdf
|
136
|
-
$ rake epub
|
137
|
+
$ rake pdf ## generate PDF
|
138
|
+
$ rake epub ## generate EPUB
|
139
|
+
$ rake text ## generate text with decoration
|
140
|
+
$ rake plaintext ## generate text without decoration
|
137
141
|
```
|
138
142
|
|
139
|
-
|
140
143
|
There is a sample YAML file [config.yml.sample](https://github.com/kmuto/review/blob/master/doc/config.yml.sample) in the same directory of this document.
|
141
144
|
|
142
145
|
### add chapters and modify them
|
data/lib/review/book/base.rb
CHANGED
@@ -32,11 +32,11 @@ module ReVIEW
|
|
32
32
|
|
33
33
|
def self.update_rubyenv(dir)
|
34
34
|
return if @basedir_seen.key?(dir)
|
35
|
-
if File.file?(
|
35
|
+
if File.file?(File.join(dir, 'review-ext.rb'))
|
36
36
|
if ENV['REVIEW_SAFE_MODE'].to_i & 2 > 0
|
37
37
|
ReVIEW.logger.warn 'review-ext.rb is prohibited in safe mode. ignored.'
|
38
38
|
else
|
39
|
-
Kernel.load File.expand_path(
|
39
|
+
Kernel.load File.expand_path(File.join(dir, 'review-ext.rb'))
|
40
40
|
end
|
41
41
|
end
|
42
42
|
@basedir_seen[dir] = true
|
@@ -183,8 +183,11 @@ module ReVIEW
|
|
183
183
|
def catalog
|
184
184
|
return @catalog if @catalog.present?
|
185
185
|
|
186
|
-
catalogfile_path =
|
187
|
-
@catalog = File.open(catalogfile_path) { |f| Catalog.new(f) } if File.file? catalogfile_path
|
186
|
+
catalogfile_path = filename_join(@basedir, config['catalogfile'])
|
187
|
+
@catalog = File.open(catalogfile_path, 'r:BOM|utf-8') { |f| Catalog.new(f) } if File.file? catalogfile_path
|
188
|
+
if @catalog
|
189
|
+
@catalog.validate!(basedir)
|
190
|
+
end
|
188
191
|
@catalog
|
189
192
|
end
|
190
193
|
|
@@ -226,7 +229,7 @@ module ReVIEW
|
|
226
229
|
if catalog
|
227
230
|
@read_part = catalog.parts
|
228
231
|
else
|
229
|
-
@read_part = File.read(
|
232
|
+
@read_part = File.read(File.join(@basedir, config['part_file']))
|
230
233
|
end
|
231
234
|
end
|
232
235
|
|
@@ -234,23 +237,26 @@ module ReVIEW
|
|
234
237
|
if catalog
|
235
238
|
catalog.parts.present?
|
236
239
|
else
|
237
|
-
File.exist?(
|
240
|
+
File.exist?(File.join(@basedir, config['part_file']))
|
238
241
|
end
|
239
242
|
end
|
240
243
|
|
241
244
|
def read_bib
|
242
|
-
File.read(
|
245
|
+
File.read(File.join(@basedir, bib_file))
|
243
246
|
end
|
244
247
|
|
245
248
|
def bib_exist?
|
246
|
-
File.exist?(
|
249
|
+
File.exist?(File.join(@basedir, bib_file))
|
247
250
|
end
|
248
251
|
|
249
252
|
def prefaces
|
250
|
-
|
253
|
+
if catalog
|
254
|
+
return mkpart_from_namelist(catalog.predef.split("\n"))
|
255
|
+
end
|
251
256
|
|
252
257
|
begin
|
253
|
-
|
258
|
+
predef_file = filename_join(@basedir, config['predef_file'])
|
259
|
+
mkpart_from_namelistfile(predef_file) if File.file?(predef_file)
|
254
260
|
rescue FileNotFound => err
|
255
261
|
raise FileNotFound, "preface #{err.message}"
|
256
262
|
end
|
@@ -264,7 +270,8 @@ module ReVIEW
|
|
264
270
|
end
|
265
271
|
|
266
272
|
begin
|
267
|
-
|
273
|
+
postdef_file = filename_join(@basedir, config['postdef_file'])
|
274
|
+
mkpart_from_namelistfile(postdef_file) if File.file?(postdef_file)
|
268
275
|
rescue FileNotFound => err
|
269
276
|
raise FileNotFound, "postscript #{err.message}"
|
270
277
|
end
|
@@ -301,12 +308,12 @@ module ReVIEW
|
|
301
308
|
return catalog.parts_with_chaps.map do |entry|
|
302
309
|
if entry.is_a?(Hash)
|
303
310
|
chaps = entry.values.first.map do |chap|
|
304
|
-
chap = Chapter.new(self, num += 1, chap,
|
311
|
+
chap = Chapter.new(self, num += 1, chap, File.join(@basedir, chap))
|
305
312
|
chap
|
306
313
|
end
|
307
314
|
Part.new(self, part += 1, chaps, read_part.split("\n")[part - 1])
|
308
315
|
else
|
309
|
-
chap = Chapter.new(self, num += 1, entry,
|
316
|
+
chap = Chapter.new(self, num += 1, entry, File.join(@basedir, entry))
|
310
317
|
if chap.number
|
311
318
|
num = chap.number
|
312
319
|
else
|
@@ -320,7 +327,7 @@ module ReVIEW
|
|
320
327
|
chap = read_chaps.
|
321
328
|
strip.lines.map(&:strip).join("\n").split(/\n{2,}/).
|
322
329
|
map do |part_chunk|
|
323
|
-
chaps = part_chunk.split.map { |chapid| Chapter.new(self, num += 1, chapid,
|
330
|
+
chaps = part_chunk.split.map { |chapid| Chapter.new(self, num += 1, chapid, File.join(@basedir, chapid)) }
|
324
331
|
if part_exist? && read_part.split("\n").size > part
|
325
332
|
Part.new(self, part += 1, chaps, read_part.split("\n")[part - 1])
|
326
333
|
else
|
@@ -352,14 +359,14 @@ module ReVIEW
|
|
352
359
|
|
353
360
|
def mkchap(name, number = nil)
|
354
361
|
name += ext if File.extname(name).empty?
|
355
|
-
path =
|
362
|
+
path = File.join(@basedir, name)
|
356
363
|
raise FileNotFound, "file not exist: #{path}" unless File.file?(path)
|
357
364
|
Chapter.new(self, number, name, path)
|
358
365
|
end
|
359
366
|
|
360
367
|
def mkchap_ifexist(name, idx = nil)
|
361
368
|
name += ext if File.extname(name).empty?
|
362
|
-
path =
|
369
|
+
path = File.join(@basedir, name)
|
363
370
|
if File.file?(path)
|
364
371
|
idx += 1 if idx
|
365
372
|
Chapter.new(self, idx, name, path)
|
@@ -369,10 +376,10 @@ module ReVIEW
|
|
369
376
|
def read_file(filename)
|
370
377
|
unless @warn_old_files[filename]
|
371
378
|
@warn_old_files[filename] = true
|
372
|
-
warn "!!! #{filename} is obsoleted. please use catalog.yml." if caller.none? { |item| item =~ %r{/review/test/test_} }
|
379
|
+
ReVIEW.logger.warn "!!! #{filename} is obsoleted. please use catalog.yml." if caller.none? { |item| item =~ %r{/review/test/test_} }
|
373
380
|
end
|
374
381
|
res = ''
|
375
|
-
File.open(
|
382
|
+
File.open(filename_join(@basedir, filename), 'r:BOM|utf-8') do |f|
|
376
383
|
f.each_line do |line|
|
377
384
|
next if /\A#/ =~ line
|
378
385
|
line.gsub!(/#.*\Z/, '')
|
@@ -385,6 +392,10 @@ module ReVIEW
|
|
385
392
|
rescue Errno::EISDIR
|
386
393
|
''
|
387
394
|
end
|
395
|
+
|
396
|
+
def filename_join(*args)
|
397
|
+
File.join(args.reject(&:nil?))
|
398
|
+
end
|
388
399
|
end
|
389
400
|
end
|
390
401
|
end
|
data/lib/review/book/index.rb
CHANGED
@@ -88,9 +88,11 @@ module ReVIEW
|
|
88
88
|
|
89
89
|
def number(id)
|
90
90
|
chapter = @index.fetch(id)
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
begin
|
92
|
+
chapter.format_number
|
93
|
+
rescue # part
|
94
|
+
I18n.t('part', chapter.number)
|
95
|
+
end
|
94
96
|
end
|
95
97
|
|
96
98
|
def title(id)
|
@@ -280,6 +282,7 @@ module ReVIEW
|
|
280
282
|
headlines = []
|
281
283
|
inside_column = false
|
282
284
|
inside_block = nil
|
285
|
+
column_level = -1
|
283
286
|
src.each do |line|
|
284
287
|
if line =~ %r{\A//[a-z]+.*\{\Z}
|
285
288
|
inside_block = true
|
@@ -293,19 +296,20 @@ module ReVIEW
|
|
293
296
|
|
294
297
|
m = HEADLINE_PATTERN.match(line)
|
295
298
|
next if m.nil? || m[1].size > 10 # Ignore too deep index
|
296
|
-
next if m[4].strip.empty? # no title
|
297
299
|
index = m[1].size - 2
|
298
300
|
|
299
301
|
# column
|
300
302
|
if m[2] == 'column'
|
301
303
|
inside_column = true
|
304
|
+
column_level = index
|
302
305
|
next
|
303
306
|
elsif m[2] == '/column'
|
304
307
|
inside_column = false
|
305
308
|
next
|
306
309
|
end
|
307
|
-
inside_column = false if indexs.blank? || index <=
|
310
|
+
inside_column = false if indexs.blank? || index <= column_level
|
308
311
|
next if inside_column
|
312
|
+
next if m[4].strip.empty? # no title
|
309
313
|
|
310
314
|
next unless index >= 0
|
311
315
|
if indexs.size > (index + 1)
|
@@ -324,6 +328,7 @@ module ReVIEW
|
|
324
328
|
@items = items
|
325
329
|
@chap = chap
|
326
330
|
@index = {}
|
331
|
+
@logger = ReVIEW.logger
|
327
332
|
items.each do |i|
|
328
333
|
@logger.warn "warning: duplicate ID: #{i.id}" if @index[i.id]
|
329
334
|
@index[i.id] = i
|
data/lib/review/builder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2002-
|
1
|
+
# Copyright (c) 2002-2018 Minero Aoki, Kenshi Muto
|
2
2
|
#
|
3
3
|
# This program is free software.
|
4
4
|
# You can distribute or modify this program under the terms of
|
@@ -12,6 +12,7 @@ require 'review/compiler'
|
|
12
12
|
require 'review/sec_counter'
|
13
13
|
require 'stringio'
|
14
14
|
require 'cgi'
|
15
|
+
require 'fileutils'
|
15
16
|
|
16
17
|
module ReVIEW
|
17
18
|
class Builder
|
@@ -27,10 +28,13 @@ module ReVIEW
|
|
27
28
|
nil
|
28
29
|
end
|
29
30
|
|
31
|
+
attr_accessor :doc_status
|
32
|
+
|
30
33
|
def initialize(strict = false, *args)
|
31
34
|
@strict = strict
|
32
35
|
@output = nil
|
33
36
|
@logger = ReVIEW.logger
|
37
|
+
@doc_status = {}
|
34
38
|
builder_init(*args)
|
35
39
|
end
|
36
40
|
|
@@ -148,8 +152,12 @@ module ReVIEW
|
|
148
152
|
return if rows.empty?
|
149
153
|
table_begin rows.first.size
|
150
154
|
if sepidx
|
151
|
-
sepidx.times
|
152
|
-
|
155
|
+
sepidx.times do
|
156
|
+
tr(rows.shift.map { |s| th(s) })
|
157
|
+
end
|
158
|
+
rows.each do |cols|
|
159
|
+
tr(cols.map { |s| td(s) })
|
160
|
+
end
|
153
161
|
else
|
154
162
|
rows.each do |cols|
|
155
163
|
h, *cs = *cols
|
@@ -160,9 +168,15 @@ module ReVIEW
|
|
160
168
|
end
|
161
169
|
|
162
170
|
def adjust_n_cols(rows)
|
163
|
-
rows.each
|
171
|
+
rows.each do |cols|
|
172
|
+
while cols.last and cols.last.strip.empty?
|
173
|
+
cols.pop
|
174
|
+
end
|
175
|
+
end
|
164
176
|
n_maxcols = rows.map(&:size).max
|
165
|
-
rows.each
|
177
|
+
rows.each do |cols|
|
178
|
+
cols.concat [''] * (n_maxcols - cols.size)
|
179
|
+
end
|
166
180
|
rows
|
167
181
|
end
|
168
182
|
private :adjust_n_cols
|
@@ -183,6 +197,10 @@ module ReVIEW
|
|
183
197
|
# footnote_end
|
184
198
|
# end
|
185
199
|
|
200
|
+
def blankline
|
201
|
+
puts ''
|
202
|
+
end
|
203
|
+
|
186
204
|
def compile_inline(s)
|
187
205
|
@compiler.text(s)
|
188
206
|
end
|
@@ -191,35 +209,30 @@ module ReVIEW
|
|
191
209
|
compile_inline @book.chapter_index.display_string(id)
|
192
210
|
rescue KeyError
|
193
211
|
error "unknown chapter: #{id}"
|
194
|
-
nofunc_text("[UnknownChapter:#{id}]")
|
195
212
|
end
|
196
213
|
|
197
214
|
def inline_chap(id)
|
198
215
|
@book.chapter_index.number(id)
|
199
216
|
rescue KeyError
|
200
217
|
error "unknown chapter: #{id}"
|
201
|
-
nofunc_text("[UnknownChapter:#{id}]")
|
202
218
|
end
|
203
219
|
|
204
220
|
def inline_title(id)
|
205
221
|
compile_inline @book.chapter_index.title(id)
|
206
222
|
rescue KeyError
|
207
223
|
error "unknown chapter: #{id}"
|
208
|
-
nofunc_text("[UnknownChapter:#{id}]")
|
209
224
|
end
|
210
225
|
|
211
226
|
def inline_list(id)
|
212
227
|
"#{I18n.t('list')}#{@chapter.list(id).number}"
|
213
228
|
rescue KeyError
|
214
229
|
error "unknown list: #{id}"
|
215
|
-
nofunc_text("[UnknownList:#{id}]")
|
216
230
|
end
|
217
231
|
|
218
232
|
def inline_img(id)
|
219
233
|
"#{I18n.t('image')}#{@chapter.image(id).number}"
|
220
234
|
rescue KeyError
|
221
235
|
error "unknown image: #{id}"
|
222
|
-
nofunc_text("[UnknownImage:#{id}]")
|
223
236
|
end
|
224
237
|
|
225
238
|
def inline_imgref(id)
|
@@ -236,14 +249,12 @@ module ReVIEW
|
|
236
249
|
"#{I18n.t('table')}#{@chapter.table(id).number}"
|
237
250
|
rescue KeyError
|
238
251
|
error "unknown table: #{id}"
|
239
|
-
nofunc_text("[UnknownTable:#{id}]")
|
240
252
|
end
|
241
253
|
|
242
254
|
def inline_fn(id)
|
243
255
|
@chapter.footnote(id).content
|
244
256
|
rescue KeyError
|
245
257
|
error "unknown footnote: #{id}"
|
246
|
-
nofunc_text("[UnknownFootnote:#{id}]")
|
247
258
|
end
|
248
259
|
|
249
260
|
def inline_bou(str)
|
@@ -252,8 +263,12 @@ module ReVIEW
|
|
252
263
|
|
253
264
|
def inline_ruby(arg)
|
254
265
|
base, *ruby = *arg.scan(/(?:(?:(?:\\\\)*\\,)|[^,\\]+)+/)
|
255
|
-
|
256
|
-
|
266
|
+
if base
|
267
|
+
base = base.gsub(/\\,/, ',')
|
268
|
+
end
|
269
|
+
if ruby
|
270
|
+
ruby = ruby.join(',').gsub(/\\,/, ',')
|
271
|
+
end
|
257
272
|
compile_ruby(base, ruby)
|
258
273
|
end
|
259
274
|
|
@@ -265,7 +280,9 @@ module ReVIEW
|
|
265
280
|
def inline_href(arg)
|
266
281
|
url, label = *arg.scan(/(?:(?:(?:\\\\)*\\,)|[^,\\]+)+/).map(&:lstrip)
|
267
282
|
url = url.gsub(/\\,/, ',').strip
|
268
|
-
|
283
|
+
if label
|
284
|
+
label = label.gsub(/\\,/, ',').strip
|
285
|
+
end
|
269
286
|
compile_href(url, label)
|
270
287
|
end
|
271
288
|
|
@@ -284,20 +301,23 @@ module ReVIEW
|
|
284
301
|
|
285
302
|
def inline_hd(id)
|
286
303
|
m = /\A([^|]+)\|(.+)/.match(id)
|
287
|
-
|
304
|
+
if m && m[1]
|
305
|
+
chapter = @book.contents.detect { |chap| chap.id == m[1] }
|
306
|
+
end
|
288
307
|
if chapter
|
289
308
|
inline_hd_chap(chapter, m[2])
|
290
309
|
else
|
291
310
|
inline_hd_chap(@chapter, id)
|
292
311
|
end
|
293
312
|
rescue KeyError
|
294
|
-
error "unknown
|
295
|
-
nofunc_text("[UnknownHeader:#{id}]")
|
313
|
+
error "unknown headline: #{id}"
|
296
314
|
end
|
297
315
|
|
298
316
|
def inline_column(id)
|
299
317
|
m = /\A([^|]+)\|(.+)/.match(id)
|
300
|
-
|
318
|
+
if m && m[1]
|
319
|
+
chapter = @book.chapters.detect { |chap| chap.id == m[1] }
|
320
|
+
end
|
301
321
|
if chapter
|
302
322
|
inline_column_chap(chapter, m[2])
|
303
323
|
else
|
@@ -305,7 +325,6 @@ module ReVIEW
|
|
305
325
|
end
|
306
326
|
rescue KeyError
|
307
327
|
error "unknown column: #{id}"
|
308
|
-
nofunc_text("[UnknownColumn:#{id}]")
|
309
328
|
end
|
310
329
|
|
311
330
|
def inline_column_chap(chapter, id)
|
@@ -324,7 +343,9 @@ module ReVIEW
|
|
324
343
|
if matched = str.match(/\|(.*?)\|(.*)/)
|
325
344
|
builders = matched[1].split(',').map { |i| i.gsub(/\s/, '') }
|
326
345
|
c = target_name
|
327
|
-
|
346
|
+
if builders.include?(c)
|
347
|
+
print matched[2].gsub('\\n', "\n")
|
348
|
+
end
|
328
349
|
else
|
329
350
|
print str.gsub('\\n', "\n")
|
330
351
|
end
|
@@ -345,8 +366,11 @@ module ReVIEW
|
|
345
366
|
end
|
346
367
|
|
347
368
|
def error(msg)
|
348
|
-
|
349
|
-
|
369
|
+
if msg =~ /:\d+: error: /
|
370
|
+
raise ApplicationError, msg
|
371
|
+
else
|
372
|
+
raise ApplicationError, "#{@location}: error: #{msg}"
|
373
|
+
end
|
350
374
|
end
|
351
375
|
|
352
376
|
def handle_metric(str)
|
@@ -374,15 +398,20 @@ module ReVIEW
|
|
374
398
|
|
375
399
|
def get_chap(chapter = @chapter)
|
376
400
|
if @book.config['secnolevel'] > 0 && !chapter.number.nil? && !chapter.number.to_s.empty?
|
377
|
-
|
378
|
-
|
401
|
+
if chapter.is_a?(ReVIEW::Book::Part)
|
402
|
+
return I18n.t('part_short', chapter.number)
|
403
|
+
else
|
404
|
+
return chapter.format_number(nil)
|
405
|
+
end
|
379
406
|
end
|
380
407
|
nil
|
381
408
|
end
|
382
409
|
|
383
410
|
def extract_chapter_id(chap_ref)
|
384
411
|
m = /\A([\w+-]+)\|(.+)/.match(chap_ref)
|
385
|
-
|
412
|
+
if m
|
413
|
+
return [@book.contents.detect { |chap| chap.id == m[1] }, m[2]]
|
414
|
+
end
|
386
415
|
[@chapter, chap_ref]
|
387
416
|
end
|
388
417
|
|
@@ -401,7 +430,7 @@ module ReVIEW
|
|
401
430
|
def graph(lines, id, command, caption = nil)
|
402
431
|
c = target_name
|
403
432
|
dir = File.join(@book.basedir, @book.image_dir, c)
|
404
|
-
|
433
|
+
FileUtils.mkdir_p(dir)
|
405
434
|
file = "#{id}.#{image_ext}"
|
406
435
|
file_path = File.join(dir, file)
|
407
436
|
|
@@ -410,7 +439,7 @@ module ReVIEW
|
|
410
439
|
graphviz: "echo '#{line}' | dot -T#{image_ext} -o#{file_path}",
|
411
440
|
gnuplot: %Q(echo 'set terminal ) +
|
412
441
|
"#{image_ext == 'eps' ? 'postscript eps' : image_ext}\n" +
|
413
|
-
%Q(
|
442
|
+
%Q( set output "#{file_path}"\n#{line}' | gnuplot),
|
414
443
|
blockdiag: "echo '#{line}' " +
|
415
444
|
"| blockdiag -a -T #{image_ext} -o #{file_path} /dev/stdin",
|
416
445
|
aafigure: "echo '#{line}' | aafigure -t#{image_ext} -o#{file_path}"
|
@@ -428,11 +457,7 @@ module ReVIEW
|
|
428
457
|
end
|
429
458
|
|
430
459
|
def inline_include(file_name)
|
431
|
-
compile_inline File.read(file_name)
|
432
|
-
end
|
433
|
-
|
434
|
-
def include(file_name)
|
435
|
-
File.foreach(file_name) { |line| paragraph([line]) }
|
460
|
+
compile_inline File.read(file_name, mode: 'rt:BOM|utf-8').chomp
|
436
461
|
end
|
437
462
|
|
438
463
|
def ul_item_begin(lines)
|