review 5.3.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +1 -1
  3. data/.github/workflows/ruby.yml +1 -1
  4. data/.rubocop.yml +1 -322
  5. data/NEWS.ja.md +48 -0
  6. data/NEWS.md +48 -0
  7. data/README.md +9 -8
  8. data/bin/review +1 -1
  9. data/bin/review-catalog-converter +15 -15
  10. data/bin/review-check +7 -7
  11. data/bin/review-compile +6 -8
  12. data/bin/review-index +1 -1
  13. data/bin/review-preproc +1 -1
  14. data/bin/review-validate +2 -2
  15. data/doc/config.yml.sample +7 -1
  16. data/doc/config.yml.sample-simple +1 -1
  17. data/lib/review/book/base.rb +3 -3
  18. data/lib/review/book/book_unit.rb +1 -1
  19. data/lib/review/book/chapter.rb +1 -1
  20. data/lib/review/book/index.rb +3 -3
  21. data/lib/review/book/part.rb +12 -13
  22. data/lib/review/book/volume.rb +1 -1
  23. data/lib/review/builder.rb +10 -12
  24. data/lib/review/catalog.rb +5 -5
  25. data/lib/review/compiler.rb +13 -13
  26. data/lib/review/configure.rb +5 -2
  27. data/lib/review/epub2html.rb +12 -12
  28. data/lib/review/epubmaker/content.rb +1 -1
  29. data/lib/review/epubmaker/epubcommon.rb +44 -42
  30. data/lib/review/epubmaker/epubv2.rb +2 -1
  31. data/lib/review/epubmaker/epubv3.rb +5 -4
  32. data/lib/review/epubmaker/producer.rb +3 -3
  33. data/lib/review/epubmaker/reviewheaderlistener.rb +1 -1
  34. data/lib/review/epubmaker.rb +32 -31
  35. data/lib/review/extentions/string.rb +1 -1
  36. data/lib/review/htmlbuilder.rb +16 -15
  37. data/lib/review/htmlutils.rb +17 -17
  38. data/lib/review/i18n.rb +3 -3
  39. data/lib/review/idgxmlbuilder.rb +22 -21
  40. data/lib/review/idgxmlmaker.rb +15 -13
  41. data/lib/review/index_builder.rb +4 -20
  42. data/lib/review/init.rb +4 -4
  43. data/lib/review/latexbuilder.rb +30 -32
  44. data/lib/review/lineinput.rb +3 -3
  45. data/lib/review/location.rb +1 -1
  46. data/lib/review/logger.rb +21 -21
  47. data/lib/review/makerhelper.rb +3 -3
  48. data/lib/review/markdownbuilder.rb +6 -6
  49. data/lib/review/pdfmaker.rb +23 -19
  50. data/lib/review/plaintextbuilder.rb +5 -5
  51. data/lib/review/preprocessor/repository.rb +1 -1
  52. data/lib/review/preprocessor.rb +5 -5
  53. data/lib/review/textmaker.rb +20 -18
  54. data/lib/review/textutils.rb +3 -5
  55. data/lib/review/topbuilder.rb +71 -12
  56. data/lib/review/update.rb +16 -8
  57. data/lib/review/version.rb +1 -1
  58. data/lib/review/webmaker.rb +32 -32
  59. data/lib/review/webtocprinter.rb +10 -10
  60. data/lib/review/yamlloader.rb +35 -2
  61. data/review.gemspec +1 -0
  62. data/samples/sample-book/src/config.yml +0 -1
  63. data/templates/html/_titlepage.html.erb +9 -17
  64. data/templates/opf/opf_manifest_epubv2.opf.erb +1 -1
  65. data/templates/opf/opf_manifest_epubv3.opf.erb +1 -1
  66. data/test/book_test_helper.rb +10 -10
  67. data/test/test_epub3maker.rb +3 -3
  68. data/test/test_epubmaker.rb +14 -29
  69. data/test/test_epubmaker_cmd.rb +2 -2
  70. data/test/test_htmlbuilder.rb +4 -5
  71. data/test/test_idgxmlbuilder.rb +10 -10
  72. data/test/test_idgxmlmaker_cmd.rb +1 -1
  73. data/test/test_img_math.rb +11 -2
  74. data/test/test_latexbuilder.rb +2 -3
  75. data/test/test_pdfmaker_cmd.rb +10 -10
  76. data/test/test_textmaker_cmd.rb +1 -1
  77. data/test/test_topbuilder.rb +151 -11
  78. data/test/test_yamlloader.rb +28 -42
  79. metadata +8 -7
