review 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +31 -0
  3. data/.github/workflows/ruby-win.yml +3 -3
  4. data/.github/workflows/ruby.yml +1 -1
  5. data/.rubocop.yml +15 -7
  6. data/NEWS.ja.md +108 -0
  7. data/NEWS.md +108 -0
  8. data/README.md +7 -6
  9. data/Rakefile +7 -2
  10. data/bin/review +2 -4
  11. data/bin/review-catalog-converter +3 -3
  12. data/bin/review-check +6 -8
  13. data/bin/review-checkdep +1 -4
  14. data/bin/review-compile +2 -5
  15. data/bin/review-epub2html +1 -4
  16. data/bin/review-epubmaker +3 -4
  17. data/bin/review-idgxmlmaker +1 -3
  18. data/bin/review-index +11 -5
  19. data/bin/review-init +1 -4
  20. data/bin/review-pdfmaker +1 -3
  21. data/bin/review-preproc +2 -4
  22. data/bin/review-textmaker +1 -3
  23. data/bin/review-update +1 -4
  24. data/bin/review-validate +3 -3
  25. data/bin/review-vol +1 -4
  26. data/bin/review-webmaker +1 -3
  27. data/doc/config.yml.sample +21 -5
  28. data/doc/config.yml.sample-simple +1 -1
  29. data/doc/format.ja.md +21 -10
  30. data/doc/format.md +21 -10
  31. data/doc/quickstart.ja.md +11 -1
  32. data/doc/quickstart.md +11 -2
  33. data/lib/review.rb +1 -1
  34. data/lib/review/book/base.rb +4 -0
  35. data/lib/review/book/book_unit.rb +3 -0
  36. data/lib/review/book/chapter.rb +3 -0
  37. data/lib/review/book/index.rb +1 -0
  38. data/lib/review/book/volume.rb +1 -0
  39. data/lib/review/builder.rb +8 -1
  40. data/lib/review/call_hook.rb +20 -0
  41. data/lib/review/catalog.rb +1 -0
  42. data/lib/review/compiler.rb +27 -10
  43. data/lib/review/configure.rb +64 -7
  44. data/lib/review/epubmaker.rb +93 -96
  45. data/lib/review/epubmaker/content.rb +113 -0
  46. data/lib/review/epubmaker/epubcommon.rb +372 -0
  47. data/lib/review/epubmaker/epubv2.rb +178 -0
  48. data/lib/review/epubmaker/epubv3.rb +231 -0
  49. data/lib/review/epubmaker/producer.rb +168 -0
  50. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  51. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  52. data/lib/review/exception.rb +6 -0
  53. data/lib/review/htmlbuilder.rb +36 -49
  54. data/lib/review/htmlutils.rb +1 -1
  55. data/lib/review/i18n.rb +1 -0
  56. data/lib/review/idgxmlbuilder.rb +33 -30
  57. data/lib/review/idgxmlmaker.rb +3 -1
  58. data/lib/review/img_math.rb +245 -0
  59. data/lib/review/index_builder.rb +1 -0
  60. data/lib/review/init.rb +4 -4
  61. data/lib/review/latexbox.rb +58 -0
  62. data/lib/review/latexbuilder.rb +30 -19
  63. data/lib/review/latexutils.rb +9 -1
  64. data/lib/review/lineinput.rb +112 -2
  65. data/lib/review/logger.rb +41 -2
  66. data/lib/review/makerhelper.rb +2 -205
  67. data/lib/review/markdownbuilder.rb +32 -1
  68. data/lib/review/pdfmaker.rb +31 -29
  69. data/lib/review/plaintextbuilder.rb +9 -1
  70. data/lib/review/preprocessor.rb +12 -6
  71. data/lib/review/rstbuilder.rb +1 -1
  72. data/lib/review/sec_counter.rb +1 -0
  73. data/lib/review/template.rb +6 -0
  74. data/lib/review/textmaker.rb +11 -7
  75. data/lib/review/textutils.rb +2 -10
  76. data/lib/review/tocprinter.rb +85 -68
  77. data/lib/review/topbuilder.rb +18 -11
  78. data/lib/review/update.rb +5 -6
  79. data/lib/review/version.rb +1 -1
  80. data/lib/review/volumeprinter.rb +4 -5
  81. data/lib/review/webmaker.rb +18 -13
  82. data/lib/review/webtocprinter.rb +10 -9
  83. data/lib/review/yamlloader.rb +2 -1
  84. data/review.gemspec +5 -3
  85. data/samples/sample-book/src/config-epub2.yml +1 -1
  86. data/samples/sample-book/src/config.yml +1 -1
  87. data/samples/sample-book/src/lib/tasks/review.rake +17 -1
  88. data/samples/syntax-book/ch01.re +1 -1
  89. data/samples/syntax-book/ch02.re +21 -6
  90. data/samples/syntax-book/ch03.re +1 -1
  91. data/samples/syntax-book/images/img3-2.png +0 -0
  92. data/templates/html/_colophon.html.erb +23 -0
  93. data/templates/html/_colophon_history.html.erb +9 -0
  94. data/templates/html/_cover.html.erb +10 -0
  95. data/templates/html/_part_body.html.erb +6 -0
  96. data/templates/html/_titlepage.html.erb +20 -0
  97. data/templates/html/layout-html5.html.erb +6 -0
  98. data/templates/html/layout-xhtml1.html.erb +6 -0
  99. data/templates/latex/config.erb +8 -0
  100. data/templates/latex/review-jlreq/review-base.sty +4 -5
  101. data/templates/latex/review-jlreq/review-jlreq.cls +10 -2
  102. data/templates/latex/review-jlreq/review-style.sty +6 -1
  103. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  104. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  105. data/templates/latex/review-jsbook/review-base.sty +5 -7
  106. data/templates/latex/review-jsbook/review-jsbook.cls +10 -2
  107. data/templates/latex/review-jsbook/review-style.sty +6 -1
  108. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  109. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  110. data/templates/opf/epubv2.opf.erb +7 -7
  111. data/templates/opf/epubv3.opf.erb +7 -7
  112. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  113. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  114. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  115. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  116. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  117. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  118. data/templates/web/html/layout-html5.html.erb +6 -5
  119. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  120. data/test/assets/header_listener.html +35 -0
  121. data/test/assets/img_math/img1.png +0 -0
  122. data/test/assets/img_math/img2.png +0 -0
  123. data/test/assets/img_math/img3.png +0 -0
  124. data/test/assets/syntax_book_index_detail.txt +58 -0
  125. data/test/assets/test_template.tex +4 -1
  126. data/test/assets/test_template_backmatter.tex +4 -1
  127. data/test/run_test.rb +1 -1
  128. data/test/test_book_chapter.rb +2 -2
  129. data/test/test_catalog_converter_cmd.rb +1 -1
  130. data/test/test_epub3maker.rb +168 -124
  131. data/test/test_epubmaker.rb +243 -131
  132. data/test/test_epubmaker_cmd.rb +2 -2
  133. data/test/test_helper.rb +5 -4
  134. data/test/test_htmlbuilder.rb +64 -6
  135. data/test/test_idgxmlbuilder.rb +13 -0
  136. data/test/test_idgxmlmaker_cmd.rb +7 -3
  137. data/test/test_img_math.rb +111 -0
  138. data/test/test_indexbuilder.rb +5 -5
  139. data/test/test_latexbuilder.rb +107 -4
  140. data/test/test_lineinput.rb +20 -93
  141. data/test/test_markdownbuilder.rb +29 -0
  142. data/test/test_pdfmaker.rb +71 -0
  143. data/test/test_pdfmaker_cmd.rb +2 -2
  144. data/test/test_plaintextbuilder.rb +10 -18
  145. data/test/test_reviewheaderlistener.rb +49 -0
  146. data/test/test_template.rb +12 -2
  147. data/test/test_textmaker_cmd.rb +5 -1
  148. data/test/test_tocprinter.rb +46 -0
  149. data/test/test_topbuilder.rb +6 -1
  150. data/test/test_update.rb +34 -34
  151. data/test/test_zip_exporter.rb +5 -6
  152. metadata +91 -17
  153. data/lib/epubmaker.rb +0 -23
  154. data/lib/epubmaker/content.rb +0 -111
  155. data/lib/epubmaker/epubcommon.rb +0 -449
  156. data/lib/epubmaker/epubv2.rb +0 -142
  157. data/lib/epubmaker/epubv3.rb +0 -235
  158. data/lib/epubmaker/producer.rb +0 -375
  159. data/lib/epubmaker/zip_exporter.rb +0 -81
  160. data/lib/lineinput.rb +0 -155
