review 3.0.0.preview3 → 3.0.0.preview4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.ja.md +26 -0
- data/NEWS.md +26 -0
- data/bin/review +2 -0
- data/bin/review-update +19 -0
- data/doc/format.ja.md +11 -0
- data/doc/format.md +11 -1
- data/doc/format_idg.ja.md +2 -4
- data/lib/review/book/chapter.rb +1 -0
- data/lib/review/book/compilable.rb +9 -0
- data/lib/review/book/index.rb +7 -1
- data/lib/review/builder.rb +29 -3
- data/lib/review/compiler.rb +2 -1
- data/lib/review/htmlbuilder.rb +40 -28
- data/lib/review/i18n.rb +8 -0
- data/lib/review/i18n.yml +22 -1
- data/lib/review/idgxmlbuilder.rb +42 -36
- data/lib/review/init.rb +2 -2
- data/lib/review/latexbuilder.rb +27 -1
- data/lib/review/makerhelper.rb +2 -1
- data/lib/review/plaintextbuilder.rb +27 -41
- data/lib/review/rstbuilder.rb +9 -1
- data/lib/review/topbuilder.rb +9 -1
- data/lib/review/update.rb +527 -0
- data/lib/review/version.rb +1 -1
- data/review.gemspec +1 -1
- data/samples/sample-book/README.md +1 -1
- data/samples/sample-book/src/Rakefile +2 -112
- data/samples/sample-book/src/config.yml +3 -1
- data/samples/sample-book/src/lib/tasks/review.rake +113 -0
- data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +17 -0
- data/samples/sample-book/src/sty/reviewmacro.sty +15 -1
- data/samples/syntax-book/Rakefile +2 -87
- data/samples/syntax-book/ch02.re +6 -1
- data/samples/syntax-book/config.yml +7 -4
- data/samples/syntax-book/images/cover-b5.ai +5735 -15
- data/samples/syntax-book/lib/tasks/review.rake +113 -0
- data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +17 -0
- data/samples/syntax-book/sty/reviewmacro.sty +11 -35
- data/templates/latex/config.erb +1 -0
- data/templates/latex/review-jlreq/review-base.sty +4 -0
- data/templates/latex/review-jlreq/review-jlreq.cls +56 -2
- data/templates/latex/review-jlreq/review-style.sty +0 -6
- data/templates/latex/review-jsbook/review-base.sty +5 -0
- data/test/assets/test_template.tex +2 -1
- data/test/assets/test_template_backmatter.tex +2 -1
- data/test/test_htmlbuilder.rb +39 -1
- data/test/test_idgxmlbuilder.rb +24 -0
- data/test/test_latexbuilder.rb +39 -0
- data/test/test_pdfmaker_cmd.rb +1 -1
- data/test/test_plaintextbuilder.rb +19 -0
- data/test/test_topbuilder.rb +21 -0
- data/test/test_update.rb +450 -0
- metadata +12 -2
data/lib/review/idgxmlbuilder.rb
CHANGED
@@ -264,14 +264,7 @@ module ReVIEW
|
|
264
264
|
end
|
265
265
|
|
266
266
|
def inline_list(id)
|
267
|
-
|
268
|
-
if get_chap(chapter).nil?
|
269
|
-
"<span type='list'>#{I18n.t('list')}#{I18n.t('format_number_without_chapter', [chapter.list(id).number])}</span>"
|
270
|
-
else
|
271
|
-
"<span type='list'>#{I18n.t('list')}#{I18n.t('format_number', [get_chap(chapter), chapter.list(id).number])}</span>"
|
272
|
-
end
|
273
|
-
rescue KeyError
|
274
|
-
error "unknown list: #{id}"
|
267
|
+
"<span type='list'>#{super(id)}</span>"
|
275
268
|
end
|
276
269
|
|
277
270
|
def list_header(id, caption, _lang)
|
@@ -369,25 +362,15 @@ module ReVIEW
|
|
369
362
|
end
|
370
363
|
|
371
364
|
def inline_table(id)
|
372
|
-
|
373
|
-
if get_chap(chapter).nil?
|
374
|
-
"<span type='table'>#{I18n.t('table')}#{I18n.t('format_number_without_chapter', [chapter.table(id).number])}</span>"
|
375
|
-
else
|
376
|
-
"<span type='table'>#{I18n.t('table')}#{I18n.t('format_number', [get_chap(chapter), chapter.table(id).number])}</span>"
|
377
|
-
end
|
378
|
-
rescue KeyError
|
379
|
-
error "unknown table: #{id}"
|
365
|
+
"<span type='table'>#{super(id)}</span>"
|
380
366
|
end
|
381
367
|
|
382
368
|
def inline_img(id)
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
end
|
389
|
-
rescue KeyError
|
390
|
-
error "unknown image: #{id}"
|
369
|
+
"<span type='image'>#{super(id)}</span>"
|
370
|
+
end
|
371
|
+
|
372
|
+
def inline_eq(id)
|
373
|
+
"<span type='eq'>#{super(id)}</span>"
|
391
374
|
end
|
392
375
|
|
393
376
|
def inline_imgref(id)
|
@@ -440,13 +423,26 @@ module ReVIEW
|
|
440
423
|
end
|
441
424
|
end
|
442
425
|
|
443
|
-
def texequation(lines)
|
426
|
+
def texequation(lines, id = nil, caption = '')
|
444
427
|
@texblockequation += 1
|
428
|
+
if id
|
429
|
+
puts '<equationblock>'
|
430
|
+
if get_chap.nil?
|
431
|
+
puts %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
|
432
|
+
else
|
433
|
+
puts %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
445
437
|
puts %Q(<replace idref="texblock-#{@texblockequation}">)
|
446
438
|
puts '<pre>'
|
447
439
|
puts lines.join("\n")
|
448
440
|
puts '</pre>'
|
449
441
|
puts '</replace>'
|
442
|
+
|
443
|
+
if id
|
444
|
+
puts '</equationblock>'
|
445
|
+
end
|
450
446
|
end
|
451
447
|
|
452
448
|
def table(lines, id = nil, caption = nil)
|
@@ -1067,20 +1063,30 @@ module ReVIEW
|
|
1067
1063
|
end
|
1068
1064
|
|
1069
1065
|
def inline_chapref(id)
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
if
|
1074
|
-
|
1066
|
+
if @book.config.check_version('2', exception: false)
|
1067
|
+
# backward compatibility
|
1068
|
+
chs = ['', '「', '」']
|
1069
|
+
if @book.config['chapref']
|
1070
|
+
chs2 = @book.config['chapref'].split(',')
|
1071
|
+
if chs2.size != 3
|
1072
|
+
error '--chapsplitter must have exactly 3 parameters with comma.'
|
1073
|
+
else
|
1074
|
+
chs = chs2
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
s = "#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
|
1078
|
+
if @book.config['chapterlink']
|
1079
|
+
%Q(<link href="#{id}">#{s}</link>)
|
1075
1080
|
else
|
1076
|
-
|
1081
|
+
s
|
1077
1082
|
end
|
1078
|
-
end
|
1079
|
-
s = "#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
|
1080
|
-
if @book.config['chapterlink']
|
1081
|
-
%Q(<link href="#{id}">#{s}</link>)
|
1082
1083
|
else
|
1083
|
-
|
1084
|
+
title = super
|
1085
|
+
if @book.config['chapterlink']
|
1086
|
+
%Q(<link href="#{id}">#{title}</link>)
|
1087
|
+
else
|
1088
|
+
title
|
1089
|
+
end
|
1084
1090
|
end
|
1085
1091
|
rescue KeyError
|
1086
1092
|
error "unknown chapter: #{id}"
|
data/lib/review/init.rb
CHANGED
@@ -170,13 +170,13 @@ EOS
|
|
170
170
|
|
171
171
|
File.open(dir + '/Rakefile', 'w') do |file|
|
172
172
|
file.write <<-EOS
|
173
|
-
Dir.glob('lib/tasks/*.rake').each do |file|
|
173
|
+
Dir.glob('lib/tasks/*.rake').sort.each do |file|
|
174
174
|
load(file)
|
175
175
|
end
|
176
176
|
EOS
|
177
177
|
end
|
178
178
|
|
179
|
-
FileUtils.cp(@review_dir + '/samples/sample-book/src/
|
179
|
+
FileUtils.cp(@review_dir + '/samples/sample-book/src/lib/tasks/review.rake',
|
180
180
|
dir + '/lib/tasks/review.rake')
|
181
181
|
end
|
182
182
|
|
data/lib/review/latexbuilder.rb
CHANGED
@@ -733,13 +733,28 @@ module ReVIEW
|
|
733
733
|
latex_block 'flushright', lines
|
734
734
|
end
|
735
735
|
|
736
|
-
def texequation(lines)
|
736
|
+
def texequation(lines, id = nil, caption = '')
|
737
737
|
blank
|
738
|
+
|
739
|
+
if id
|
740
|
+
puts macro('begin', 'reviewequationblock')
|
741
|
+
if get_chap.nil?
|
742
|
+
puts macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
|
743
|
+
else
|
744
|
+
puts macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
738
748
|
puts macro('begin', 'equation*')
|
739
749
|
lines.each do |line|
|
740
750
|
puts unescape(line)
|
741
751
|
end
|
742
752
|
puts macro('end', 'equation*')
|
753
|
+
|
754
|
+
if id
|
755
|
+
puts macro('end', 'reviewequationblock')
|
756
|
+
end
|
757
|
+
|
743
758
|
blank
|
744
759
|
end
|
745
760
|
|
@@ -863,6 +878,17 @@ module ReVIEW
|
|
863
878
|
error "unknown image: #{id}"
|
864
879
|
end
|
865
880
|
|
881
|
+
def inline_eq(id)
|
882
|
+
chapter, id = extract_chapter_id(id)
|
883
|
+
if get_chap(chapter).nil?
|
884
|
+
macro('reviewequationref', I18n.t('format_number_without_chapter', [chapter.equation(id).number]))
|
885
|
+
else
|
886
|
+
macro('reviewequationref', I18n.t('format_number', [get_chap(chapter), chapter.equation(id).number]))
|
887
|
+
end
|
888
|
+
rescue KeyError
|
889
|
+
error "unknown equation: #{id}"
|
890
|
+
end
|
891
|
+
|
866
892
|
def footnote(id, content)
|
867
893
|
if @book.config['footnotetext'] || @foottext[id]
|
868
894
|
puts macro("footnotetext[#{@chapter.footnote(id).number}]", compile_inline(content.strip))
|
data/lib/review/makerhelper.rb
CHANGED
@@ -75,7 +75,7 @@ module ReVIEW
|
|
75
75
|
|
76
76
|
def default_imgmath_preamble
|
77
77
|
<<-EOB
|
78
|
-
\\documentclass[uplatex]{jsarticle}
|
78
|
+
\\documentclass[uplatex,a3paper,landscape]{jsarticle}
|
79
79
|
\\usepackage[deluxe,uplatex]{otf}
|
80
80
|
\\usepackage[T1]{fontenc}
|
81
81
|
\\usepackage{textcomp}
|
@@ -92,6 +92,7 @@ module ReVIEW
|
|
92
92
|
\\usepackage{anyfontsize}
|
93
93
|
\\usepackage{bm}
|
94
94
|
\\pagestyle{empty}
|
95
|
+
% \\setpaperwidth{1000mm}
|
95
96
|
EOB
|
96
97
|
end
|
97
98
|
|
@@ -137,17 +137,6 @@ module ReVIEW
|
|
137
137
|
|
138
138
|
alias_method :lead, :read
|
139
139
|
|
140
|
-
def inline_list(id)
|
141
|
-
chapter, id = extract_chapter_id(id)
|
142
|
-
if get_chap(chapter)
|
143
|
-
%Q(#{I18n.t('list')}#{I18n.t('format_number', [get_chap(chapter), chapter.list(id).number])})
|
144
|
-
else
|
145
|
-
%Q(#{I18n.t('list')}#{I18n.t('format_number_without_chapter', [chapter.list(id).number])})
|
146
|
-
end
|
147
|
-
rescue KeyError
|
148
|
-
error "unknown list: #{id}"
|
149
|
-
end
|
150
|
-
|
151
140
|
def list_header(id, caption, _lang)
|
152
141
|
blank
|
153
142
|
if get_chap
|
@@ -207,28 +196,6 @@ module ReVIEW
|
|
207
196
|
base_parablock 'quote', lines, nil
|
208
197
|
end
|
209
198
|
|
210
|
-
def inline_table(id)
|
211
|
-
chapter, id = extract_chapter_id(id)
|
212
|
-
if get_chap(chapter)
|
213
|
-
"#{I18n.t('table')}#{I18n.t('format_number', [get_chap(chapter), chapter.table(id).number])}"
|
214
|
-
else
|
215
|
-
"#{I18n.t('table')}#{I18n.t('format_number_without_chapter', [chapter.table(id).number])}"
|
216
|
-
end
|
217
|
-
rescue KeyError
|
218
|
-
error "unknown table: #{id}"
|
219
|
-
end
|
220
|
-
|
221
|
-
def inline_img(id)
|
222
|
-
chapter, id = extract_chapter_id(id)
|
223
|
-
if get_chap(chapter)
|
224
|
-
"#{I18n.t('image')}#{I18n.t('format_number', [get_chap(chapter), chapter.image(id).number])}"
|
225
|
-
else
|
226
|
-
"#{I18n.t('image')}#{I18n.t('format_number_without_chapter', [chapter.image(id).number])}"
|
227
|
-
end
|
228
|
-
rescue KeyError
|
229
|
-
error "unknown image: #{id}"
|
230
|
-
end
|
231
|
-
|
232
199
|
def image(_lines, id, caption, _metric = nil)
|
233
200
|
blank
|
234
201
|
if get_chap
|
@@ -239,7 +206,16 @@ module ReVIEW
|
|
239
206
|
blank
|
240
207
|
end
|
241
208
|
|
242
|
-
def texequation(lines)
|
209
|
+
def texequation(lines, id = nil, caption = '')
|
210
|
+
if id
|
211
|
+
blank
|
212
|
+
if get_chap
|
213
|
+
puts "#{I18n.t('equation')}#{I18n.t('format_number', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
|
214
|
+
else
|
215
|
+
puts "#{I18n.t('equation')}#{I18n.t('format_number_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
243
219
|
puts lines.join("\n")
|
244
220
|
blank
|
245
221
|
end
|
@@ -623,15 +599,25 @@ module ReVIEW
|
|
623
599
|
end
|
624
600
|
|
625
601
|
def inline_chapref(id)
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
if
|
630
|
-
|
602
|
+
if @book.config.check_version('2', exception: false)
|
603
|
+
# backward compatibility
|
604
|
+
chs = ['', '「', '」']
|
605
|
+
if @book.config['chapref']
|
606
|
+
chs2 = @book.config['chapref'].split(',')
|
607
|
+
if chs2.size != 3
|
608
|
+
error '--chapsplitter must have exactly 3 parameters with comma.'
|
609
|
+
end
|
610
|
+
chs = chs2
|
611
|
+
end
|
612
|
+
"#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
|
613
|
+
else
|
614
|
+
title = super
|
615
|
+
if @book.config['chapterlink']
|
616
|
+
%Q(<link href="#{id}">#{title}</link>)
|
617
|
+
else
|
618
|
+
title
|
631
619
|
end
|
632
|
-
chs = chs2
|
633
620
|
end
|
634
|
-
"#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
|
635
621
|
rescue KeyError
|
636
622
|
error "unknown chapter: #{id}"
|
637
623
|
end
|
data/lib/review/rstbuilder.rb
CHANGED
@@ -297,11 +297,19 @@ module ReVIEW
|
|
297
297
|
blank
|
298
298
|
end
|
299
299
|
|
300
|
-
def texequation(lines)
|
300
|
+
def texequation(lines, id = nil, caption = '')
|
301
|
+
if id
|
302
|
+
puts ".. _#{id}:"
|
303
|
+
end
|
304
|
+
|
301
305
|
puts '.. math::'
|
302
306
|
blank
|
303
307
|
puts lines.map { |line| " #{line}" }.join
|
304
308
|
blank
|
309
|
+
if caption.present?
|
310
|
+
puts " #{caption}"
|
311
|
+
blank
|
312
|
+
end
|
305
313
|
end
|
306
314
|
|
307
315
|
def table_header(id, caption)
|
data/lib/review/topbuilder.rb
CHANGED
@@ -170,8 +170,16 @@ module ReVIEW
|
|
170
170
|
blank
|
171
171
|
end
|
172
172
|
|
173
|
-
def texequation(lines)
|
173
|
+
def texequation(lines, id = nil, caption = '')
|
174
|
+
blank
|
174
175
|
puts "◆→開始:#{@titles['texequation']}←◆"
|
176
|
+
if id
|
177
|
+
if get_chap
|
178
|
+
puts "#{I18n.t('equation')}#{I18n.t('format_number', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
|
179
|
+
else
|
180
|
+
puts "#{I18n.t('equation')}#{I18n.t('format_number_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
|
181
|
+
end
|
182
|
+
end
|
175
183
|
puts lines.join("\n")
|
176
184
|
puts "◆→終了:#{@titles['texequation']}←◆"
|
177
185
|
blank
|
@@ -0,0 +1,527 @@
|
|
1
|
+
#
|
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
|
+
require 'fileutils'
|
10
|
+
require 'optparse'
|
11
|
+
require 'review'
|
12
|
+
require 'review/i18n'
|
13
|
+
require 'yaml'
|
14
|
+
require 'digest'
|
15
|
+
|
16
|
+
module ReVIEW
|
17
|
+
class Update
|
18
|
+
def self.execute(*args)
|
19
|
+
new.execute(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
# should be
|
23
|
+
TARGET_VERSION = '3.0'
|
24
|
+
EPUB_VERSION = '3'
|
25
|
+
HTML_VERSION = '5'
|
26
|
+
TEX_DOCUMENTCLASS = ['review-jsbook', 'review-jlreq']
|
27
|
+
TEX_DOCUMENTCLASS_BAD = ['jsbook', nil]
|
28
|
+
TEX_DOCUMENTCLASS_OPTS = 'cameraready=print,paper=a5'
|
29
|
+
TEX_COMMAND = 'uplatex'
|
30
|
+
TEX_OPTIONS = '-interaction=nonstopmode -file-line-error'
|
31
|
+
DVI_COMMAND = 'dvipdfmx'
|
32
|
+
DVI_OPTIONS = '-d 5 -z 9'
|
33
|
+
|
34
|
+
attr_reader :config_ymls, :locale_ymls, :catalog_ymls, :tex_ymls, :epub_ymls
|
35
|
+
attr_accessor :force, :specified_template
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@template = nil
|
39
|
+
@specified_template = nil
|
40
|
+
@force = nil
|
41
|
+
@logger = ReVIEW.logger
|
42
|
+
@review_dir = File.dirname(File.expand_path('..', __dir__))
|
43
|
+
@config_ymls = []
|
44
|
+
@locale_ymls = []
|
45
|
+
@catalog_ymls = []
|
46
|
+
@tex_ymls = []
|
47
|
+
@epub_ymls = []
|
48
|
+
|
49
|
+
@backup = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def execute(*args)
|
53
|
+
parse_options(args)
|
54
|
+
dir = Dir.pwd
|
55
|
+
|
56
|
+
parse_ymls(dir)
|
57
|
+
check_old_catalogs(dir)
|
58
|
+
|
59
|
+
show_version
|
60
|
+
|
61
|
+
if @config_ymls.empty?
|
62
|
+
@logger.error t("!! No *.yml file with 'review_version' was found. Aborted. !!")
|
63
|
+
raise ApplicationError
|
64
|
+
end
|
65
|
+
|
66
|
+
check_own_files(dir)
|
67
|
+
update_version
|
68
|
+
update_rakefile(dir)
|
69
|
+
update_epub_version
|
70
|
+
update_locale
|
71
|
+
update_tex_parameters
|
72
|
+
if @template
|
73
|
+
update_tex_stys(@template, dir)
|
74
|
+
end
|
75
|
+
update_tex_command
|
76
|
+
update_dvi_command
|
77
|
+
|
78
|
+
puts t('Finished.')
|
79
|
+
rescue ApplicationError
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def t(message, args = [])
|
84
|
+
unless I18n.get(message)
|
85
|
+
I18n.set(message, message) # just copy
|
86
|
+
end
|
87
|
+
I18n.t(message, args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def confirm(message, args = [], default = true)
|
91
|
+
if @force
|
92
|
+
@logger.info t(message, args)
|
93
|
+
if default
|
94
|
+
@logger.info ' yes'
|
95
|
+
return true
|
96
|
+
else
|
97
|
+
@logger.info 'no'
|
98
|
+
return nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
loop do
|
103
|
+
print t(message, args)
|
104
|
+
if default
|
105
|
+
print ' [y]/n '
|
106
|
+
else
|
107
|
+
print ' y/[n] '
|
108
|
+
end
|
109
|
+
case gets.chomp.downcase
|
110
|
+
when 'yes', 'y'
|
111
|
+
return true
|
112
|
+
when 'no', 'n'
|
113
|
+
return nil
|
114
|
+
when ''
|
115
|
+
return default
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def rewrite_yml(yml, key, val)
|
121
|
+
content = File.read(yml)
|
122
|
+
content.gsub!(/^(\s*)#{key}:.*$/, '\1' + "#{key}: #{val}")
|
123
|
+
if @backup
|
124
|
+
FileUtils.mv yml, "#{yml}-old"
|
125
|
+
end
|
126
|
+
File.write(yml, content)
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_options(args)
|
130
|
+
opts = OptionParser.new
|
131
|
+
opts.version = ReVIEW::VERSION
|
132
|
+
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [option]"
|
133
|
+
opts.on('-h', '--help', 'print this message and quit.') do
|
134
|
+
puts opts.help
|
135
|
+
exit 0
|
136
|
+
end
|
137
|
+
opts.on('--latex-template name', 'specify LaTeX template name. (default: review-jsbook)') do |tname|
|
138
|
+
@specified_template = tname
|
139
|
+
end
|
140
|
+
|
141
|
+
begin
|
142
|
+
opts.parse!(args)
|
143
|
+
rescue OptionParser::ParseError => err
|
144
|
+
@logger.error err.message
|
145
|
+
$stderr.puts opts.help
|
146
|
+
raise ApplicationError
|
147
|
+
end
|
148
|
+
|
149
|
+
if @specified_template
|
150
|
+
tdir = File.join(@review_dir, 'templates/latex', @specified_template)
|
151
|
+
unless File.exist?(tdir)
|
152
|
+
@logger.error "!! #{tdir} not found. Aborted. !!"
|
153
|
+
raise ApplicationError
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def parse_ymls(dir)
|
159
|
+
language = 'en'
|
160
|
+
|
161
|
+
Dir.glob(File.join(dir, '*.yml')).sort.each do |yml|
|
162
|
+
begin
|
163
|
+
config = YAML.load_file(yml)
|
164
|
+
if config['language'].present?
|
165
|
+
language = config['language']
|
166
|
+
end
|
167
|
+
|
168
|
+
if config['review_version'].present?
|
169
|
+
@config_ymls.push(yml)
|
170
|
+
end
|
171
|
+
if config['texdocumentclass'].present? ||
|
172
|
+
config['texcommand'].present? ||
|
173
|
+
config['texoptions'].present? ||
|
174
|
+
config['dvicommand'].present? ||
|
175
|
+
config['dvioptions'].present? ||
|
176
|
+
config['pdfmaker'].present?
|
177
|
+
@tex_ymls.push(yml)
|
178
|
+
end
|
179
|
+
if config['epubmaker'].present? || config['epubversion'].present? ||
|
180
|
+
config['htmlversion'].present?
|
181
|
+
@epub_ymls.push(yml)
|
182
|
+
end
|
183
|
+
if config['locale'].present?
|
184
|
+
@locale_ymls.push(yml)
|
185
|
+
end
|
186
|
+
if config['PREDEF'].present? || config['CHAPS'].present? ||
|
187
|
+
config['APPENDIX'].present? || config['POSTDEF'].present?
|
188
|
+
@catalog_ymls.push(yml)
|
189
|
+
end
|
190
|
+
rescue Psych::SyntaxError
|
191
|
+
@logger.error "!! #{yml} is broken. Ignored. !!"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
I18n.setup(language)
|
195
|
+
|
196
|
+
@config_ymls.uniq!
|
197
|
+
@locale_ymls.uniq!
|
198
|
+
@catalog_ymls.uniq!
|
199
|
+
@tex_ymls.uniq!
|
200
|
+
@epub_ymls.uniq!
|
201
|
+
end
|
202
|
+
|
203
|
+
def check_old_catalogs(dir)
|
204
|
+
files = Dir.glob(File.join(dir, '*')).map do |fname|
|
205
|
+
if %w[PREDEF CHAPS POSTDEF PART].include?(File.basename(fname))
|
206
|
+
File.basename(fname)
|
207
|
+
else
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
end.compact
|
211
|
+
|
212
|
+
unless files.empty?
|
213
|
+
@logger.error t("!! %s file(s) is obsoleted. Run 'review-catalog-converter' to convert to 'catalog.yml' and remove old files. Aborted. !!", files.join(', '))
|
214
|
+
raise ApplicationError
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def show_version
|
219
|
+
puts t('** review-update updates your project to %s **', ReVIEW::VERSION)
|
220
|
+
end
|
221
|
+
|
222
|
+
def check_own_files(dir)
|
223
|
+
if File.exist?(File.join(dir, 'layouts/layout.tex.erb'))
|
224
|
+
unless confirm('** There is custom layouts/layout.tex.erb file. Updating may break to make PDF until you fix layout.tex.erb. Do you really proceed to update? **', [], nil)
|
225
|
+
raise ApplicationError
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
if File.exist?(File.join(dir, 'review-ext.rb'))
|
230
|
+
@logger.info t('** There is review-ext.rb file. You need to update it by yourself. **')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def update_version
|
235
|
+
@config_ymls.each do |yml|
|
236
|
+
config = YAML.load_file(yml)
|
237
|
+
if config['review_version'].to_f == TARGET_VERSION.to_f
|
238
|
+
next
|
239
|
+
end
|
240
|
+
|
241
|
+
flag = true
|
242
|
+
if config['review_version'].to_f > TARGET_VERSION.to_f
|
243
|
+
flag = nil
|
244
|
+
end
|
245
|
+
|
246
|
+
if confirm("%s: Update '%s' to '%s'?", [File.basename(yml), 'review_version', TARGET_VERSION], flag)
|
247
|
+
rewrite_yml(yml, 'review_version', TARGET_VERSION)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def update_rakefile(dir)
|
253
|
+
taskdir = File.join(dir, 'lib/tasks')
|
254
|
+
unless File.exist?(taskdir)
|
255
|
+
FileUtils.mkdir_p taskdir
|
256
|
+
end
|
257
|
+
|
258
|
+
master_rakefile = File.join(@review_dir, 'samples/sample-book/src/Rakefile')
|
259
|
+
|
260
|
+
target_rakefile = File.join(dir, 'Rakefile')
|
261
|
+
if File.exist?(target_rakefile)
|
262
|
+
if Digest::SHA256.hexdigest(File.read(target_rakefile)) != Digest::SHA256.hexdigest(File.read(master_rakefile))
|
263
|
+
if confirm('%s will be overridden with Re:VIEW version (%s). Do you really proceed?', ['Rakefile', master_rakefile])
|
264
|
+
FileUtils.mv target_rakefile, "#{target_rakefile}-old"
|
265
|
+
FileUtils.cp master_rakefile, target_rakefile
|
266
|
+
end
|
267
|
+
end
|
268
|
+
else
|
269
|
+
FileUtils.cp master_rakefile, target_rakefile
|
270
|
+
end
|
271
|
+
|
272
|
+
master_rakefile = File.join(@review_dir, 'samples/sample-book/src/lib/tasks/review.rake')
|
273
|
+
target_rakefile = File.join(taskdir, 'review.rake')
|
274
|
+
if File.exist?(target_rakefile)
|
275
|
+
if Digest::SHA256.hexdigest(File.read(target_rakefile)) != Digest::SHA256.hexdigest(File.read(master_rakefile))
|
276
|
+
if confirm('%s will be overridden with Re:VIEW version (%s). Do you really proceed?', ['lib/tasks/review.rake', master_rakefile])
|
277
|
+
FileUtils.mv target_rakefile, "#{target_rakefile}-old"
|
278
|
+
FileUtils.cp master_rakefile, target_rakefile
|
279
|
+
end
|
280
|
+
end
|
281
|
+
else
|
282
|
+
FileUtils.cp master_rakefile, target_rakefile
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def update_epub_version
|
287
|
+
@epub_ymls.each do |yml|
|
288
|
+
config = YAML.load_file(yml)
|
289
|
+
if config['epubversion'].present? && config['epubversion'].to_f < EPUB_VERSION.to_f
|
290
|
+
if confirm("%s: Update '%s' to '%s' from '%s'?", [File.basename(yml), 'epubversion', EPUB_VERSION, config['epubversion']])
|
291
|
+
rewrite_yml(yml, 'epubversion', EPUB_VERSION)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
if !config['htmlversion'].present? || config['htmlversion'].to_f >= HTML_VERSION.to_f
|
295
|
+
next
|
296
|
+
end
|
297
|
+
if confirm("%s: Update '%s' to '%s' from '%s'?", [File.basename(yml), 'htmlversion', HTML_VERSION, config['htmlversion']])
|
298
|
+
rewrite_yml(yml, 'htmlversion', HTML_VERSION)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def update_locale
|
304
|
+
@locale_ymls.each do |yml|
|
305
|
+
config = YAML.load_file(yml)
|
306
|
+
if !config['chapter_quote'].present? || config['chapter_quote'].scan('%s').size != 1
|
307
|
+
next
|
308
|
+
end
|
309
|
+
v = config['chapter_quote'].sub('%s', '%s %s')
|
310
|
+
if confirm("%s: 'chapter_quote' now takes 2 values. Update '%s' to '%s'?", [File.basename(yml), config['chapter_quote'], v])
|
311
|
+
rewrite_yml(yml, 'chapter_quote', v)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def update_tex_parameters
|
317
|
+
@tex_ymls.each do |yml|
|
318
|
+
config = YAML.load_file(yml)
|
319
|
+
unless config['texdocumentclass']
|
320
|
+
next
|
321
|
+
end
|
322
|
+
|
323
|
+
if TEX_DOCUMENTCLASS.include?(config['texdocumentclass'][0])
|
324
|
+
if @specified_template.present? && config['texdocumentclass'][0] != @specified_template
|
325
|
+
# want to use other template?
|
326
|
+
@logger.error t("%s: !! 'texdocumentclass' uses new class '%s' already, but you specified '%s'. This tool can't handle such migration. Ignored. !!", [File.basename(yml), config['texdocumentclass'][0], @specified_template])
|
327
|
+
@template = nil
|
328
|
+
end
|
329
|
+
next
|
330
|
+
else
|
331
|
+
@template = config['texdocumentclass'][0]
|
332
|
+
end
|
333
|
+
|
334
|
+
if TEX_DOCUMENTCLASS_BAD.include?(config['texdocumentclass'][0])
|
335
|
+
cno = TEX_DOCUMENTCLASS_BAD.index(config['texdocumentclass'][0])
|
336
|
+
|
337
|
+
if @specified_template && @specified_template != TEX_DOCUMENTCLASS[cno]
|
338
|
+
# not default, manually selected
|
339
|
+
unless confirm("%s: 'texdocumentclass' uses the old class '%s'. By default it is migrated to '%s', but you specify '%s'. Do you really migrate 'texdocumentclass' to '%s'?",
|
340
|
+
[File.basename(yml), TEX_DOCUMENTCLASS_BAD[cno],
|
341
|
+
TEX_DOCUMENTCLASS[cno],
|
342
|
+
@specified_template, @specified_template])
|
343
|
+
@template = nil
|
344
|
+
next
|
345
|
+
end
|
346
|
+
@template = @specified_template
|
347
|
+
else
|
348
|
+
# default migration
|
349
|
+
@template = TEX_DOCUMENTCLASS[cno]
|
350
|
+
unless confirm("%s: 'texdocumentclass' uses the old class '%s'. By default it is migrated to '%s'. Do you really migrate 'texdocumentclass' to '%s'?", [File.basename(yml), TEX_DOCUMENTCLASS_BAD[cno], @template, @template])
|
351
|
+
@template = nil
|
352
|
+
next
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
flag, modified_opts = convert_documentclass_opts(yml, @template, config['texdocumentclass'][1])
|
357
|
+
if flag # successfully converted
|
358
|
+
@logger.info t("%s: previous 'texdocumentclass' option '%s' is safely replaced with '%s'.", [File.basename(yml), config['texdocumentclass'][1], modified_opts])
|
359
|
+
else # something wrong
|
360
|
+
unless confirm("%s: previous 'texdocumentclass' option '%s' couldn't be converted fully. '%s' is suggested. Do you really proceed?", [File.basename(yml), config['texdocumentclass'][1], modified_opts], nil)
|
361
|
+
@template = nil
|
362
|
+
next
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
rewrite_yml(yml, 'texdocumentclass', %Q(["#{@template}", "#{modified_opts}"]))
|
367
|
+
else
|
368
|
+
@template = nil
|
369
|
+
@logger.error t("%s: ** 'texdocumentclass' specifies '%s'. Because this is unknown class for this tool, you need to update it by yourself if it won't work. **", [File.basename(yml), config['texdocumentclass']])
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def convert_documentclass_opts(yml, cls, prev_opts)
|
375
|
+
# XXX: at this time, review-jsbook and review-jlreq uses same parameters
|
376
|
+
opts = []
|
377
|
+
flag = true
|
378
|
+
case cls
|
379
|
+
when 'review-jsbook' # at this time, it ignores keyval
|
380
|
+
prev_opts.split(/\s*,\s*/).each do |v|
|
381
|
+
case v
|
382
|
+
when 'a4j', 'a5j', 'b4j', 'b5j', 'a3paper', 'a4paper', 'a5paper', 'a6paper', 'b4paper', 'b5paper', 'b6paper', 'letterpaper', 'legalpaper', 'executivepaper'
|
383
|
+
opts << "paper=#{v.sub('j', '').sub('paper', '')}"
|
384
|
+
when /[\d.]+ptj/ # not cared...
|
385
|
+
q = sprintf('%.2f', v.sub('pt', '').to_f * 1.4056)
|
386
|
+
opts << "Q=#{q}"
|
387
|
+
when /[\d.]+pt/
|
388
|
+
q = sprintf('%.2f', v.sub('pt', '').to_f * 1.4056)
|
389
|
+
opts << "Q=#{q}"
|
390
|
+
when /[\d.]+Q/
|
391
|
+
opts << "Q=#{v.sub('Q', '')}"
|
392
|
+
when 'landscape', 'oneside', 'twoside', 'vartwoside', 'onecolumn',
|
393
|
+
'twocolumn', 'titlepage', 'notitlepage', 'openright',
|
394
|
+
'openany', 'leqno', 'fleqn', 'disablejfam', 'draft', 'final',
|
395
|
+
'mingoth', 'winjis', 'jis', 'papersize', 'english', 'report',
|
396
|
+
'jslogo', 'nojslogo'
|
397
|
+
# pass-through
|
398
|
+
opts << v
|
399
|
+
when 'uplatex', 'nomag', 'usemag', 'nomag*', 'tombow', 'tombo', 'mentuke', 'autodetect-engine'
|
400
|
+
# can be ignored
|
401
|
+
next
|
402
|
+
else
|
403
|
+
flag = nil
|
404
|
+
end
|
405
|
+
end
|
406
|
+
opts << 'cameraready=print'
|
407
|
+
opts << 'cover=false'
|
408
|
+
when 'review-jlreq'
|
409
|
+
# at this time, only think about jsbook->jlreq
|
410
|
+
prev_opts.split(/\s*,\s*/).each do |v|
|
411
|
+
case v
|
412
|
+
when 'a4j', 'a5j', 'b4j', 'b5j', 'a3paper', 'a4paper', 'a5paper', 'a6paper', 'b4paper', 'b5paper', 'b6paper', 'letterpaper', 'legalpaper', 'executivepaper'
|
413
|
+
opts << "paper=#{v.sub('j', '').sub('paper', '')}"
|
414
|
+
when /[\d.]+ptj/ # not cared...
|
415
|
+
opts << "fontsize=#{v.sub('j', '')}"
|
416
|
+
when /[\d.]+pt/
|
417
|
+
opts << "fontsize=#{v}"
|
418
|
+
when /[\d.]+Q/
|
419
|
+
opts << "fontsize=#{v}"
|
420
|
+
when 'landscape', 'oneside', 'twoside', 'onecolumn', 'twocolumn', 'titlepage', 'notitlepage', 'openright', 'openany', 'leqno', 'fleqn', 'draft', 'final', 'report'
|
421
|
+
# pass-through
|
422
|
+
opts << v
|
423
|
+
when 'uplatex', 'nomag', 'usemag', 'nomag*', 'tombow', 'tombo', 'mentuke', 'autodetect-engine'
|
424
|
+
# can be ignored
|
425
|
+
next
|
426
|
+
else
|
427
|
+
# 'vartwoside', 'disablejfam', 'mingoth', 'winjis', 'jis', 'papersize', 'english', 'jslogo', 'nojslogo'
|
428
|
+
flag = nil
|
429
|
+
end
|
430
|
+
end
|
431
|
+
opts << 'cameraready=print'
|
432
|
+
opts << 'cover=false'
|
433
|
+
else
|
434
|
+
flag = nil
|
435
|
+
@logger.error t("%s: ** '%s' is unknown class. Ignored. **", [File.basename(yml), cls])
|
436
|
+
end
|
437
|
+
return flag, opts.join(',')
|
438
|
+
end
|
439
|
+
|
440
|
+
def update_tex_stys(template, dir)
|
441
|
+
texmacrodir = File.join(dir, 'sty')
|
442
|
+
unless File.exist?(texmacrodir)
|
443
|
+
FileUtils.mkdir texmacrodir
|
444
|
+
end
|
445
|
+
|
446
|
+
tdir = File.join(@review_dir, 'templates/latex', template)
|
447
|
+
Dir.glob(File.join(tdir, '*.*')).each do |master_styfile|
|
448
|
+
target_styfile = File.join(texmacrodir, File.basename(master_styfile))
|
449
|
+
|
450
|
+
unless File.exist?(target_styfile)
|
451
|
+
# just copy
|
452
|
+
FileUtils.cp master_styfile, target_styfile
|
453
|
+
next
|
454
|
+
end
|
455
|
+
if File.basename(target_styfile) == 'review-custom.sty'
|
456
|
+
next
|
457
|
+
end
|
458
|
+
|
459
|
+
if Digest::SHA256.hexdigest(File.read(target_styfile)) == Digest::SHA256.hexdigest(File.read(master_styfile))
|
460
|
+
# same
|
461
|
+
next
|
462
|
+
end
|
463
|
+
|
464
|
+
if confirm('%s will be overridden with Re:VIEW version (%s). Do you really proceed?', [target_styfile, master_styfile])
|
465
|
+
FileUtils.mv target_styfile, "#{target_styfile}-old"
|
466
|
+
FileUtils.cp master_styfile, target_styfile
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
if template == 'review-jsbook'
|
471
|
+
# provide gentombow from vendor/. current version is 2018/08/30 v0.9j
|
472
|
+
unless File.exist?(File.join(texmacrodir, 'gentombow09j.sty'))
|
473
|
+
FileUtils.cp File.join(@review_dir, 'vendor/gentombow/gentombow.sty'), File.join(texmacrodir, 'gentombow09j.sty')
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
def update_tex_command
|
479
|
+
@tex_ymls.each do |yml|
|
480
|
+
config = YAML.load_file(yml)
|
481
|
+
if !config['texcommand'] || config['texcommand'] !~ /\s+\-/
|
482
|
+
next
|
483
|
+
end
|
484
|
+
# option should be moved to texoptions
|
485
|
+
cmd, opts = config['texcommand'].split(/\s+\-/, 2)
|
486
|
+
opts = "-#{opts}"
|
487
|
+
|
488
|
+
unless confirm("%s: 'texcommand' has options ('%s'). Move it to 'texoptions'?", [File.basename(yml), opts])
|
489
|
+
next
|
490
|
+
end
|
491
|
+
|
492
|
+
if config['texoptions'].present?
|
493
|
+
config['texoptions'] += " #{opts}"
|
494
|
+
rewrite_yml(yml, 'texcommand', %Q("#{cmd}"))
|
495
|
+
rewrite_yml(yml, 'texoptions', %Q("#{config['texoptions']}"))
|
496
|
+
else
|
497
|
+
rewrite_yml(yml, 'texcommand', %Q("#{cmd}"\ntexoptions: "#{TEX_OPTIONS} #{opts}"))
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
def update_dvi_command
|
503
|
+
@tex_ymls.each do |yml|
|
504
|
+
config = YAML.load_file(yml)
|
505
|
+
if !config['dvicommand'] || config['dvicommand'] !~ /\s+\-/
|
506
|
+
next
|
507
|
+
end
|
508
|
+
|
509
|
+
# option should be moved to dvioptions
|
510
|
+
cmd, opts = config['dvicommand'].split(/\s+\-/, 2)
|
511
|
+
opts = "-#{opts}"
|
512
|
+
|
513
|
+
unless confirm("%s: 'dvicommand' has options ('%s'). Move it to 'dvioptions'?", [File.basename(yml), opts])
|
514
|
+
next
|
515
|
+
end
|
516
|
+
|
517
|
+
if config['dvioptions'].present?
|
518
|
+
config['dvioptions'] += " #{opts}"
|
519
|
+
rewrite_yml(yml, 'dvicommand', %Q("#{cmd}"))
|
520
|
+
rewrite_yml(yml, 'dvioptions', %Q("#{config['dvioptions']}"))
|
521
|
+
else
|
522
|
+
rewrite_yml(yml, 'dvicommand', %Q("#{cmd}"\ndvioptions: "#{DVI_OPTIONS} #{opts}"))
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|