review-retrovert 0.3.1 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/retrovert.yml +61 -0
  3. data/.gitignore +2 -2
  4. data/.ruby-version +1 -0
  5. data/Dockerfile +1 -1
  6. data/Gemfile +1 -0
  7. data/Gemfile.lock +82 -17
  8. data/README.md +6 -3
  9. data/lib/review/retrovert/cli.rb +4 -0
  10. data/lib/review/retrovert/converter.rb +375 -9
  11. data/lib/review/retrovert/version.rb +1 -1
  12. data/lib/review/retrovert/yamlconfig.rb +13 -1
  13. data/review-retrovert.gemspec +2 -2
  14. data/testdata/mybook/.gitignore +7 -0
  15. data/testdata/mybook/README.md +43 -0
  16. data/testdata/mybook/Rakefile +16 -0
  17. data/testdata/mybook/catalog.yml +33 -0
  18. data/testdata/mybook/config-starter.yml +139 -0
  19. data/testdata/mybook/config.yml +375 -0
  20. data/testdata/mybook/contents/00-preface.re +83 -0
  21. data/testdata/mybook/contents/01-install.re +272 -0
  22. data/testdata/mybook/contents/02-tutorial.re +1008 -0
  23. data/testdata/mybook/contents/03-syntax.re +2613 -0
  24. data/testdata/mybook/contents/04-customize.re +728 -0
  25. data/testdata/mybook/contents/05-faq.re +328 -0
  26. data/testdata/mybook/contents/06-bestpractice.re +971 -0
  27. data/testdata/mybook/contents/91-compare.re +18 -0
  28. data/testdata/mybook/contents/92-filelist.re +119 -0
  29. data/testdata/mybook/contents/93-background.re +267 -0
  30. data/testdata/mybook/contents/99-postface.re +38 -0
  31. data/testdata/mybook/css/normalize.css +349 -0
  32. data/testdata/mybook/css/webstyle.css +514 -0
  33. data/testdata/mybook/images/03-syntax/favicon-16x16.png +0 -0
  34. data/testdata/mybook/images/03-syntax/figure_heretop.png +0 -0
  35. data/testdata/mybook/images/03-syntax/tw-icon1.jpg +0 -0
  36. data/testdata/mybook/images/03-syntax/tw-icon2.jpg +0 -0
  37. data/testdata/mybook/images/03-syntax/tw-icon3.jpg +0 -0
  38. data/testdata/mybook/images/03-syntax/tw-icon4.jpg +0 -0
  39. data/testdata/mybook/images/04-customize/caption_pagebreak.png +0 -0
  40. data/testdata/mybook/images/04-customize/chaptitlepage_sample.png +0 -0
  41. data/testdata/mybook/images/05-faq/codeblock_rpadding1.png +0 -0
  42. data/testdata/mybook/images/05-faq/codeblock_rpadding2.png +0 -0
  43. data/testdata/mybook/images/06-bestpractice/figure_heretop.png +0 -0
  44. data/testdata/mybook/images/06-bestpractice/font_beramono.png +0 -0
  45. data/testdata/mybook/images/06-bestpractice/heading_design1.png +0 -0
  46. data/testdata/mybook/images/06-bestpractice/heading_design2.png +0 -0
  47. data/testdata/mybook/images/06-bestpractice/margin_book.png +0 -0
  48. data/testdata/mybook/images/06-bestpractice/multiline-title.png +0 -0
  49. data/testdata/mybook/images/06-bestpractice/preface_numbered.png +0 -0
  50. data/testdata/mybook/images/06-bestpractice/program_border.png +0 -0
  51. data/testdata/mybook/images/06-bestpractice/sechead_design_4.png +0 -0
  52. data/testdata/mybook/images/06-bestpractice/titlepage-samples.png +0 -0
  53. data/testdata/mybook/images/93-background/bug913.png +0 -0
  54. data/testdata/mybook/images/93-background/slide2.png +0 -0
  55. data/testdata/mybook/images/cover_a5.pdf +0 -0
  56. data/testdata/mybook/images/cover_b5.pdf +0 -0
  57. data/testdata/mybook/images/tw-icon.jpg +0 -0
  58. data/testdata/mybook/layouts/layout.epub.erb +29 -0
  59. data/testdata/mybook/layouts/layout.html5.erb +106 -0
  60. data/testdata/mybook/layouts/layout.tex.erb +546 -0
  61. data/testdata/mybook/lib/hooks/beforetexcompile.rb +55 -0
  62. data/testdata/mybook/lib/ruby/review-builder.rb +503 -0
  63. data/testdata/mybook/lib/ruby/review-cli.rb +58 -0
  64. data/testdata/mybook/lib/ruby/review-compiler.rb +523 -0
  65. data/testdata/mybook/lib/ruby/review-epubmaker.rb +606 -0
  66. data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +661 -0
  67. data/testdata/mybook/lib/ruby/review-latexbuilder.rb +782 -0
  68. data/testdata/mybook/lib/ruby/review-maker.rb +235 -0
  69. data/testdata/mybook/lib/ruby/review-monkeypatch.rb +91 -0
  70. data/testdata/mybook/lib/ruby/review-pdfmaker.rb +468 -0
  71. data/testdata/mybook/lib/ruby/review-textbuilder.rb +36 -0
  72. data/testdata/mybook/lib/ruby/review-tocparser.rb +285 -0
  73. data/testdata/mybook/lib/ruby/review-webmaker.rb +433 -0
  74. data/testdata/mybook/lib/tasks/mytasks.rake +31 -0
  75. data/testdata/mybook/lib/tasks/review.rake +142 -0
  76. data/testdata/mybook/lib/tasks/review.rake.orig +72 -0
  77. data/testdata/mybook/lib/tasks/starter.rake +326 -0
  78. data/testdata/mybook/locale.yml +6 -0
  79. data/testdata/mybook/review-ext.rb +206 -0
  80. data/testdata/mybook/sty/jumoline.sty +310 -0
  81. data/testdata/mybook/sty/mycolophon.sty +81 -0
  82. data/testdata/mybook/sty/mystyle.sty +8 -0
  83. data/testdata/mybook/sty/mytextsize.sty +61 -0
  84. data/testdata/mybook/sty/mytitlepage.sty +103 -0
  85. data/testdata/mybook/sty/reviewmacro.sty +60 -0
  86. data/testdata/mybook/sty/starter-codeblock.sty +332 -0
  87. data/testdata/mybook/sty/starter-color.sty +79 -0
  88. data/testdata/mybook/sty/starter-font.sty +112 -0
  89. data/testdata/mybook/sty/starter-heading.sty +514 -0
  90. data/testdata/mybook/sty/starter-note.sty +127 -0
  91. data/testdata/mybook/sty/starter-section.sty +262 -0
  92. data/testdata/mybook/sty/starter-toc.sty +72 -0
  93. data/testdata/mybook/sty/starter.sty +554 -0
  94. data/testdata/mybook/style.css +597 -0
  95. metadata +100 -10
  96. data/.travis.yml +0 -6