@@ -137,7 +137,7 @@ module ReVIEW
137
137
 
138
138
  def dd(lines)
139
139
  split_paragraph(lines).each do |paragraph|
140
- puts paragraph.gsub(/\n/, '')
140
+ puts paragraph.delete("\n")
141
141
  end
142
142
  end
143
143
 
@@ -647,10 +647,18 @@ module ReVIEW
647
647
  ''
648
648
  end
649
649
 
650
+ def inline_ins(str)
651
+ str
652
+ end
653
+
650
654
  def inline_del(_str)
651
655
  ''
652
656
  end
653
657
 
658
+ def inline_tcy(str)
659
+ str
660
+ end
661
+
654
662
  def inline_br(_str)
655
663
  "\n"
656
664
  end
@@ -115,7 +115,7 @@ module ReVIEW
115
115
 
116
116
  when /\A\s*\z/ # empty line
117
117
  @f.puts
118
- else
118
+ else # rubocop:disable Lint/DuplicateBranch
119
119
  @f.print line
120
120
  end
121
121
  end
@@ -196,6 +196,7 @@ module ReVIEW
196
196
  args = m[2].split(/,\s*/)
197
197
  opts = parse_optargs(m[3])
198
198
  return if (argc == 0) && args.empty?
199
+
199
200
  if argc == -1
