review 5.0.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +35 -0
  3. data/.github/workflows/ruby-win.yml +8 -4
  4. data/.github/workflows/ruby.yml +6 -2
  5. data/.rubocop.yml +24 -9
  6. data/NEWS.ja.md +215 -0
  7. data/NEWS.md +215 -1
  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 +10 -20
  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 +30 -38
  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 +23 -5
  28. data/doc/config.yml.sample-simple +1 -1
  29. data/doc/format.ja.md +49 -12
  30. data/doc/format.md +52 -12
  31. data/doc/quickstart.ja.md +11 -1
  32. data/doc/quickstart.md +11 -2
  33. data/doc/writing_vertical.ja.md +6 -0
  34. data/lib/review/book/base.rb +4 -0
  35. data/lib/review/book/book_unit.rb +15 -2
  36. data/lib/review/book/chapter.rb +3 -0
  37. data/lib/review/book/index.rb +5 -1
  38. data/lib/review/book/volume.rb +1 -0
  39. data/lib/review/builder.rb +90 -54
  40. data/lib/review/call_hook.rb +20 -0
  41. data/lib/review/catalog.rb +2 -0
  42. data/lib/review/compiler.rb +88 -52
  43. data/lib/review/configure.rb +64 -7
  44. data/lib/review/epubmaker/content.rb +113 -0
  45. data/lib/review/epubmaker/epubcommon.rb +372 -0
  46. data/lib/review/epubmaker/epubv2.rb +178 -0
  47. data/lib/review/epubmaker/epubv3.rb +231 -0
  48. data/lib/review/epubmaker/producer.rb +167 -0
  49. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  50. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  51. data/lib/review/epubmaker.rb +114 -129
  52. data/lib/review/exception.rb +13 -0
  53. data/lib/review/htmlbuilder.rb +109 -67
  54. data/lib/review/htmlutils.rb +1 -1
  55. data/lib/review/i18n.rb +1 -0
  56. data/lib/review/i18n.yml +6 -0
  57. data/lib/review/idgxmlbuilder.rb +72 -48
  58. data/lib/review/idgxmlmaker.rb +15 -14
  59. data/lib/review/img_math.rb +239 -0
  60. data/lib/review/index_builder.rb +90 -32
  61. data/lib/review/init.rb +4 -4
  62. data/lib/review/latexbox.rb +58 -0
  63. data/lib/review/latexbuilder.rb +79 -58
  64. data/lib/review/latexutils.rb +9 -1
  65. data/lib/review/lineinput.rb +112 -2
  66. data/lib/review/loggable.rb +27 -0
  67. data/lib/review/logger.rb +89 -2
  68. data/lib/review/makerhelper.rb +7 -206
  69. data/lib/review/markdownbuilder.rb +44 -4
  70. data/lib/review/pdfmaker.rb +70 -51
  71. data/lib/review/plaintextbuilder.rb +20 -11
  72. data/lib/review/preprocessor/directive.rb +35 -0
  73. data/lib/review/preprocessor/line.rb +34 -0
  74. data/lib/review/preprocessor/repository.rb +177 -0
  75. data/lib/review/preprocessor.rb +105 -301
  76. data/lib/review/rstbuilder.rb +13 -4
  77. data/lib/review/sec_counter.rb +1 -0
  78. data/lib/review/template.rb +11 -1
  79. data/lib/review/textmaker.rb +23 -20
  80. data/lib/review/textutils.rb +10 -17
  81. data/lib/review/tocprinter.rb +93 -71
  82. data/lib/review/topbuilder.rb +44 -19
  83. data/lib/review/update.rb +5 -6
  84. data/lib/review/version.rb +1 -1
  85. data/lib/review/volumeprinter.rb +11 -12
  86. data/lib/review/webmaker.rb +31 -27
  87. data/lib/review/webtocprinter.rb +10 -9
  88. data/lib/review/yamlloader.rb +2 -1
  89. data/lib/review.rb +1 -1
  90. data/review.gemspec +5 -3
  91. data/samples/sample-book/src/config-epub2.yml +1 -1
  92. data/samples/sample-book/src/config.yml +1 -1
  93. data/samples/sample-book/src/lib/tasks/review.rake +19 -1
  94. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +2 -1
  95. data/samples/syntax-book/ch01.re +1 -1
  96. data/samples/syntax-book/ch02.re +30 -6
  97. data/samples/syntax-book/ch03.re +1 -1
  98. data/samples/syntax-book/images/img3-2.png +0 -0
  99. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +2 -1
  100. data/templates/html/_colophon.html.erb +23 -0
  101. data/templates/html/_colophon_history.html.erb +9 -0
  102. data/templates/html/_cover.html.erb +10 -0
  103. data/templates/html/_part_body.html.erb +6 -0
  104. data/templates/html/_titlepage.html.erb +20 -0
  105. data/templates/html/layout-html5.html.erb +6 -0
  106. data/templates/html/layout-xhtml1.html.erb +6 -0
  107. data/templates/latex/config.erb +11 -0
  108. data/templates/latex/review-jlreq/review-base.sty +7 -9
  109. data/templates/latex/review-jlreq/review-jlreq.cls +48 -6
  110. data/templates/latex/review-jlreq/review-style.sty +6 -1
  111. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  112. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  113. data/templates/latex/review-jsbook/review-base.sty +13 -9
  114. data/templates/latex/review-jsbook/review-jsbook.cls +41 -6
  115. data/templates/latex/review-jsbook/review-style.sty +6 -1
  116. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  117. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  118. data/templates/opf/epubv2.opf.erb +7 -7
  119. data/templates/opf/epubv3.opf.erb +7 -7
  120. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  121. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  122. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  123. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  124. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  125. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  126. data/templates/web/html/layout-html5.html.erb +6 -5
  127. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  128. data/test/assets/header_listener.html +35 -0
  129. data/test/assets/img_math/img1.png +0 -0
  130. data/test/assets/img_math/img2.png +0 -0
  131. data/test/assets/img_math/img3.png +0 -0
  132. data/test/assets/syntax_book_index_detail.txt +60 -0
  133. data/test/assets/test_template.tex +7 -1
  134. data/test/assets/test_template_backmatter.tex +7 -1
  135. data/test/run_test.rb +1 -1
  136. data/test/test_book_chapter.rb +27 -4
  137. data/test/test_builder.rb +10 -8
  138. data/test/test_catalog_converter_cmd.rb +1 -1
  139. data/test/test_epub3maker.rb +168 -124
  140. data/test/test_epubmaker.rb +248 -131
  141. data/test/test_epubmaker_cmd.rb +15 -4
  142. data/test/test_helper.rb +5 -4
  143. data/test/test_htmlbuilder.rb +170 -31
  144. data/test/test_idgxmlbuilder.rb +44 -23
  145. data/test/test_idgxmlmaker_cmd.rb +7 -3
  146. data/test/test_img_math.rb +111 -0
  147. data/test/test_index.rb +30 -4
  148. data/test/test_indexbuilder.rb +5 -5
  149. data/test/test_latexbuilder.rb +151 -26
  150. data/test/test_latexbuilder_v2.rb +18 -10
  151. data/test/test_lineinput.rb +20 -93
  152. data/test/test_markdownbuilder.rb +42 -0
  153. data/test/test_pdfmaker.rb +90 -0
  154. data/test/test_pdfmaker_cmd.rb +2 -2
  155. data/test/test_plaintextbuilder.rb +56 -40
  156. data/test/test_preprocessor.rb +188 -1
  157. data/test/test_reviewheaderlistener.rb +49 -0
  158. data/test/test_rstbuilder.rb +13 -0
  159. data/test/test_template.rb +12 -2
  160. data/test/test_textmaker_cmd.rb +5 -1
  161. data/test/test_tocprinter.rb +46 -0
  162. data/test/test_topbuilder.rb +50 -19
  163. data/test/test_update.rb +34 -34
  164. data/test/test_zip_exporter.rb +5 -6
  165. metadata +95 -17
  166. data/lib/epubmaker/content.rb +0 -111
  167. data/lib/epubmaker/epubcommon.rb +0 -449
  168. data/lib/epubmaker/epubv2.rb +0 -142
  169. data/lib/epubmaker/epubv3.rb +0 -235
  170. data/lib/epubmaker/producer.rb +0 -375
  171. data/lib/epubmaker/zip_exporter.rb +0 -81
  172. data/lib/epubmaker.rb +0 -23
  173. data/lib/lineinput.rb +0 -155