@@ -165,7 +165,7 @@ module ReVIEW
165
165
  end
166
166
 
167
167
  def check_spec(spec)
168
- app_error "wrong spec: #{spec.inspect}" unless /\A\w+\z/ =~ spec
168
+ app_error "wrong spec: #{spec.inspect}" unless /\A\w+\z/.match?(spec)
169
169
  spec
170
170
  end
171
171
 
@@ -70,11 +70,11 @@ module ReVIEW
70
70
  direc = parse_directive(line, 1, 'eval')
71
71
  path = expand(direc.arg)
72
72
  @leave_content = File.extname(path) == '.re'
73
- if direc['eval']
74
- ent = evaluate(path, ent)
75
- else
76
- ent = @repository.fetch_file(path)
77
- end
73
+ ent = if direc['eval']
74
+ evaluate(path, ent)
75
+ else
76
+ @repository.fetch_file(path)
77
+ end
78
78
  replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
79
79
 
80
80
  when /\A\#@map(?:range)?/
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2021 Kenshi Muto
1
+ # Copyright (c) 2018-2022 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -74,9 +74,14 @@ module ReVIEW
74
74
  cmd_config, yamlfile = parse_opts(args)
75
75
  error! "#{yamlfile} not found." unless File.exist?(yamlfile)
76
76
 
77
- @config = ReVIEW::Configure.create(maker: 'textmaker',
78
- yamlfile: yamlfile,
79
- config: cmd_config)
77
+ begin
78
+ @config = ReVIEW::Configure.create(maker: 'textmaker',
79
+ yamlfile: yamlfile,
80
+ config: cmd_config)
81
+ rescue ReVIEW::ConfigError => e
82
+ error! e.message
83
+ end
84
+
80
85
  @img_math = ReVIEW::ImgMath.new(@config, path_name: '_review_math_text')
81
86
 
82
87
  I18n.setup(@config['language'])
@@ -111,12 +116,11 @@ module ReVIEW
111
116
 
112
117
  def build_body(basetmpdir, _yamlfile)
113
118
  base_path = Pathname.new(@basedir)
114
- builder = nil
115
- if @plaintext
116
- builder = ReVIEW::PLAINTEXTBuilder.new(img_math: @img_math)
117
- else
118
- builder = ReVIEW::TOPBuilder.new(img_math: @img_math)
119
- end
119
+ builder = if @plaintext
120
+ ReVIEW::PLAINTEXTBuilder.new(img_math: @img_math)
121
+ else
122
+ ReVIEW::TOPBuilder.new(img_math: @img_math)
123
+ end
120
124
  @converter = ReVIEW::Converter.new(@book, builder)
121
125
  @book.parts.each do |part|
122
126
  if part.name.present?
@@ -142,13 +146,11 @@ module ReVIEW
142
146
  end
143
147
 
144
148
  def build_chap(chap, base_path, basetmpdir, ispart)
145
- filename = ''
146
-
147
- if ispart.present?
148
- filename = chap.path
149
- else
150
- filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
151
- end
149
+ filename = if ispart.present?
150
+ chap.path
151
+ else
152
+ Pathname.new(chap.path).relative_path_from(base_path).to_s
153
+ end
152
154
  id = File.basename(filename).sub(/\.re\Z/, '')
153
155
  if @buildonly && !@buildonly.include?(id)
154
156
  warn "skip #{id}.re"
@@ -159,7 +161,7 @@ module ReVIEW
159
161
 
160
162
  begin
161
163
  @converter.convert(filename, File.join(basetmpdir, textfile))
162
- rescue => e
164
+ rescue StandardError => e
163
165
  @compile_errors = true
164
166
  error "compile error in #{filename} (#{e.class})"
