review 3.0.0.preview3 → 3.0.0.preview4

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.ja.md +26 -0
  3. data/NEWS.md +26 -0
  4. data/bin/review +2 -0
  5. data/bin/review-update +19 -0
  6. data/doc/format.ja.md +11 -0
  7. data/doc/format.md +11 -1
  8. data/doc/format_idg.ja.md +2 -4
  9. data/lib/review/book/chapter.rb +1 -0
  10. data/lib/review/book/compilable.rb +9 -0
  11. data/lib/review/book/index.rb +7 -1
  12. data/lib/review/builder.rb +29 -3
  13. data/lib/review/compiler.rb +2 -1
  14. data/lib/review/htmlbuilder.rb +40 -28
  15. data/lib/review/i18n.rb +8 -0
  16. data/lib/review/i18n.yml +22 -1
  17. data/lib/review/idgxmlbuilder.rb +42 -36
  18. data/lib/review/init.rb +2 -2
  19. data/lib/review/latexbuilder.rb +27 -1
  20. data/lib/review/makerhelper.rb +2 -1
  21. data/lib/review/plaintextbuilder.rb +27 -41
  22. data/lib/review/rstbuilder.rb +9 -1
  23. data/lib/review/topbuilder.rb +9 -1
  24. data/lib/review/update.rb +527 -0
  25. data/lib/review/version.rb +1 -1
  26. data/review.gemspec +1 -1
  27. data/samples/sample-book/README.md +1 -1
  28. data/samples/sample-book/src/Rakefile +2 -112
  29. data/samples/sample-book/src/config.yml +3 -1
  30. data/samples/sample-book/src/lib/tasks/review.rake +113 -0
  31. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +17 -0
  32. data/samples/sample-book/src/sty/reviewmacro.sty +15 -1
  33. data/samples/syntax-book/Rakefile +2 -87
  34. data/samples/syntax-book/ch02.re +6 -1
  35. data/samples/syntax-book/config.yml +7 -4
  36. data/samples/syntax-book/images/cover-b5.ai +5735 -15
  37. data/samples/syntax-book/lib/tasks/review.rake +113 -0
  38. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +17 -0
  39. data/samples/syntax-book/sty/reviewmacro.sty +11 -35
  40. data/templates/latex/config.erb +1 -0
  41. data/templates/latex/review-jlreq/review-base.sty +4 -0
  42. data/templates/latex/review-jlreq/review-jlreq.cls +56 -2
  43. data/templates/latex/review-jlreq/review-style.sty +0 -6
  44. data/templates/latex/review-jsbook/review-base.sty +5 -0
  45. data/test/assets/test_template.tex +2 -1
  46. data/test/assets/test_template_backmatter.tex +2 -1
  47. data/test/test_htmlbuilder.rb +39 -1
  48. data/test/test_idgxmlbuilder.rb +24 -0
  49. data/test/test_latexbuilder.rb +39 -0
  50. data/test/test_pdfmaker_cmd.rb +1 -1
  51. data/test/test_plaintextbuilder.rb +19 -0
  52. data/test/test_topbuilder.rb +21 -0
  53. data/test/test_update.rb +450 -0
  54. metadata +12 -2
@@ -264,14 +264,7 @@ module ReVIEW
264
264
  end
265
265
 
266
266
  def inline_list(id)
267
- chapter, id = extract_chapter_id(id)
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
- chapter, id = extract_chapter_id(id)
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
- chapter, id = extract_chapter_id(id)
384
- if get_chap(chapter).nil?
385
- "<span type='image'>#{I18n.t('image')}#{I18n.t('format_number_without_chapter', [chapter.image(id).number])}</span>"
386
- else
387
- "<span type='image'>#{I18n.t('image')}#{I18n.t('format_number', [get_chap(chapter), chapter.image(id).number])}</span>"
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
- chs = ['', '「', '」']
1071
- if @book.config['chapref']
1072
- chs2 = @book.config['chapref'].split(',')
1073
- if chs2.size != 3
1074
- error '--chapsplitter must have exactly 3 parameters with comma.'
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
- chs = chs2
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
- s
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}"
@@ -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/Rakefile',
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
 
@@ -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))
@@ -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
- chs = ['', '「', '」']
627
- if @book.config['chapref']
628
- chs2 = @book.config['chapref'].split(',')
629
- if chs2.size != 3
630
- error '--chapsplitter must have exactly 3 parameters with comma.'
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
@@ -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)
@@ -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