200
201
  # Any number of arguments are allowed.
201
202
  elsif args.size != argc
@@ -212,6 +213,7 @@ module ReVIEW
212
213
 
213
214
  def parse_optargs(str)
214
215
  return nil unless str
216
+
215
217
  table = {}
216
218
  str.split(/,\s*/).each do |a|
217
219
  name, spec = a.split('=', 2)
@@ -222,11 +224,14 @@ module ReVIEW
222
224
 
223
225
  def optarg_value(spec)
224
226
  case spec
225
- when 'true' then true # [name=true]
226
- when 'false' then false # [name=false]
227
- when 'nil' then nil # [name=nil]
228
- when nil then true # [name]
229
- when /^\d+$/ then $&.to_i # [name=8]
227
+ when 'true' # [name=true], [name]
228
+ true
229
+ when 'false' # [name=false]
230
+ false
231
+ when 'nil' # [name=nil]
232
+ nil
233
+ when /^\d+$/ # [name=8]
234
+ $&.to_i
230
235
  else # [name=val]
231
236
  spec
232
237
  end
@@ -427,6 +432,7 @@ module ReVIEW
427
432
 
428
433
  else
429
434
  next if yacchack && (line.strip == ';')
435
+
430
436
  line = canonical(line)
431
437
  curr.each_value { |list| list.push(Line.new(lineno, line)) }
432
438
  lineno += 1
@@ -155,7 +155,7 @@ module ReVIEW
155
155
 
156
156
  def dd(lines)
157
157
  split_paragraph(lines).each do |paragraph|