165
167
  error e.message
@@ -72,13 +72,11 @@ module ReVIEW
72
72
  end
73
73
 
74
74
  # lazy than rule 3, but it looks better
75
- if lazy
76
- if (%i[F W H].include?(Unicode::Eaw.property(tail)) &&
75
+ if lazy && ((%i[F W H].include?(Unicode::Eaw.property(tail)) &&
77
76
  tail !~ /\p{Hangul}/) ||
78
77
  (%i[F W H].include?(Unicode::Eaw.property(head)) &&
79
- head !~ /\p{Hangul}/)
80
- space = nil
81
- end
78
+ head !~ /\p{Hangul}/))
79
+ space = nil
82
80
  end
83
81
  end
84
82
  space
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2021 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2008-2022 Minero Aoki, Kenshi Muto
2
2
  # 2002-2006 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -262,13 +262,61 @@ module ReVIEW
262
262
  blank
263
263
  end
264
264
 
265
+ def table_rows(sepidx, rows)
266
+ if sepidx
267
+ sepidx.times do
268
+ tr(rows.shift.map { |s| th(s) })
269
+ end
270
+ if !@book.config['textmaker'] || !@book.config['textmaker']['th_bold']
271
+ puts '-' * 12
272
+ end
273
+ rows.each do |cols|
274
+ tr(cols.map { |s| td(s) })
275
+ end
276
+ else
277
+ rows.each do |cols|
278
+ h, *cs = *cols
279
+ tr([th(h)] + cs.map { |s| td(s) })
280
+ end
281
+ end
282
+ end
283
+
265
284
  def th(str)
266
- "★#{str}☆"
285
+ if @book.config['textmaker'] && @book.config['textmaker']['th_bold']
286
+ "★#{str}☆"
287
+ else
288
+ str
289
+ end
267
290
  end
268
291
 
269
292
  def table_end
270
293
  end
271
294
 
295
+ def imgtable(lines, id, caption = nil, metric = nil)
296
+ metrics = parse_metric('top', metric)
297
+ metrics = " #{metrics}" if metrics.present?
298
+ blank
299
+ puts "◆→開始:#{@titles['table']}←◆"
300
+ if caption_top?('table') && caption.present?
301
+ table_header(id, caption)
302
+ end
303
+
304
+ if @chapter.image_bound?(id)
305
+ puts "◆→#{@chapter.image(id).path}#{metrics}←◆"
306
+ else
307
+ warn "image not bound: #{id}", location: location
308
+ lines.each do |line|
309
+ puts line
310
+ end
311
+ end
312
+
313
+ if !caption_top?('table') && caption.present?
314
+ table_header(id, caption)
315
+ end
316
+ puts "◆→終了:#{@titles['table']}←◆"
317
+ blank
318
+ end
319
+
272
320
  def comment(lines, comment = nil)
273
321
  return unless @book.config['draft']
274
322
 
@@ -314,8 +362,9 @@ module ReVIEW
314
362
 
315
363
  def compile_kw(word, alt)
316
364
  if alt
317
- then "★#{word}☆(#{alt.strip})"
318
- else "★#{word}☆"
365
+ "★#{word}☆(#{alt.strip})"
366
+ else
367
+ "★#{word}☆"
319
368
  end
320
369
  end
321
370
 
@@ -398,7 +447,7 @@ module ReVIEW
398
447
  def inline_icon(id)
399
448
  begin
400
449
  "◆→画像 #{@chapter.image(id).path.sub(%r{\A\./}, '')}←◆"
401
- rescue
450
+ rescue StandardError
402
451
  warn "image not bound: #{id}", location: location
403
452
  "◆→画像 #{id}←◆"
404
453
  end
@@ -495,27 +544,37 @@ module ReVIEW
495
544
  ), __FILE__, __LINE__ - 11
496
545
  end
497
546
 
498
- def indepimage(_lines, id, caption = nil, metric = nil)
547
+ def indepimage(lines, id, caption = nil, metric = nil)
499
548
  metrics = parse_metric('top', metric)
500
549
  metrics = " #{metrics}" if metrics.present?
501
550
  blank