@@ -9,119 +9,109 @@
9
9
 
10
10
  require 'review/textutils'
11
11
  require 'review/exception'
12
- require 'nkf'
12
+ require 'review/preprocessor/directive'
13
+ require 'review/preprocessor/line'
14
+ require 'review/preprocessor/repository'
15
+ require 'review/loggable'
16
+ require 'open3'
13
17
 
14
18
  module ReVIEW
15
- module ErrorUtils
16
- def init_errorutils(f)
17
- @errutils_file = f
18
- @errutils_err = false
19
- end
20
-
21
- def warn(msg)
22
- @logger.warn "#{location}: #{msg}"
23
- end
24
-
25
- def error(msg)
26
- @errutils_err = true
27
- raise ApplicationError, "#{location}: #{msg}"
28
- end
29
-
30
- def location
31
- "#{filename}:#{lineno}"
32
- end
33
-
34
- def filename
35
- @errutils_file.path
36
- end
37
-
38
- def lineno
39
- @errutils_file.lineno
40
- end
41
- end
42
-
43
19
  class Preprocessor
44
- include ErrorUtils
20
+ include Loggable
45
21
 
46
- def initialize(repo, param)
47
- @repository = repo
48
- @config = param
22
+ TYPES = %w[file range].freeze
23
+ KNOWN_DIRECTIVES = %w[require provide warn ok].freeze
24
+ INF_INDENT = 9999
25
+
26
+ def initialize(param)
27
+ @repository = ReVIEW::Preprocessor::Repository.new(param)
28
+ @config = param ## do not use params in this class; only used in Repository
49
29
  @logger = ReVIEW.logger