158
- puts " #{paragraph.gsub(/\n/, '')}"
158
+ puts " #{paragraph.delete("\n")}"
159
159
  end
160
160
  end
161
161
 
@@ -55,6 +55,7 @@ module ReVIEW
55
55
 
56
56
  if level == 1
57
57
  return nil unless secnolevel >= 1
58
+
58
59
  if @chapter.is_a?(ReVIEW::Book::Part)
59
60
  num = @chapter.number
60
61
  "#{I18n.t('part', num)}#{I18n.t('chapter_postfix')}"
@@ -10,8 +10,14 @@ module ReVIEW
10
10
  self.new(filename, mode)
11
11
  end
12
12
 
13
+ def self.generate(path:, binding:, mode: 1, template_dir: ReVIEW::Template::TEMPLATE_DIR)
14
+ template_file = File.expand_path(path, template_dir)
15
+ self.new(template_file, mode).result(binding)
16
+ end
17
+
13
18
  def initialize(filename = nil, mode = nil)
14
19
  return unless filename
20
+
15
21
  content = File.read(filename)
16
22
  @erb = ERB.new(content, nil, mode)
17
23
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2020 Kenshi Muto
1
+ # Copyright (c) 2018-2021 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -16,6 +16,7 @@ require 'review/yamlloader'
16
16
  require 'review/topbuilder'
17
17
  require 'review/version'
18
18
  require 'review/makerhelper'
19
+ require 'review/img_math'
19
20
 
20
21
  module ReVIEW
21
22
  class TEXTMaker
@@ -27,6 +28,7 @@ module ReVIEW
27
28
  @basedir = nil
28
29
  @logger = ReVIEW.logger
29
30
  @plaintext = nil
31
+ @img_math = nil
30
32
  end
31
33
 
32
34
  def error(msg)
@@ -70,7 +72,7 @@ module ReVIEW
70
72
  end
71
73
 
72
74
  def remove_old_files(path)
73
- cleanup_mathimg('_review_math_text')
75
+ @img_math.cleanup_mathimg
74
76
  FileUtils.rm_rf(path)
75
77
  end
76
78
 
@@ -81,18 +83,20 @@ module ReVIEW
81
83
  @config = ReVIEW::Configure.create(maker: 'textmaker',
82
84
  yamlfile: yamlfile,
83
85
  config: cmd_config)
86
+ @img_math = ReVIEW::ImgMath.new(@config, path_name: '_review_math_text')
84
87
 
85
88
  I18n.setup(@config['language'])
86
89
  begin
87
90
  generate_text_files(yamlfile)
91
+ @logger.success("built #{build_path}")
88
92
  rescue ApplicationError => e
89
93
  raise if @config['debug']
94
+
90
95
  error(e.message)
91
96
  end
92
97
 
93
- math_dir = "./#{@config['imagedir']}/_review_math_text"
94
- if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.map'))
95
- make_math_images(math_dir)
98
+ if @config['math_format'] == 'imgmath'
99
+ @img_math.make_math_images
96
100
  end
97
101
  end
98
102
 
@@ -111,9 +115,9 @@ module ReVIEW
111
115
  base_path = Pathname.new(@basedir)
112
116
  builder = nil
113
117
  if @plaintext
114
- builder = ReVIEW::PLAINTEXTBuilder.new
118
+ builder = ReVIEW::PLAINTEXTBuilder.new(img_math: @img_math)
115
119
  else
116
- builder = ReVIEW::TOPBuilder.new
120
+ builder = ReVIEW::TOPBuilder.new(img_math: @img_math)
117
121
  end
118
122
  @converter = ReVIEW::Converter.new(@book, builder)
119
123
  @book.parts.each do |part|
@@ -51,6 +51,7 @@ module ReVIEW
51
51
  if tail.nil? || head.nil?
52
52
  return nil
53
53
  end
54
+
54
55
  space = true