551
+ puts "◆→開始:#{@titles['image']}←◆"
502
552
  if caption_top?('image') && caption.present?
503
- puts "図 #{compile_inline(caption)}"
553
+ indepimage_header(id, caption)
554
+ blank
504
555
  end
505
- begin
506
- puts "◆→画像 #{@chapter.image(id).path.sub(%r{\A\./}, '')}#{metrics}←◆"
507
- rescue
556
+ if @chapter.image_bound?(id)
557
+ puts "◆→#{@chapter.image(id).path}#{metrics}←◆"
558
+ else
508
559
  warn "image not bound: #{id}", location: location
509
- puts "◆→画像 #{id}←◆"
560
+ lines.each do |line|
561
+ puts line
562
+ end
510
563
  end
511
564
  if !caption_top?('image') && caption.present?
512
- puts "図 #{compile_inline(caption)}"
565
+ blank
566
+ indepimage_header(id, caption)
513
567
  end
568
+ puts "◆→終了:#{@titles['image']}←◆"
514
569
  blank
515
570
  end
516
571
 
517
572
  alias_method :numberlessimage, :indepimage
518
573
 
574
+ def indepimage_header(_id, caption)
575
+ puts "図#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
576
+ end
577
+
519
578
  def inline_code(str)
520
579
  "△#{str}☆"
521
580
  end
data/lib/review/update.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2018-2020 Kenshi Muto
2
+ # Copyright (c) 2018-2022 Kenshi Muto
3
3
  #
4
4
  # This program is free software.
5
5
  # You can distribute or modify this program under the terms of
@@ -165,7 +165,7 @@ module ReVIEW
165
165
 
166
166
  Dir.glob(File.join(dir, '*.yml')).sort.each do |yml|
167
167
  begin
168
- config = YAML.load_file(yml)
168
+ config = YAMLLoader.safe_load_file(yml)
169
169
  if config['language'].present?
170
170
  language = config['language']
171
171
  end
@@ -226,9 +226,11 @@ module ReVIEW
226
226
 
227
227
  def check_own_files(dir)
228
228
  if File.exist?(File.join(dir, 'layouts/layout.tex.erb'))
229
+ # rubocop:disable Style/SoleNestedConditional
229
230
  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)
230
231
  raise ApplicationError
231
232
  end
233
+ # rubocop:enable Style/SoleNestedConditional
232
234
  end
233
235
 
234
236
  if File.exist?(File.join(dir, 'review-ext.rb'))
@@ -238,7 +240,7 @@ module ReVIEW
238
240
 
239
241
  def update_version
240
242
  @config_ymls.each do |yml|
241
- config = YAML.load_file(yml)
243
+ config = YAMLLoader.safe_load_file(yml)
242
244
  if config['review_version'].to_f.round(1) == TARGET_VERSION.to_f.round(1)
243
245
  next
244
246
  end
@@ -265,10 +267,12 @@ module ReVIEW
265
267
  target_rakefile = File.join(dir, 'Rakefile')
266
268
  if File.exist?(target_rakefile)
267
269
  if Digest::SHA256.hexdigest(File.read(target_rakefile)) != Digest::SHA256.hexdigest(File.read(master_rakefile))
270
+ # rubocop:disable Style/SoleNestedConditional
268
271
  if confirm('%s will be overridden with Re:VIEW version (%s). Do you really proceed?', ['Rakefile', master_rakefile])
269
272
  FileUtils.mv(target_rakefile, "#{target_rakefile}-old")
270
273
  FileUtils.cp(master_rakefile, target_rakefile)
271
274
  end
275
+ # rubocop:enable Style/SoleNestedConditional
272
276
  end
273
277
  else
274
278
  @logger.info t('new file %s is created.', [target_rakefile]) unless @force
@@ -278,12 +282,14 @@ module ReVIEW
278
282
  master_rakefile = File.join(@review_dir, 'samples/sample-book/src/lib/tasks/review.rake')
279
283
  target_rakefile = File.join(taskdir, 'review.rake')
280
284
  if File.exist?(target_rakefile)