@@ -0,0 +1,661 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+ ### ReVIEW::HTMLBuilderクラスを拡張する
5
+ ###
6
+
7
+ require 'review/htmlbuilder'
8
+
9
+
10
+ module ReVIEW
11
+
12
+ defined?(HTMLBuilder) or raise "internal error: HTMLBuilder not found."
13
+
14
+
15
+ class HTMLBuilder
16
+
17
+ attr_accessor :starter_config
18
+
19
+ def layoutfile
20
+ ## 'rake web' のときに使うレイアウトファイルを 'layout.html5.erb' へ変更
21
+ if @book.config.maker == 'webmaker'
22
+ htmldir = 'web/html'
23
+ #localfilename = 'layout-web.html.erb'
24
+ localfilename = 'layout.html5.erb'
25
+ else
26
+ htmldir = 'html'
27
+ localfilename = 'layout.html.erb'
28
+ end
29
+ ## 以下はリファクタリングした結果
30
+ basename = @book.htmlversion == 5 ? 'layout-html5.html.erb' : 'layout-xhtml1.html.erb'
31
+ htmlfilename = File.join(htmldir, basename)
32
+ #
33
+ layout_file = File.join(@book.basedir, 'layouts', localfilename)
34
+ if ! File.exist?(layout_file)
35
+ ! File.exist?(File.join(@book.basedir, 'layouts', 'layout.erb')) or
36
+ raise ReVIEW::ConfigError, 'layout.erb is obsoleted. Please use layout.html.erb.'
37
+ layout_file = nil
38
+ elsif ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
39
+ warn "user's layout is prohibited in safe mode. ignored."
40
+ layout_file = nil
41
+ end
42
+ layout_file ||= File.expand_path(htmlfilename, ReVIEW::Template::TEMPLATE_DIR)
43
+ return layout_file
44
+ end
45
+
46
+ def result
47
+ # default XHTML header/footer
48
+ @title = strip_html(compile_inline(@chapter.title))
49
+ @body = @output.string
50
+ @language = @book.config['language']
51
+ @stylesheets = @book.config['stylesheet']
52
+ @next = @chapter.next_chapter
53
+ @prev = @chapter.prev_chapter
54
+ @next_title = @next ? compile_inline(@next.title) : ''
55
+ @prev_title = @prev ? compile_inline(@prev.title) : ''
56
+
57
+ if @book.config.maker == 'webmaker'
58
+ #@toc = ReVIEW::WEBTOCPrinter.book_to_string(@book) #-
59
+ @toc = ReVIEW::WEBTOCPrinter.book_to_html(@book, @chapter) #+
60
+ end
61
+
62
+ ReVIEW::Template.load(layoutfile).result(binding)
63
+ end
64
+
65
+ def headline(level, label, caption)
66
+ prefix, anchor = headline_prefix(level)
67
+ prefix = "<span class=\"secno\">#{prefix}</span> " if prefix
68
+ puts "" if level > 1
69
+ a_id = ""
70
+ a_id = "<a id=\"h#{anchor}\"></a>" if anchor
71
+ #
72
+ if caption.empty?
73
+ puts a_id if label
74
+ else
75
+ br = ""
76
+ attr = label ? " id=\"#{normalize_id(label)}\"" : ""
77
+ conf = @starter_config
78
+ case level
79
+ when 1 ; attr << " class=\"#{conf['chapter_decoration']} #{conf['chapter_align']} #{conf['chapter_oneline'] ? 'oneline' : 'twolines'}\"" if prefix
80
+ attr << " class=\"none #{conf['chapter_align']}\"" unless prefix
81
+ br = "<br/>" unless conf['chapter_oneline']
82
+ when 2 ; attr << " class=\"#{conf['section_decoration']}\""
83
+ when 3 ; attr << " class=\"#{conf['subsection_decoration']}\""
84
+ end
85
+ puts "<h#{level}#{attr}>#{a_id}#{prefix}#{br}#{compile_inline(caption)}</h#{level}>"
86
+ end
87
+ end
88
+
89
+ def result_metric(array)
90
+ attrs = {}
91
+ array.each do |item|
92
+ k = item.keys[0]
93
+ v = item[k]
94
+ if k == 'border' && v == 'on'
95
+ k = 'class'; v = 'border-on'
96
+ end
97
+ (attrs[k] ||= []) << v
98
+ end
99
+ attrs.map {|k, arr| " #{k}=\"#{arr.join(' ')}\"" }.join()
100
+ end
101
+
102
+ def image_image(id, caption, metric)
103
+ src = @chapter.image(id).path.sub(%r{\A\./}, '')
104
+ alt = escape_html(compile_inline(caption))
105
+ metrics = parse_metric('html', metric)
106
+ metrics = " class=\"img\"" unless metrics.present?
107
+ puts "<div id=\"#{normalize_id(id)}\" class=\"image\">"
108
+ puts "<img src=\"#{src}\" alt=\"#{alt}\"#{metrics} />"
109
+ image_header(id, caption)
110
+ puts "</div>"
111
+ end
112
+
113
+ ## コードブロック(//program, //terminal)
114
+
115
+ def program(lines, id=nil, caption=nil, optionstr=nil)
116
+ _codeblock('program', 'code', lines, id, caption, optionstr)
117
+ end
118
+
119
+ def terminal(lines, id=nil, caption=nil, optionstr=nil)
120
+ _codeblock('terminal', 'cmd-code', lines, id, caption, optionstr)
121
+ end
122
+
123
+ protected
124
+
125
+ def _codeblock(blockname, classname, lines, id, caption, optionstr)
126
+ ## ブロックコマンドのオプション引数はCompilerクラスでパースすべき。
127
+ ## しかしCompilerクラスがそのような設計になってないので、
128
+ ## 仕方ないのでBuilderクラスでパースする。
129
+ opts = _parse_codeblock_optionstr(optionstr, blockname)
130
+ CODEBLOCK_OPTIONS.each {|k, v| opts[k] = v unless opts.key?(k) }
131
+ #
132
+ if opts['eolmark']
133
+ lines = lines.map {|line| "#{detab(line)}<small class=\"startereolmark\"></small>" }
134
+ else
135
+ lines = lines.map {|line| detab(line) }
136
+ end
137
+ #
138
+ indent_w = opts['indentwidth']
139
+ if indent_w && indent_w > 0
140
+ indent_str = " " * (indent_w - 1) + '<span class="indentbar"> </span>'
141
+ lines = lines.map {|line|
142
+ line.sub(/\A( +)/) {
143
+ m, n = ($1.length - 1).divmod indent_w
144
+ " " << indent_str * m << " " * n
145
+ }
146
+ }
147
+ end
148
+ #
149
+ puts "<div id=\"#{normalize_id(id)}\" class=\"#{classname}\">" if id.present?
150
+ puts "<div class=\"#{classname}\">" unless id.present?
151
+ #
152
+ if id.present? || caption.present?
153
+ str = _build_caption_str(id, caption)
154
+ print "<span class=\"caption\">#{str}</span>\n"
155
+ classattr = "list"
156
+ else
157
+ classattr = "emlist"
158
+ end
159
+ #
160
+ lang = opts['lang']
161
+ lang = File.extname(id || "").gsub(".", "") if lang.blank?
162
+ classattr << " language-#{lang}" unless lang.blank?
163
+ classattr << " highlight" if highlight?
164
+ print "<pre class=\"#{classattr}\">"
165
+ #
166
+ gen = opts['lineno'] ? LineNumberGenerator.new(opts['lineno']).each : nil
167
+ if gen
168
+ width = opts['linenowidth']
169
+ if width < 0
170
+ format = "%s"
171
+ elsif width == 0
172
+ last_lineno = gen.each.take(lines.length).compact.last
173
+ width = last_lineno.to_s.length
174
+ format = "%#{width}s"
175
+ else
176
+ format = "%#{width}s"
177
+ end
178
+ end
179
+ buf = []
180
+ start_tag = opts['linenowidth'] >= 0 ? "<em class=\"linenowidth\">" : "<em class=\"lineno\">"
181
+ lines.each_with_index do |line, i|
182
+ buf << start_tag << (format % gen.next) << ": </em>" if gen
183
+ buf << line << "\n"
184
+ end
185
+ puts highlight(body: buf.join(), lexer: lang,
186
+ format: "html", linenum: !!gen,
187
+ #options: {linenostart: start}
188
+ )
189
+ #
190
+ print "</pre>\n"
191
+ print "</div>\n"
192
+ end
193
+
194
+ public
195
+
196
+ ## コードリスト(//list, //emlist, //listnum, //emlistnum, //cmd, //source)
197
+ def list(lines, id=nil, caption=nil, lang=nil)
198
+ _codeblock("list", "caption-code", lines, id, caption, _codeblock_optstr(lang, false))
199
+ end
200
+ def listnum(lines, id=nil, caption=nil, lang=nil)
201
+ _codeblock("listnum", "code", lines, id, caption, _codeblock_optstr(lang, true))
202
+ end
203
+ def emlist(lines, caption=nil, lang=nil)
204
+ _codeblock("emlist", "emlist-code", lines, nil, caption, _codeblock_optstr(lang, false))
205
+ end
206
+ def emlistnum(lines, caption=nil, lang=nil)
207
+ _codeblock("emlistnum", "emlistnum-code", lines, nil, caption, _codeblock_optstr(lang, true))
208
+ end
209
+ def source(lines, caption=nil, lang=nil)
210
+ _codeblock("source", "source-code", lines, nil, caption, _codeblock_optstr(lang, false))
211
+ end
212
+ def cmd(lines, caption=nil, lang=nil)
213
+ lang ||= "shell-session"
214
+ _codeblock("cmd", "cmd-code", lines, nil, caption, _codeblock_optstr(lang, false))
215
+ end
216
+ def _codeblock_optstr(lang, lineno_flag)
217
+ arr = []
218
+ arr << lang if lang
219
+ if lineno_flag
220
+ first_line_num = line_num()
221
+ arr << "lineno=#{first_line_num}"
222
+ arr << "linenowidth=0"
223
+ end
224
+ return arr.join(",")
225
+ end
226
+ private :_codeblock_optstr
227
+
228
+ protected
229
+
230
+ ## @<secref>{}
231
+
232
+ def _build_secref(chap, num, title, parent_title)
233
+ s = ""
234
+ ## 親セクションのタイトルがあれば使う
235
+ if parent_title
236
+ s << "「%s」内の" % parent_title # TODO: I18n化
237
+ end
238
+ ## 対象セクションへのリンクを作成する
239
+ if @book.config['chapterlink']
240
+ filename = "#{chap.id}#{extname()}"
241
+ dom_id = 'h' + num.gsub('.', '-')
242
+ s << "「<a href=\"#{filename}##{dom_id}\">#{title}</a>」"
243
+ else
244
+ s << "「#{title}」"
245
+ end
246
+ return s
247
+ end
248
+
249
+ public
250
+
251
+ ## 順序つきリスト
252
+
253
+ def ol_begin(start_num=nil)
254
+ @_ol_types ||= [] # stack
255
+ case start_num
256
+ when nil
257
+ type = "1"; start = 1
258
+ when /\A(\d+)\.\z/
259
+ type = "1"; start = $1.to_i
260
+ when /\A([A-Z])\.\z/
261
+ type = "A"; start = $1.ord - 'A'.ord + 1
262
+ when /\A([a-z])\.\z/
263
+ type = "a"; start = $1.ord - 'a'.ord + 1
264
+ else
265
+ type = nil; start = nil
266
+ end
267
+ if type
268
+ puts "<ol start=\"#{start}\" type=\"#{type}\">"
269
+ else
270
+ puts "<ol class=\"ol-none\">"
271
+ end
272
+ @_ol_types.push(type)
273
+ end
274
+
275
+ def ol_end()
276
+ ol = !! @_ol_types.pop()
277
+ if ol
278
+ puts "</ol>"
279
+ else
280
+ puts "</ol>"
281
+ end
282
+ end
283
+
284
+ def ol_item_begin(lines, num)
285
+ ol = !! @_ol_types[-1]
286
+ if ol
287
+ print "<li>#{lines.join}"
288
+ else
289
+ n = escape_html(num)
290
+ print "<li data-mark=\"#{n}\"><span class=\"li-mark\">#{n} </span>#{lines.join}"
291
+ end
292
+ end
293
+
294
+ def ol_item_end()
295
+ puts "</li>"
296
+ end
297
+
298
+ ## 入れ子可能なブロック命令
299
+
300
+ def on_minicolumn(type, caption, &b)
301
+ puts "<div class=\"#{type}\">"
302
+ puts "<p class=\"caption\">#{compile_inline(caption)}</p>" if caption.present?
303
+ yield
304
+ puts '</div>'
305
+ end
306
+ protected :on_minicolumn
307
+
308
+ def on_sideimage_block(imagefile, imagewidth, option_str=nil, &b)
309
+ imagefile, imagewidth, opts = validate_sideimage_args(imagefile, imagewidth, option_str)
310
+ filepath = find_image_filepath(imagefile)
311
+ side = (opts['side'] || 'L') == 'L' ? 'left' : 'right'
312
+ imgclass = opts['border'] ? "image-bordered" : nil
313
+ normalize = proc {|s| s =~ /^\A(\d+(\.\d+))%\z/ ? "#{$1.to_f/100.0}\\textwidth" : s }
314
+ imgwidth = normalize.call(imagewidth)
315
+ boxwidth = normalize.call(opts['boxwidth']) || imgwidth
316
+ sepwidth = normalize.call(opts['sep'] || "0pt")
317
+ #
318
+ puts "<div class=\"sideimage\">\n"
319
+ puts " <div class=\"sideimage-image\" style=\"float:#{side};text-align:center;width:#{boxwidth}\">\n"
320
+ puts " <img src=\"#{filepath}\" class=\"#{imgclass}\" style=\"width:#{imgwidth}\"/>\n"
321
+ puts " </div>\n"
322
+ puts " <div class=\"sideimage-text\" style=\"margin-#{side}:#{boxwidth}\">\n"
323
+ puts " <div style=\"padding-#{side}:#{sepwidth}\">\n"
324
+ yield
325
+ puts " </div>\n"
326
+ puts " </div>\n"
327
+ puts "</div>\n"
328
+ end
329
+
330
+ #### ブロック命令
331
+
332
+ def footnote(id, str)
333
+ id_val = "fn-#{normalize_id(id)}"
334
+ href = "#fnb-#{normalize_id(id)}"
335
+ text = compile_inline(str)
336
+ chap_num = @chapter.footnote(id).number
337
+ if @book.config['epubversion'].to_i == 3
338
+ attr = " epub:type=\"footnote\""
339
+ mark = "[*#{chap_num}]"
340
+ else
341
+ attr = ""
342
+ mark = "[<a href=\"#{href}\">*#{chap_num}</a>]"
343
+ end
344
+ #
345
+ if truncate_if_endwith?("</div><!--/.footnote-list-->\n")
346
+ else
347
+ puts "<div class=\"footnote-list\">"
348
+ end
349
+ print "<div class=\"footnote\" id=\"#{id_val}\"#{attr}>"
350
+ print "<p class=\"footnote\">"
351
+ print "<span class=\"footnote-mark\">#{mark} </span>"
352
+ print text
353
+ print "</p>"
354
+ puts "</div>"
355
+ puts "</div><!--/.footnote-list-->\n"
356
+ end
357
+
358
+ alias __original_texequation texequation
359
+ def texequation(lines, label=nil, caption=nil)
360
+ if label.present?
361
+ chap = get_chap()
362
+ if chap.nil?
363
+ key = "format_number_header_without_chapter"
364
+ args = [@chapter.equation(label).number]
365
+ else
366
+ key = "format_number_header"
367
+ args = [chap, @chapter.equation(label).number]
368
+ end
369
+ s1 = I18n.t("equation")
370
+ s2 = I18n.t(key, args)
371
+ s3 = I18n.t("caption_prefix")
372
+ s4 = compile_inline(caption)
373
+ puts "<span class=\"caption\">#{s1}#{s2}#{s3}#{s4}</span>"
374
+ has_caption_line = true
375
+ elsif caption.present?
376
+ s3 = I18n.t("caption_prefix")
377
+ s4 = compile_inline(caption)
378
+ puts "<span class=\"caption\">#{s3}#{s4}</span>"
379
+ has_caption_line = true
380
+ else
381
+ has_caption_line = false
382
+ end
383
+ #
384
+ __original_texequation(lines)
385
+ end
386
+
387
+ ## 章 (Chapter) の概要
388
+ def abstract(lines)
389
+ puts '<div class="abstract">'
390
+ puts lines
391
+ puts '</div>'
392
+ end
393
+
394
+ ## 章タイトルを独立したページに
395
+ def makechaptitlepage(option=nil)
396
+ puts '' # HTMLでは特に何もしない
397
+ end
398
+
399
+ ## 縦方向のスペースがなければ改ページ
400
+ def needvspace(builder_name, height)
401
+ if builder_name == 'html' || builder_name == 'epub'
402
+ puts "<div style=\"height:#{height}\"></div>"
403
+ end
404
+ end
405
+
406
+ ## 段(Paragraph)の終わりにスペースを入れる
407
+ def paragraphend()
408
+ puts '' # HTMLでは特に何もしない
409
+ end
410
+
411
+ ## 小段(Subparagraph)の終わりにスペースを入れる(あれば)
412
+ def subparagraphend()
413
+ puts '' # HTMLでは特に何もしない
414
+ end
415
+
416
+ ## 引用(複数段落に対応)
417
+ def blockquote(lines)
418
+ puts '<blockquote class="blockquote">'
419
+ puts lines
420
+ puts '</blockquote>'
421
+ end
422
+
423
+ ## 引用(//quote{ ... //})
424
+ ## (入れ子対応なので、中に箇条書きや別のブロックを入れられる)
425
+ def on_quote_block()
426
+ puts '<blockquote class="blockquote">'
427
+ yield
428
+ puts '</blockquote>'
429
+ end
430
+ def quote(lines)
431
+ on_quote_block() do
432
+ puts lines
433
+ end
434
+ end
435
+
436
+ ## 引用 (====[quote] ... ====[/quote])
437
+ ## (ブロック構文ではないので、中に別のブロックや箇条書きを入れられる)
438
+ def quote_begin(level, label, caption)
439
+ puts '<blockquote class="blockquote">'
440
+ end
441
+ def quote_end(level)
442
+ puts '</blockquote>'
443
+ end
444
+
445
+ ## ノート(//note{ ... //})
446
+ ## (入れ子対応なので、中に箇条書きや別のブロックを入れられる)
447
+ def on_note_block(label=nil, caption=nil)
448
+ caption, label = label, nil if caption.nil?
449
+ if label
450
+ puts "<div class=\"note\" id=\"#{label}\">"
451
+ else
452
+ puts "<div class=\"note\">"
453
+ end
454
+ puts "<h5>#{compile_inline(caption)}</h5>" if caption.present?
455
+ yield
456
+ puts "</div>"
457
+ end
458
+ def note(lines, label=nil, caption=nil)
459
+ on_quote_block(label, caption) do
460
+ puts lines
461
+ end
462
+ end
463
+
464
+ ## ノート (====[note] ... ====[/note])
465
+ ## (ブロック構文ではないので、中に別のブロックや箇条書きを入れられる)
466
+ def note_begin(level, label, caption)
467
+ s = compile_inline(caption || "")
468
+ puts "<div class=\"note\">"
469
+ puts "<h5>#{s}</h5>" if s.present?
470
+ end
471
+ def note_end(level)
472
+ puts "</div>"
473
+ end
474
+
475
+ #### インライン命令
476
+
477
+ def inline_fn(id)
478
+ if @book.config['epubversion'].to_i == 3
479
+ type = " epub:type=\"noteref\""
480
+ else
481
+ type = ""
482
+ end
483
+ return "<sup><a id=\"fnb-#{normalize_id(id)}\" href=\"#fn-#{normalize_id(id)}\" class=\"noteref\"#{type}>*#{@chapter.footnote(id).number}</a></sup>"
484
+ rescue KeyError
485
+ error "unknown footnote: #{id}"
486
+ end
487
+
488
+ ## ファイル名
489
+ def inline_file(str)
490
+ on_inline_file { escape(str) }
491
+ end
492
+ def on_inline_file
493
+ "<span class=\"file\">#{yield}</span>"
494
+ end
495
+
496
+ ## ユーザ入力
497
+ def inline_userinput(str)
498
+ on_inline_input { escape(str) }
499
+ end
500
+ def on_inline_userinput
501
+ "<span class=\"userinput\">#{yield}</span>"
502
+ end
503
+
504
+ ## 引数をそのまま表示 (No Operation)
505
+ def inline_nop(str)
506
+ escape_html(str || "")
507
+ end
508
+ alias inline_letitgo inline_nop
509
+
510
+ ## 目立たせない(@<strong>{} の反対)
511
+ def inline_weak(str)
512
+ on_inline_weak { escape(str) }
513
+ end
514
+ def on_inline_weak
515
+ "<span class=\"weak\">#{yield}</span>"
516
+ end
517
+
518
+ ## 文字を小さくする
519
+ def inline_small(str) ; on_inline_small { escape(str) } ; end
520
+ def inline_xsmall(str) ; on_inline_xsmall { escape(str) } ; end
521
+ def inline_xxsmall(str) ; on_inline_xxsmall { escape(str) } ; end
522
+
523
+ def on_inline_small ; "<small style=\"font-size:small\">#{yield}</small>" ; end
524
+ def on_inline_xsmall ; "<small style=\"font-size:x-small\">#{yield}</small>" ; end
525
+ def on_inline_xxsmall ; "<small style=\"font-size:xx-small\">#{yield}</small>"; end
526
+
527
+ ## 文字を大きくする
528
+ def inline_large(str) ; on_inline_large { escape(str) } ; end
529
+ def inline_xlarge(str) ; on_inline_xlarge { escape(str) } ; end
530
+ def inline_xxlarge(str) ; on_inline_xxlarge { escape(str) } ; end
531
+ def on_inline_large ; "<span style=\"font-size:large\">#{yield}</span>" ; end
532
+ def on_inline_xlarge ; "<span style=\"font-size:x-large\">#{yield}</span>" ; end
533
+ def on_inline_xxlarge ; "<span style=\"font-size:xx-large\">#{yield}</span>"; end
534
+
535
+ ## 文字を大きくした@<strong>{}
536
+ def inline_xstrong(str) ; on_inline_xstrong { escape(str) }; end
537
+ def inline_xxstrong(str); on_inline_xxstrong { escape(str) }; end
538
+ def on_inline_xstrong ; "<span style=\"font-size:x-large\">#{yield}</span>"; end
539
+ def on_inline_xxstrong; "<span style=\"font-size:xx-large\">#{yield}</span>"; end
540
+
541
+ ## コードブロック中で折り返し箇所を手動で指定する
542
+ def inline_foldhere(arg)
543
+ '<br>'
544
+ end
545
+
546
+ ## ターミナルでのカーソル(背景が白、文字が黒)
547
+ def inline_cursor(str)
548
+ "<span class=\"cursor\">#{escape_html(str)}</span>"
549
+ end
550
+
551
+ ## nestable inline commands
552
+
553
+ def on_inline_i() ; "<i>#{yield}</i>" ; end
554
+ def on_inline_b() ; "<b>#{yield}</b>" ; end
555
+ def on_inline_code() ; "<code>#{yield}</code>" ; end
556
+ def on_inline_tt() ; "<tt>#{yield}</tt>" ; end
557
+ def on_inline_del() ; "<s>#{yield}</s>" ; end
558
+ def on_inline_sub() ; "<sub>#{yield}</sub>" ; end
559
+ def on_inline_sup() ; "<sup>#{yield}</sup>" ; end
560
+ def on_inline_em() ; "<em>#{yield}</em>" ; end
561
+ def on_inline_strong(); "<strong>#{yield}</strong>" ; end
562
+ def on_inline_u() ; "<u>#{yield}</u>" ; end
563
+ def on_inline_ami() ; "<span class=\"ami\">#{yield}</span>"; end
564
+ def on_inline_balloon(); "<span class=\"balloon\">← #{yield}</span>"; end
565
+
566
+ def build_inline_href(url, escaped_label) # compile_href()をベースに改造
567
+ flag_link = @book.config['externallink']
568
+ return _inline_hyperlink(url, escaped_label, flag_link)
569
+ end
570
+
571
+ def inline_hlink(str)
572
+ url, label = str.split(/, /, 2)
573
+ flag_link = @book.config['externallink']
574
+ return _inline_hyperlink(url, escape(label), flag_link)
575
+ end
576
+
577
+ def _inline_hyperlink(url, escaped_label, flag_link)
578
+ if flag_link
579
+ label = escaped_label || escape_html(url)
580
+ "<a href=\"#{escape_html(url)}\" class=\"link\">#{label}</a>"
581
+ elsif escaped_label
582
+ I18n.t('external_link', [escaped_label, escape_html(url)])
583
+ else
584
+ escape_html(url)
585
+ end
586
+ end
587
+ private :_inline_hyperlink
588
+
589
+ def build_inline_ruby(escaped_word, escaped_yomi) # compile_ruby()をベースに改造
590
+ pre = I18n.t('ruby_prefix'); post = I18n.t('ruby_postfix')
591
+ if @book.htmlversion == 5
592
+ "<ruby>#{escaped_word}<rp>#{pre}</rp><rt>#{escaped_yomi}</rt><rp>#{post}</rp></ruby>"
593
+ else
594
+ "<ruby><rb>#{escaped_word}</rb><rp>#{pre}</rp><rt>#{escaped_yomi}</rt><rp>#{post}</rp></ruby>"
595
+ end
596
+ end
597
+
598
+ protected
599
+
600
+ ## ノートを参照する
601
+ def build_noteref(chapter, label, caption)
602
+ href = chapter ? "#{chapter.id}#{extname()}##{label}" : "##{label}"
603
+ %Q`ノート「<a href="#{href}">#{escape(caption)}</a>」`
604
+ end
605
+
606
+ ## 数式を参照する
607
+ def build_eq(chapter, label, number)
608
+ s = "#{I18n.t('equation')}#{chapter.number}.#{number}"
609
+ "<a>#{escape(s)}</a>"
610
+ end
611
+
612
+ end
613
+
614
+
615
+ class TEXTBuilder
616
+
617
+ ## nestable inline commands
618
+
619
+ def on_inline_i() ; "<i>#{yield}</i>" ; end
620
+ def on_inline_b() ; "<b>#{yield}</b>" ; end
621
+ def on_inline_code() ; "<code>#{yield}</code>" ; end
622
+ def on_inline_tt() ; "<tt>#{yield}</tt>" ; end
623
+ def on_inline_del() ; "<s>#{yield}</s>" ; end
624
+ def on_inline_sub() ; "<sub>#{yield}</sub>" ; end
625
+ def on_inline_sup() ; "<sup>#{yield}</sup>" ; end
626
+ def on_inline_em() ; "<em>#{yield}</em>" ; end
627
+ def on_inline_strong(); "<strong>#{yield}</strong>" ; end
628
+ def on_inline_u() ; "<u>#{yield}</u>" ; end
629
+ def on_inline_ami() ; "<span class=\"ami\">#{yield}</span>"; end
630
+
631
+ def build_inline_href(url, escaped_label) # compile_href()をベースに改造
632
+ if @book.config['externallink']
633
+ label = escaped_label || escape_html(url)
634
+ "<a href=\"#{escape_html(url)}\" class=\"link\">#{label}</a>"
635
+ elsif escaped_label
636
+ I18n.t('external_link', [escaped_label, escape_html(url)])
637
+ else
638
+ escape_html(url)
639
+ end
640
+ end
641
+
642
+ def build_inline_ruby(escaped_word, escaped_yomi) # compile_ruby()をベースに改造
643
+ pre = I18n.t('ruby_prefix'); post = I18n.t('ruby_postfix')
644
+ if @book.htmlversion == 5
645
+ "<ruby>#{escaped_word}<rp>#{pre}</rp><rt>#{escaped_yomi}</rt><rp>#{post}</rp></ruby>"
646
+ else
647
+ "<ruby><rb>#{escaped_word}</rb><rp>#{pre}</rp><rt>#{escaped_yomi}</rt><rp>#{post}</rp></ruby>"
648
+ end
649
+ end
650
+
651
+ ## その他
652
+
653
+ def inline_nop(str)
654
+ str || ''
655
+ end
656
+ alias inline_letitgo inline_nop
657
+
658
+ end
659
+
660
+
661
+ end