55
56
  # rule 2
56
57
  if %i[F W H].include?(Unicode::Eaw.property(tail)) &&
@@ -86,6 +87,7 @@ module ReVIEW
86
87
  unless @book.config['join_lines_by_lang']
87
88
  return lines.join
88
89
  end
90
+
89
91
  lazy = true
90
92
  lang = 'ja'
91
93
  0.upto(lines.size - 2) do |n|
@@ -96,16 +98,6 @@ module ReVIEW
96
98
  lines.join
97
99
  end
98
100
 
99
- def defer_math_image(str, path, key)
100
- # for Re:VIEW >3
101
- File.open(File.join(File.dirname(path), "__IMGMATH_BODY__#{key}.tex"), 'w') do |f|
102
- f.puts str
103
- end
104
- File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.map'), 'a+') do |f|
105
- f.puts key
106
- end
107
- end
108
-
109
101
  private
110
102
 
111
103
  # remove elements at the back of `lines` if element is empty string
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2008-2021 Minero Aoki, Kenshi Muto
2
2
  # 1999-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -36,34 +36,45 @@ module ReVIEW
36
36
  end
37
37
 
38
38
  class TOCPrinter
39
- def self.execute(*args)
40
- Signal.trap(:INT) { exit 1 }
41
- if RUBY_PLATFORM !~ /mswin(?!ce)|mingw|cygwin|bccwin/
42
- Signal.trap(:PIPE, 'IGNORE')
39
+ class Counter
40
+ def initialize(name: nil, level: nil, headline: nil, lines: nil, chars: nil, list_lines: nil, text_lines: nil, part: nil)
41
+ @name = name
42
+ @level = level
43
+ @headline = headline
44
+ @lines = lines
45
+ @chars = chars
46
+ @list_lines = list_lines
47
+ @text_lines = text_lines
48
+ @part = part
43
49
  end
50
+
51
+ attr_accessor :name, :level, :headline, :lines, :chars, :list_lines, :text_lines, :part
52
+ end
53
+
54
+ def self.execute(*args)
44
55
  new.execute(*args)
45
- rescue Errno::EPIPE
46
- exit 0
47
56
  end
48
57
 
49
58
  def initialize
50
59
  @logger = ReVIEW.logger
51
- @config = ReVIEW::Configure.values
52
60
  @yamlfile = 'config.yml'
53
- @book = ReVIEW::Book::Base.new('.', config: @config)
54
61
  @upper = 4
55
62
  @indent = true
56
63
  @buildonly = nil
57
64
  @detail = nil
65
+ @calc_char_width = nil
58
66
  end
59
67
 
68
+ attr_accessor :calc_char_width
69
+
60
70
  def execute(*args)
61
71
  parse_options(args)
72
+ @config = ReVIEW::Configure.create(yamlfile: @yamlfile)
73
+ @book = ReVIEW::Book::Base.new('.', config: @config)
62
74
  unless File.readable?(@yamlfile)
63
75
  @logger.error("No such fiile or can't open #{@yamlfile}.")
64
76
  exit 1
65
77
  end
66
- @book.load_config(@yamlfile)
67
78
  I18n.setup(@config['language'])
68
79
 
69
80
  if @detail
@@ -84,27 +95,27 @@ module ReVIEW
84
95
  begin
85
96
  @book.parts.each do |part|
86
97
  if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
87
- result_array.push({ part: 'start' })
98
+ result_array.push(Counter.new(part: 'start'))
88
99
  if part.file?
89
- result = build_chap(part)
90
- result_array += parse_contents(part.name, @upper, result)
100
+ content = build_chap(part)
101
+ result_array.concat(parse_contents(part.name, @upper, content))
91
102
  else
92
103
  title = part.format_number + I18n.t('chapter_postfix') + part.title