285
+ # rubocop:disable Style/SoleNestedConditional
281
286
  if Digest::SHA256.hexdigest(File.read(target_rakefile)) != Digest::SHA256.hexdigest(File.read(master_rakefile))
282
287
  if confirm('%s will be overridden with Re:VIEW version (%s). Do you really proceed?', ['lib/tasks/review.rake', master_rakefile])
283
288
  FileUtils.mv(target_rakefile, "#{target_rakefile}-old")
284
289
  FileUtils.cp(master_rakefile, target_rakefile)
285
290
  end
286
291
  end
292
+ # rubocop:enable Style/SoleNestedConditional
287
293
  else
288
294
  @logger.info t('new file %s is created.', [target_rakefile]) unless @force
289
295
  FileUtils.cp(master_rakefile, target_rakefile)
@@ -292,11 +298,13 @@ module ReVIEW
292
298
 
293
299
  def update_epub_version
294
300
  @epub_ymls.each do |yml|
295
- config = YAML.load_file(yml)
301
+ config = YAMLLoader.safe_load_file(yml)
296
302
  if config['epubversion'].present? && config['epubversion'].to_f < EPUB_VERSION.to_f
303
+ # rubocop:disable Style/SoleNestedConditional
297
304
  if confirm("%s: Update '%s' to '%s' from '%s'?", [File.basename(yml), 'epubversion', EPUB_VERSION, config['epubversion']])
298
305
  rewrite_yml(yml, 'epubversion', EPUB_VERSION)
299
306
  end
307
+ # rubocop:enable Style/SoleNestedConditional
300
308
  end
301
309
  if !config['htmlversion'].present? || config['htmlversion'].to_f >= HTML_VERSION.to_f
302
310
  next
@@ -310,7 +318,7 @@ module ReVIEW
310
318
 
311
319
  def update_locale
312
320
  @locale_ymls.each do |yml|
313
- config = YAML.load_file(yml)
321
+ config = YAMLLoader.safe_load_file(yml)
314
322
  if !config['chapter_quote'].present? || config['chapter_quote'].scan('%s').size != 1
315
323
  next
316
324
  end
@@ -324,7 +332,7 @@ module ReVIEW
324
332
 
325
333
  def update_tex_parameters
326
334
  @tex_ymls.each do |yml|
327
- config = YAML.load_file(yml)
335
+ config = YAMLLoader.safe_load_file(yml)
328
336
  unless config['texdocumentclass']
329
337
  next
330
338
  end
@@ -510,7 +518,7 @@ module ReVIEW
510
518
 
511
519
  def update_tex_command
512
520
  @tex_ymls.each do |yml|
513
- config = YAML.load_file(yml)
521
+ config = YAMLLoader.safe_load_file(yml)
514
522
  if !config['texcommand'] || config['texcommand'] !~ /\s+-/
515
523
  next
516
524
  end
@@ -535,7 +543,7 @@ module ReVIEW
535
543
 
536
544
  def update_dvi_command
537
545
  @tex_ymls.each do |yml|
538
- config = YAML.load_file(yml)
546
+ config = YAMLLoader.safe_load_file(yml)
539
547
  if !config['dvicommand'] || config['dvicommand'] !~ /\s+-/
540
548
  next
541
549
  end
@@ -1,3 +1,3 @@
1
1
  module ReVIEW
2
- VERSION = '5.3.0'.freeze
2
+ VERSION = '5.4.0'.freeze
3
3
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2021 Masayoshi Takahashi, Masanori Kado, Kenshi Muto
1
+ # Copyright (c) 2016-2022 Masayoshi Takahashi, Masanori Kado, Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -78,9 +78,13 @@ module ReVIEW
78
78
  cmd_config, yamlfile = parse_opts(args)
79
79
  error! "#{yamlfile} not found." unless File.exist?(yamlfile)
80
80
 
81
- @config = ReVIEW::Configure.create(maker: 'webmaker',
82
- yamlfile: yamlfile,
83
- config: cmd_config)
81
+ begin
82
+ @config = ReVIEW::Configure.create(maker: 'webmaker',
83
+ yamlfile: yamlfile,
84
+ config: cmd_config)
85
+ rescue ReVIEW::ConfigError => e
86
+ error! e.message
87
+ end
84
88
 