50
30
  @leave_content = nil
51
31
  end
52
32
 
53
- def process(inf, outf)
54
- init_errorutils(inf)
55
- @f = outf
56
- begin
57
- preproc(inf)
58
- rescue Errno::ENOENT => e
59
- error e.message
33
+ def process(path)
34
+ File.open(path) do |inf|
35
+ @inf = inf
36
+ @f = StringIO.new
37
+ begin
38
+ preproc(@inf)
39
+ rescue Errno::ENOENT => e
40
+ error! e.message
41
+ end
42
+ @f.string
60
43
  end
61
44
  end
62
45
 
63
46
  private
64
47
 
65
- TYPES = %w[file range].freeze
66
-
67
48
  def preproc(f)
68
- init_vars
69
- f.each_line do |line|
70
- case line
71
- when /\A\#@\#/, /\A\#\#\#\#/
72
- @f.print line
73
-
74
- when /\A\#@defvar/
75
- @f.print line
76
- direc = parse_directive(line, 2)
77
- defvar(*direc.args)
49
+ @vartable = {}
50
+ @has_errors = false
78
51
 
79
- when /\A\#@mapoutput/
80
- direc = parse_directive(line, 1, 'stderr')
81
- @f.print line
82
- get_output(expand(direc.arg), direc['stderr']).each { |out| @f.print out.string }
83
- skip_list(f)
84
-
85
- when /\A\#@mapfile/
86
- direc = parse_directive(line, 1, 'eval')
87
- path = expand(direc.arg)
88
- @leave_content = File.extname(path) == '.re'
89
- if direc['eval']
90
- ent = evaluate(path, ent)
91
- else
92
- ent = @repository.fetch_file(path)
93
- end
94
- replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
52
+ f.each_line do |line|
53
+ begin
54
+ case line
55
+ when /\A\#@\#/, /\A\#\#\#\#/
56
+ @f.print line
95
57
 