93
- result_array += [
94
- { name: '', lines: 1, chars: title.size, list_lines: 0, text_lines: 1 },
95
- { level: 0, headline: title, lines: 1, chars: title.size, list_lines: 0, text_lines: 1 }
96
- ]
104
+ result_array.push(
105
+ Counter.new(name: '', lines: 1, chars: title.size, list_lines: 0, text_lines: 1),
106
+ Counter.new(level: 0, headline: title, lines: 1, chars: title.size, list_lines: 0, text_lines: 1)
107
+ )
97
108
  end
98
109
  end
99
110
 
100
111
  part.chapters.each do |chap|
101
112
  if @buildonly.nil? || @buildonly.include?(chap.name)
102
- result = build_chap(chap)
103
- result_array += parse_contents(chap.name, @upper, result)
113
+ content = build_chap(chap)
114
+ result_array.concat(parse_contents(chap.name, @upper, content))
104
115
  end
105
116
  end
106
117
  if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
107
- result_array.push({ part: 'end' })
118
+ result_array.push(Counter.new(part: 'end'))
108
119
  end
109
120
  end
110
121
  rescue ReVIEW::FileNotFound, ReVIEW::CompileError => e
@@ -117,15 +128,15 @@ module ReVIEW
117
128
 
118
129
  def print_result(result_array)
119
130
  result_array.each do |result|
120
- if result[:part]
131
+ if result.part
121
132
  next
122
133
  end
123
134
 
124
- if result[:name]
135
+ if result.name
125
136
  # file information
126
137
  if @detail
127
138
  puts '============================='
128
- printf("%6dC %5dL %5dP %s\n", result[:chars], result[:lines], calc_pages(result).ceil, result[:name])
139
+ printf("%6dC %5dL %5dP %s\n", result.chars, result.lines, calc_pages(result).ceil, result.name)
129
140
  puts '-----------------------------'
130
141
  end
131
142
  next
@@ -133,42 +144,39 @@ module ReVIEW
133
144
 
134
145
  # section information
135
146
  if @detail
136
- printf('%6dC %5dL %5.1fP ', result[:chars], result[:lines], calc_pages(result))
147
+ printf('%6dC %5dL %5.1fP ', result.chars, result.lines, calc_pages(result))
137
148
  end
138
- if @indent && result[:level]
139
- print ' ' * (result[:level] == 0 ? 0 : result[:level] - 1)
149
+ if @indent && result.level
150
+ print ' ' * (result.level == 0 ? 0 : result.level - 1)
140
151
  end
141
- puts result[:headline]
152
+ puts result.headline
142
153
  end
143
154
  end
144
155
 
145
156
  def calc_pages(result)
146
- p = 0
147
- p += result[:list_lines].to_f / @book.page_metric.list.n_lines
148
- p += result[:text_lines].to_f / @book.page_metric.text.n_lines
149
- p
157
+ (result.list_lines.to_f / @book.page_metric.list.n_lines) +
158
+ (result.text_lines.to_f / @book.page_metric.text.n_lines)
150
159
  end
151
160
 
152
- def calc_linesize(l)
153
- return l.size unless @calc_char_width
154
- w = 0
155
- l.split('').each do |c|
161
+ def calc_linesize(line)
162
+ return line.size unless @calc_char_width
163
+
164
+ line.each_char.inject(0) do |result, char|
156
165
  # XXX: should include A also?
157
- if %i[Na H N].include?(Unicode::Eaw.property(c))
158
- w += 0.5 # halfwidth
166
+ if %i[Na H N].include?(Unicode::Eaw.property(char))
167
+ result + 0.5 # halfwidth
159
168
  else
160
- w += 1
169
+ result + 1
161
170
  end
162
171
  end
163
- w
164
172
  end
165
173
 
166
174
  def parse_contents(name, upper, content)
167
175
  headline_array = []
168
- counter = { lines: 0, chars: 0, list_lines: 0, text_lines: 0 }
176
+ counter = Counter.new(lines: 0, chars: 0, list_lines: 0, text_lines: 0)
169
177
  listmode = nil