85
89
  @config['htmlext'] = 'html'
86
90
  @img_math = ReVIEW::ImgMath.new(@config)
@@ -97,7 +101,7 @@ module ReVIEW
97
101
  end
98
102
 
99
103
  def generate_html_files(yamlfile)
100
- @basedir = File.dirname(yamlfile)
104
+ @basedir = File.absolute_path(File.dirname(yamlfile))
101
105
  @path = build_path
102
106
  remove_old_files(@path)
103
107
  Dir.mkdir(@path)
@@ -146,19 +150,27 @@ module ReVIEW
146
150
  def build_part(part, basetmpdir, htmlfile)
147
151
  @title = h("#{ReVIEW::I18n.t('part', part.number)} #{part.name.strip}")
148
152
  File.open("#{basetmpdir}/#{htmlfile}", 'w') do |f|
149
- @body = ''
150
- @body << %Q(<div class="part">\n)
151
- @body << %Q(<h1 class="part-number">#{ReVIEW::I18n.t('part', part.number)}</h1>\n)
152
- @body << %Q(<h2 class="part-title">#{part.name.strip}</h2>\n) if part.name.strip.present?
153
- @body << "</div>\n"
154
-
153
+ @part_number = part.number
154
+ @part_title = part.name.strip
155
+ @body = ReVIEW::Template.generate(path: template_name(localfile: '_part_body.html.erb', systemfile: 'html/_part_body.html.erb'), binding: binding)
155
156
  @language = @config['language']
156
157
  @stylesheets = @config['stylesheet']
157
158
  f.write ReVIEW::Template.generate(path: template_name, binding: binding)
158
159
  end
159
160
  end
160
161
 
161
- def template_name
162
+ def template_name(localfile: 'layout-web.html.erb', systemfile: nil)
163
+ if @basedir
164
+ layoutfile = File.join(@basedir, 'layouts', localfile)
165
+ if File.exist?(layoutfile)
166
+ return layoutfile
167
+ end
168
+ end
169
+
170
+ if systemfile
171
+ return systemfile
172
+ end
173
+
162
174
  if @config['htmlversion'].to_i == 5
163
175
  'web/html/layout-html5.html.erb'
164
176
  else
@@ -167,13 +179,11 @@ module ReVIEW
167
179
  end
168
180
 
169
181
  def build_chap(chap, base_path, basetmpdir, ispart)
170
- filename = ''
171
-
172
- if ispart.present?
173
- filename = chap.path
174
- else
175
- filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
176
- end
182
+ filename = if ispart.present?
183
+ chap.path
184
+ else
185
+ Pathname.new(chap.path).relative_path_from(base_path).to_s
186
+ end
177
187
  id = File.basename(filename).sub(/\.re\Z/, '')
178
188
 
179
189
  if @buildonly && !@buildonly.include?(id)
@@ -219,7 +229,7 @@ module ReVIEW
219
229
 
220
230
  if FileTest.directory?("#{resdir}/#{fname}")
221
231
  recursive_copy_files("#{resdir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
222
- elsif fname =~ /\.(#{allow_exts.join('|')})\Z/i
232
+ elsif /\.(#{allow_exts.join('|')})\Z/i.match?(fname)
223
233
  FileUtils.mkdir_p(destdir)
224
234
  FileUtils.cp("#{resdir}/#{fname}", destdir)
225
235
  end
@@ -274,18 +284,8 @@ module ReVIEW
274
284
 
275
285
  def build_titlepage(basetmpdir, htmlfile)
276
286
  @title = h('titlepage')
277
- File.open("#{basetmpdir}/#{htmlfile}", 'w') do |f|
278
- @body = ''
279
- @body << %Q(<div class="titlepage">)
280
- @body << %Q(<h1 class="tp-title">#{h(@config.name_of('booktitle'))}</h1>)
281
- if @config['aut']
282
- @body << %Q(<h2 class="tp-author">#{join_with_separator(@config.names_of('aut'), ReVIEW::I18n.t('names_splitter'))}</h2>)
283
- end
284
- if @config['pbl']
285
- @body << %Q(<h3 class="tp-publisher">#{join_with_separator(@config.names_of('pbl'), ReVIEW::I18n.t('names_splitter'))}</h3>)
286
- end
287
- @body << '</div>'
288
-
287
+ File.open(File.join(basetmpdir, htmlfile), 'w') do |f|
288
+ @body = ReVIEW::Template.generate(path: template_name(localfile: '_titlepage.html.erb', systemfile: 'html/_titlepage.html.erb'), binding: binding)
289
289
  @language = @config['language']
290
290
  @stylesheets = @config['stylesheet']
291
291
  f.write ReVIEW::Template.generate(path: template_name, binding: binding)
@@ -41,16 +41,16 @@ EOT
41
41
  next
42
42
  end
43
43
 
44
- if path.start_with?('.')
45
- content << "<li>#{escape(result.headline)}"
46
- else
47
- content << %Q(<li><a href="#{path}">#{escape(result.headline)}</a>)
48
- end
49
- if result.level == 0
50
- content << "\n<ul>" # part
51
- else
52
- content << "</li>\n"
53
- end
44
+ content << if path.start_with?('.')
45
+ "<li>#{escape(result.headline)}"
46
+ else
47
+ %Q(<li><a href="#{path}">#{escape(result.headline)}</a>)
48
+ end
49
+ content << if result.level == 0
50
+ "\n<ul>" # part
51
+ else
52
+ "</li>\n"
53
+ end
54
54
  end
55
55
  content << "</ul>\n"
56
56
  end
@@ -2,6 +2,39 @@ require 'yaml'
2
2
 
3
3
  module ReVIEW
4
4
  class YAMLLoader
5
+ def self.safe_load_file(file)
6
+ if YAML.respond_to?(:safe_load_file)
7
+ YAML.safe_load_file(file, aliases: true, permitted_classes: [Date])
8
+ else
9
+ File.open(file, 'rt:bom|utf-8') do |f|
10
+ begin
11
+ # < Ruby 3.1
12
+ YAML.safe_load(f, filename: file, aliases: true, permitted_classes: [Date])
13
+ rescue ArgumentError
14
+ # < Ruby 2.7
15
+ YAML.safe_load(f, [Date])
16
+ rescue Psych::DisallowedClass
17
+ # < Ruby 2.5
18
+ YAML.safe_load(File.read(file), [Date])
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.safe_load(s)
25
+ if YAML.respond_to?(:safe_load_file)
26
+ YAML.safe_load(s, aliases: true, permitted_classes: [Date])
27
+ else
28
+ begin
29
+ # < Ruby 3.1
30
+ YAML.safe_load(s, aliases: true, permitted_classes: [Date])
31
+ rescue ArgumentError, Psych::DisallowedClass
32
+ # < Ruby 2.7
33
+ YAML.safe_load(s, [Date])
34
+ end
35
+ end
36
+ end
37
+
5
38
  def initialize
6
39
  end
7
40
 
@@ -17,8 +50,8 @@ module ReVIEW
17
50
 
18
51
  while file_queue.present?
19
52
  current_file = file_queue.shift
20
- current_yaml = YAML.load_file(current_file)
21
- if current_yaml.instance_of?(FalseClass)
53
+ current_yaml = YAMLLoader.safe_load_file(current_file)
54
+ if current_yaml.instance_of?(FalseClass) || current_yaml.nil?
22
55
  raise "#{File.basename(current_file)} is malformed."
23
56
  end
24
57
 
data/review.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.summary = 'Re:VIEW: a easy-to-use digital publishing system'
13
13
  gem.description = 'Re:VIEW is a digital publishing system for books and ebooks. It supports InDesign, EPUB and LaTeX.'
14
14
  gem.required_rubygems_version = Gem::Requirement.new('>= 0') if gem.respond_to?(:required_rubygems_version=)
15
+ gem.metadata = { 'rubygems_mfa_required' => 'true' }
15
16
 
16
17
  gem.files = `git ls-files`.split("\n")
17
18
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -3,7 +3,6 @@ review_version: 5.0
3
3
  bookname: book
4
4
  language: ja
5
5
  booktitle: Re:VIEWサンプル書籍
6
- urnid: urn:uuid:http://reviewml.com/books/review-sample-book/
7
6
  # isbn: null
8
7
  aut: Re:VIEW Writers
9
8
  pbl: Re:VIEW Publishers
@@ -1,20 +1,12 @@
1
- <h1 class="tp-title"><%= @title_str %></h1>
2
- <% if @subtitle_str %>
3
- <h2 class="tp-subtitle"><%= h(@subtitle_str) %></h2>
1
+ <div class="titlepage">
2
+ <h1 class="tp-title"><%= h(@config.name_of('booktitle')) %></h1>
3
+ <% if @config['subtitle'] %>
4
+ <h2 class="tp-subtitle"><%= h(@config.name_of('subtitle')) %></h2>
4
5
  <% end %>
5
- <% if @author_str %>
6
- <p>
7
- <br />
8
- <br />
9
- </p>
10
- <h2 class="tp-author"><%= h(@author_str) %></h2>
6
+ <% if @config['aut'] %>
7
+ <h2 class="tp-author"><%= h(@config.names_of('aut').join(ReVIEW::I18n.t('names_splitter'))) %></h2>
11
8
  <% end %>
12
- <% if @publisher_str %>
13
- <p>
14
- <br />
15
- <br />
16
- <br />
17
- <br />
18
- </p>
19
- <h3 class="tp-publisher"><%= h(@publisher_str) %></h3>
9
+ <% if @config['pbl'] %>
10
+ <h3 class="tp-publisher"><%= h(@config.names_of('pbl').join(ReVIEW::I18n.t('names_splitter'))) %></h3>
20
11
  <% end %>
12
+ </div>
@@ -4,7 +4,7 @@
4
4
  <% if @config['toc'] && @config['mytoc'] %>
5
5
  <item id="toc" href="<%= @config['bookname'] %>-toc.<%= @config['htmlext'] %>" media-type="application/xhtml+xml"/>
6
6
  <% end %>
7
- <% @items.each do |item| %>
7
+ <% @items.sort_by { |x| x.id }.each do |item| %>
8
8
  <item id="<%= item.id %>" href="<%= item.file %>" media-type="<%= item.media %>"/>
9
9
  <% end %>
10
10
  </manifest>
@@ -4,7 +4,7 @@
4
4
  <% if @coverimage %>
5
5
  <item properties="cover-image" id="cover-<%= @coverimage.id %>" href="<%= @coverimage.file %>" media-type="<%= @coverimage.media %>"/>
6
6
  <% end %>
7
- <% @items.each do |item| %>
7
+ <% @items.sort_by { |x| x.id }.each do |item| %>
8
8
  <item id="<%= item.id %>" href="<%= item.file %>" media-type="<%= item.media %>"<%= item.properties_attribute %>/>
9
9
  <% end %>
10
10
  </manifest>
@@ -20,11 +20,11 @@ module BookTestHelper
20
20
  created_files[filename] = path
21
21
  end
22
22
  conf_path = File.expand_path('config.yml', dir)
23
- if File.exist?(conf_path)
24
- config = ReVIEW::Configure.create(yamlfile: conf_path)
25
- else
26
- config = ReVIEW::Configure.values
27
- end
23
+ config = if File.exist?(conf_path)
24
+ ReVIEW::Configure.create(yamlfile: conf_path)
25
+ else
26
+ ReVIEW::Configure.values
27
+ end
28
28
  book = Book::Base.new(dir, config: config)
29
29
  yield(dir, book, created_files)
30
30
  end
@@ -34,11 +34,11 @@ module BookTestHelper
34
34
  def get_instance_variables(obj)
35
35
  obj.instance_variables.each_with_object({}) do |name, memo|
36
36
  value = obj.instance_variable_get(name)
37
- if value.instance_variables.empty?
38
- memo[name] = value
39
- else
40
- memo[name] = get_instance_variables(value)
41
- end
37
+ memo[name] = if value.instance_variables.empty?
38
+ value
39
+ else
40
+ get_instance_variables(value)
41
+ end
42
42
  end
43
43
  end
44
44
  end