96
- when /\A\#@map(?:range)?/
97
- direc = parse_directive(line, 2, 'unindent')
98
- path = expand(direc.args[0])
99
- @leave_content = File.extname(path) == '.re'
100
- ent = @repository.fetch_range(path, direc.args[1]) or
101
- error "unknown range: #{path}: #{direc.args[1]}"
102
- ent = (direc['unindent'] ? unindent(ent, direc['unindent']) : ent)
103
- replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
58
+ when /\A\#@defvar/
59
+ @f.print line
60
+ direc = parse_directive(line, 2)
61
+ defvar(*direc.args)
104
62
 
105
- when /\A\#@end/
106
- error 'unbaranced #@end'
63
+ when /\A\#@mapoutput/
64
+ direc = parse_directive(line, 1, 'stderr')
65
+ @f.print line
66
+ get_output(expand(direc.arg), direc['stderr']).each { |out| @f.print out.string }
67
+ skip_list(f)
68
+
69
+ when /\A\#@mapfile/
70
+ direc = parse_directive(line, 1, 'eval')
71
+ path = expand(direc.arg)
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
78
+ replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
79
+
80
+ when /\A\#@map(?:range)?/
81
+ direc = parse_directive(line, 2, 'unindent')
82
+ path = expand(direc.args[0])
83
+ @leave_content = File.extname(path) == '.re'
84
+ ent = @repository.fetch_range(path, direc.args[1]) or
85
+ app_error "unknown range: #{path}: #{direc.args[1]}"
86
+ ent = (direc['unindent'] ? unindent(ent, direc['unindent']) : ent)
87
+ replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
88
+
89
+ when /\A\#@end/
90
+ app_error 'unbaranced #@end'
91
+
92
+ when /\A\#@/
93
+ op = line.slice(/@(\w+)/, 1)
94
+ warn "unknown directive: #{line.strip}", location: location unless known_directive?(op)
95
+ if op == 'warn'
96
+ warn line.strip.sub(/\#@warn\((.+)\)/, '\1'), location: location
97
+ end
98
+ @f.print line
107
99
 
108
- when /\A\#@/
109
- op = line.slice(/@(\w+)/, 1)
110
- warn "unknown directive: #{line.strip}" unless known_directive?(op)
111
- if op == 'warn'
112
- warn line.strip.sub(/\#@warn\((.+)\)/, '\1')
100
+ when /\A\s*\z/ # empty line
101
+ @f.puts
102
+ else # rubocop:disable Lint/DuplicateBranch
103
+ @f.print line
113
104
  end
114
- @f.print line
115
-
116
- when /\A\s*\z/ # empty line
117
- @f.puts
118
- else
119
- @f.print line
105
+ rescue ApplicationError => e
106
+ @has_errors = true
107
+ error e.message, location: location
120
108
  end
121
109
  end
122
- end
123
110
 
124
- KNOWN_DIRECTIVES = %w[require provide warn ok].freeze
111
+ if @has_erros
112
+ error! 'preprocessor failed.'
113
+ end
114
+ end
125
115
 
126
116
  def known_directive?(op)
127
117
  KNOWN_DIRECTIVES.index(op)
@@ -151,60 +141,37 @@ module ReVIEW
151
141
  return nil
152
142
  when %r{\A//\}}
153
143
  unless @leave_content
154
- warn '//} seen in list'
144
+ warn '//} seen in list', location: location
155
145
  @f.print line
156
146
  return nil
157
147
  end
158
148
  when /\A\#@\w/
159
- warn "#{line.slice(/\A\#@\w+/)} seen in list"
149
+ warn "#{line.slice(/\A\#@\w+/)} seen in list", location: location
160
150
  @f.print line
161
151
  when /\A\#@/
162
152
  @f.print line
163
153
  end
164
154
  end
165
- error "list reached end of file (beginning line = #{begline})"
166
- end
167
-
168
- class Directive
169
- def initialize(op, args, opts)
170
- @op = op
171
- @args = args
172
- @opts = opts
173
- end
174
-
175
- attr_reader :op
176
- attr_reader :args
177
- attr_reader :opts
178
-
179
- def arg
180
- @args.first
181
- end
182
-
183
- def opt
184
- @opts.first
185
- end
186
-
187
- def [](key)
188
- @opts[key]
189
- end
155
+ app_error "list reached end of file (beginning line = #{begline})"
190
156
  end
191
157
 
192
158
  def parse_directive(line, argc, *optdecl)
193
159
  m = /\A\#@(\w+)\((.*?)\)(?:\[(.*?)\])?\z/.match(line.strip) or
194
- error "wrong directive: #{line.strip}"
160
+ app_error "wrong directive: #{line.strip}"
195
161
  op = m[1]
196
162
  args = m[2].split(/,\s*/)
197
163
  opts = parse_optargs(m[3])
198
164
  return if (argc == 0) && args.empty?
165
+
199
166
  if argc == -1
200
167
  # Any number of arguments are allowed.
201
168
  elsif args.size != argc
202
- error 'wrong arg size'
169
+ app_error 'wrong arg size'
203
170
  end
204
171
  if opts
205
172
  wrong_opts = opts.keys - optdecl
206
173
  unless wrong_opts.empty?
207
- error "wrong option: #{wrong_opts.keys.join(' ')}"
174
+ app_error "wrong option: #{wrong_opts.keys.join(' ')}"
208
175
  end
209
176
  end
210
177
  Directive.new(op, args, opts || {})
@@ -212,6 +179,7 @@ module ReVIEW
212
179
 
213
180
  def parse_optargs(str)
214
181
  return nil unless str
182
+
215
183
  table = {}
216
184
  str.split(/,\s*/).each do |a|
217
185
  name, spec = a.split('=', 2)
@@ -222,20 +190,19 @@ module ReVIEW
222
190
 
223
191
  def optarg_value(spec)
224
192
  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]
193
+ when 'true' # [name=true], [name]
194
+ true
195
+ when 'false' # [name=false]
196
+ false
197
+ when 'nil' # [name=nil]
198
+ nil
199
+ when /^\d+$/ # [name=8]
200
+ $&.to_i
230
201
  else # [name=val]
231
202
  spec
232
203
  end
233
204
  end
234
205
 
235
- def init_vars
236
- @vartable = {}
237
- end
238
-
239
206
  def defvar(name, value)
240
207
  @vartable[name] = value
241
208
  end
@@ -253,15 +220,13 @@ module ReVIEW
253
220
  chunk.map { |line| line.edit { |s| s.sub(re, '') } }
254
221
  end
255
222
 
256
- INF_INDENT = 9999
257
-
258
223
  def minimum_indent(chunk)
259
224
  n = chunk.map { |line| line.empty? ? INF_INDENT : line.num_indent }.min
260
225
  n == INF_INDENT ? 0 : n
261
226
  end
262
227
 
263
228
  def evaluate(path, chunk)
264
- outputs = get_output("ruby #{path}", false).split(/\n/).map(&:strip)
229
+ outputs = get_output("ruby #{path}", false).split("\n").map(&:strip)
265
230
  chunk.map do |line|
266
231
  if /\# \$\d+/ =~ line.string
267
232
  # map result into source.
@@ -272,8 +237,6 @@ module ReVIEW
272
237
  end
273
238
  end
274
239
 
275
- require 'open3'
276
-
277
240
  def get_output(cmd, use_stderr)
278
241
  out = err = nil
279
242
  Open3.popen3(cmd) do |_stdin, stdout, stderr|
@@ -287,181 +250,22 @@ module ReVIEW
287
250
  if err && !err.empty?
288
251
  $stderr.puts '[unexpected stderr message]'
289
252
  err.each { |line| $stderr.print line }
290
- error 'get_output: got unexpected output'
253
+ app_error 'get_output: got unexpected output'
291
254
  end
292
255
  num = 0
293
256
  out.map { |line| Line.new(num += 1, line) }
294
257
  end
295
- end
296
-
297
- class Line
298
- def initialize(number, string)
299
- @number = number
300
- @string = string
301
- end
302
-
303
- attr_reader :number
304
- attr_reader :string
305
- alias_method :to_s, :string
306
-
307
- def edit
308
- self.class.new(@number, yield(@string))
309
- end
310
-
311
- def empty?
312
- @string.strip.empty?
313
- end
314
-
315
- def num_indent
316
- @string.slice(/\A\s*/).size
317
- end
318
- end
319
-
320
- class Repository
321
- include TextUtils
322
- include ErrorUtils
323
-
324
- def initialize(param)
325
- @repository = {}
326
- @config = param
327
- @logger = ReVIEW.logger
328
- end
329
-
330
- def fetch_file(file)
331
- file_descripter(file)['file']
332
- end
333
-
334
- def fetch_range(file, name)
335
- fetch(file, 'range', name)
336
- end
337
-
338
- def fetch(file, type, name)
339
- table = file_descripter(file)[type] or return nil
340
- table[name]
341
- end
342
-
343
- private
344
-
345
- def file_descripter(fname)
346
- @leave_content = File.extname(fname) == '.re'
347
- return @repository[fname] if @repository[fname]
348
-
349
- @repository[fname] = git?(fname) ? parse_git_blob(fname) : parse_file(fname)
350
- end
351
-
352
- def git?(fname)
353
- fname.start_with?('git|')
354
- end
355
-
356
- def parse_git_blob(g_obj)
357
- IO.popen('git show ' + g_obj.sub(/\Agit\|/, ''), 'r') do |f|
358
- init_errorutils(f)
359
- return _parse_file(f)
360
- end
361
- end
362
-
363
- def parse_file(fname)
364
- File.open(fname, 'rt:BOM|utf-8') do |f|
365
- init_errorutils(f)
366
- return _parse_file(f)
367
- end
368
- end
369
-
370
- def _parse_file(f)
371
- whole = []
372
- repo = { 'file' => whole }
373
- curr = { 'WHOLE' => whole }
374
- lineno = 1
375
- yacchack = false # remove ';'-only lines.
376
- opened = [['(not opened)', '(not opened)']] * 3
377
-
378
- f.each do |line|
379
- case line
380
- when /(?:\A\#@|\#@@)([a-z]+)_(begin|end)\((.*)\)/
381
- type = check_type($1)
382
- direction = $2
383
- spec = check_spec($3)
384
- case direction
385
- when 'begin'
386
- key = "#{type}/#{spec}"
387
- if curr[key]
388
- error "begin x2: #{key}"
389
- end
390
- (repo[type] ||= {})[spec] = curr[key] = []
391
- when 'end'
392
- curr.delete("#{type}/#{spec}") or
393
- error "end before begin: #{type}/#{spec}"
394
- else
395
- raise 'must not happen'
396
- end
397
-
398
- when %r{(?:\A\#@|\#@@)([a-z]+)/(\w+)\{}
399
- type = check_type($1)
400
- spec = check_spec($2)
401
- key = "#{type}/#{spec}"
402
- if curr[key]
403
- error "begin x2: #{key}"
404
- end
405
- (repo[type] ||= {})[spec] = curr[key] = []
406
- opened.push([type, spec])
407
-
408
- when %r{(?:\A\#@|\#@@)([a-z]+)/(\w+)\}}
409
- type = check_type($1)
410
- spec = check_spec($2)
411
- curr.delete("#{type}/#{spec}") or
412
- error "end before begin: #{type}/#{spec}"
413
- opened.delete("#{type}/#{spec}")
414
-
415
- when /(?:\A\#@|\#@@)\}/
416
- type, spec = opened.last
417
- curr.delete("#{type}/#{spec}") or
418
- error "closed before open: #{type}/#{spec}"
419
- opened.pop
420
-
421
- when /(?:\A\#@|\#@@)yacchack/
422
- yacchack = true
423
-
424
- when /\A\#@-/ # does not increment line number.
425
- line = canonical($')
426
- curr.each_value { |list| list.push(Line.new(nil, line)) }
427
-
428
- else
429
- next if yacchack && (line.strip == ';')
430
- line = canonical(line)
431
- curr.each_value { |list| list.push(Line.new(lineno, line)) }
432
- lineno += 1
433
- end
434
- end
435
- if curr.size > 1
436
- curr.delete('WHOLE')
437
- curr.each { |range, lines| @logger.warn "#{filename}: unclosed range: #{range} (begin @#{lines.first.number})" }
438
- raise ApplicationError, 'ERROR'
439
- end
440
-
441
- repo
442
- end
443
-
444
- def canonical(line)
445
- if @leave_content
446
- return line
447
- end
448
258
 
449
- tabwidth = @config['tabwidth'] || 8
450
- if tabwidth > 0
451
- detab(line, tabwidth).rstrip + "\n"
452
- else
453
- line
454
- end
259
+ def location
260
+ "#{filename}:#{lineno}"
455
261
  end
456
262
 
457
- def check_type(type)
458
- error "wrong type: #{type.inspect}" unless Preprocessor::TYPES.index(type)
459
- type
263
+ def filename
264
+ @inf.path
460
265
  end
461
266
 
462
- def check_spec(spec)
463
- error "wrong spec: #{spec.inspect}" unless /\A\w+\z/ =~ spec
464
- spec
267
+ def lineno
268
+ @inf.lineno
465
269
  end
466
270
  end
467
271
  end
@@ -54,12 +54,12 @@ module ReVIEW
54
54
  end
55
55
 
56
56
  def builder_init_file
57
+ super
57
58
  @section = 0
58
59
  @subsection = 0
59
60
  @subsubsection = 0
60
61
  @subsubsubsection = 0
61
62
  @blank_seen = true
62
- @sec_counter = SecCounter.new(5, @chapter)
63
63
  @ul_indent = 0
64
64
  @ol_indent = 0
65
65
  @in_role = false
@@ -86,6 +86,7 @@ module ReVIEW
86
86
  private :blank
87
87
 
88
88
  def result
89
+ check_printendnotes
89
90
  solve_nest(@output.string)
90
91
  end
91
92
 
@@ -124,7 +125,7 @@ module ReVIEW
124
125
  end
125
126
 
126
127
  def ul_item(lines)
127
- puts ' ' * (@ul_indent - 1) + "* #{join_lines_to_paragraph(lines)}"
128
+ puts (' ' * (@ul_indent - 1)) + "* #{join_lines_to_paragraph(lines)}"
128
129
  end
129
130
 
130
131
  def ul_end
@@ -138,7 +139,7 @@ module ReVIEW
138
139
  end
139
140
 
140
141
  def ol_item(lines, _num)
141
- puts ' ' * (@ol_indent - 1) + "#. #{join_lines_to_paragraph(lines)}"
142
+ puts (' ' * (@ol_indent - 1)) + "#. #{join_lines_to_paragraph(lines)}"
142
143
  end
143
144
 
144
145
  def ol_end
@@ -155,7 +156,7 @@ module ReVIEW
155
156
 
156
157
  def dd(lines)
157
158
  split_paragraph(lines).each do |paragraph|
158
- puts " #{paragraph.gsub(/\n/, '')}"
159
+ puts " #{paragraph.delete("\n")}"
159
160
  end
160
161
  end
161
162
 
@@ -367,6 +368,14 @@ module ReVIEW
367
368
  " [##{id.sub(' ', '_')}]_ "
368
369
  end
369
370
 
371
+ def inline_endnote(id)
372
+ " [(#{@chapter.endnote(id).number})]_ "
373
+ end
374
+
375
+ def endnote_item(id)
376
+ puts ".. [(#{@chapter.endnote(id).number})] #{compile_inline(@chapter.endnote(id).content)}"
377
+ end
378
+
370
379
  def compile_ruby(base, ruby)
371
380
  " :ruby:`#{base}`<#{ruby}>`_ "
372
381
  end
@@ -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,10 +10,20 @@ 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
- @erb = ERB.new(content, nil, mode)
22
+ @erb = if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
23
+ ERB.new(content, trim_mode: mode)
24
+ else
25
+ ERB.new(content, nil, mode)
26
+ end
17
27
  end
18
28
 
19
29
  def result(bind_data = nil)