170
178
 
171
- content.split("\n").each do |l|
179
+ content.each_line(chomp: true) do |l|
172
180
  if l.start_with?("\x01STARTLIST\x01")
173
181
  listmode = true
174
182
  next
@@ -180,58 +188,67 @@ module ReVIEW
180
188
  level = $1.to_i
181
189
  l = $'
182
190
  if level <= upper
183
- if counter[:chars] > 0
191
+ if counter.chars > 0
184
192
  headline_array.push(counter)
185
193
  end
186
194
  headline = l
187
- counter = {
195
+ counter = Counter.new(
188
196
  level: level,
189
197
  headline: headline,
190
198
  lines: 1,
191
199
  chars: headline.size,
192
200
  list_lines: 0,
193
201
  text_lines: 1
194
- }
202
+ )
195
203
  next
196
204
  end
197
205
  end
198
206
 
199
- counter[:lines] += 1
200
- counter[:chars] += l.size
207
+ counter.lines += 1
208
+ counter.chars += l.size
201
209
 
202
210
  if listmode
203
211
  # code list: calculate line wrapping
204
- if l.size == 0
205
- counter[:list_lines] += 1
206
- else
207
- counter[:list_lines] += (calc_linesize(l) - 1) / @book.page_metric.list.n_columns + 1
208
- end
212
+ counter.list_lines += calc_line_wrapping(l, mode: :list)
209
213
  else
210
214
  # normal paragraph: calculate line wrapping
211
- if l.size == 0
212
- counter[:text_lines] += 1
213
- else
214
- counter[:text_lines] += (calc_linesize(l) - 1) / @book.page_metric.text.n_columns + 1
215
- end
215
+ counter.text_lines += calc_line_wrapping(l, mode: :text)
216
216
  end
217
217
  end
218
218
  headline_array.push(counter)
219
219
 
220
- total_lines = 0
221
- total_chars = 0
222
- total_list_lines = 0
223
- total_text_lines = 0
220
+ total = calc_total_count(name, headline_array)
221
+ headline_array.unshift(total)
222
+ end
223
+
224
+ def calc_line_wrapping(line, mode:)
225
+ return 1 if line.size == 0
226
+
227
+ case mode
228
+ when :list
229
+ (calc_linesize(line) - 1) / @book.page_metric.list.n_columns + 1
230
+ else # mode == :text
231
+ (calc_linesize(line) - 1) / @book.page_metric.text.n_columns + 1
232
+ end
233
+ end
234
+
235
+ def calc_total_count(name, headline_array)
236
+ total = Counter.new(name: name,
237
+ lines: 0,
238
+ chars: 0,
239
+ list_lines: 0,
240
+ text_lines: 0)
224
241
 
225
242
  headline_array.each do |h|
226
- next unless h[:lines]
227
- total_lines += h[:lines]
228
- total_chars += h[:chars]
229
- total_list_lines += h[:list_lines]
230
- total_text_lines += h[:text_lines]
243
+ next unless h.lines
244
+
245
+ total.lines += h.lines
246
+ total.chars += h.chars
247
+ total.list_lines += h.list_lines
248
+ total.text_lines += h.text_lines
231
249
  end
232
250
 
233
- headline_array.delete_if(&:empty?).
234
- unshift({ name: name, lines: total_lines, chars: total_chars, list_lines: total_list_lines, text_lines: total_text_lines })
251
+ total
235
252
  end
236
253
 
237
254
  def build_chap(chap)
@@ -239,7 +256,7 @@ module ReVIEW
239
256
  begin
240
257
  compiler.compile(@book.chapter(chap.name))
241
258
  rescue ReVIEW::ApplicationError => e
242
- @logger.error e
259
+ @logger.error e.message
243
260
  exit 1
244
261
  end
245
262
  end