review-peg 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rubocop.yml +47 -0
  4. data/.rubocop_todo.yml +605 -0
  5. data/.travis.yml +18 -0
  6. data/COPYING +515 -0
  7. data/ChangeLog +2449 -0
  8. data/Dockerfile +22 -0
  9. data/Gemfile +6 -0
  10. data/README.rdoc +81 -0
  11. data/Rakefile +51 -0
  12. data/bin/review-catalog-converter-peg +129 -0
  13. data/bin/review-check-peg +169 -0
  14. data/bin/review-checkdep-peg +63 -0
  15. data/bin/review-compile-peg +202 -0
  16. data/bin/review-epubmaker-legacy-peg +1024 -0
  17. data/bin/review-epubmaker-peg +44 -0
  18. data/bin/review-index-peg +110 -0
  19. data/bin/review-init-peg +151 -0
  20. data/bin/review-pdfmaker-peg +18 -0
  21. data/bin/review-preproc-peg +131 -0
  22. data/bin/review-validate-peg +51 -0
  23. data/bin/review-vol-peg +100 -0
  24. data/debian/README.Debian +12 -0
  25. data/debian/README.source +5 -0
  26. data/debian/changelog +5 -0
  27. data/debian/compat +1 -0
  28. data/debian/control +22 -0
  29. data/debian/copyright +62 -0
  30. data/debian/docs +6 -0
  31. data/debian/manpage.1.ex +59 -0
  32. data/debian/patches/path.diff +91 -0
  33. data/debian/patches/series +1 -0
  34. data/debian/review.install +13 -0
  35. data/debian/review.links +4 -0
  36. data/debian/rules +13 -0
  37. data/debian/source/format +1 -0
  38. data/doc/NEWS.ja.md +350 -0
  39. data/doc/NEWS.md +354 -0
  40. data/doc/catalog.ja.md +53 -0
  41. data/doc/catalog.md +52 -0
  42. data/doc/format.ja.md +734 -0
  43. data/doc/format.md +746 -0
  44. data/doc/format_idg.ja.md +203 -0
  45. data/doc/quickstart.ja.md +222 -0
  46. data/doc/quickstart.md +252 -0
  47. data/doc/ruby-uuid/README +11 -0
  48. data/doc/ruby-uuid/README.ja +34 -0
  49. data/doc/sample.css +108 -0
  50. data/doc/sample.yml +238 -0
  51. data/lib/epubmaker.rb +24 -0
  52. data/lib/epubmaker/content.rb +93 -0
  53. data/lib/epubmaker/epubcommon.rb +424 -0
  54. data/lib/epubmaker/epubv2.rb +139 -0
  55. data/lib/epubmaker/epubv3.rb +222 -0
  56. data/lib/epubmaker/producer.rb +330 -0
  57. data/lib/lineinput.rb +107 -0
  58. data/lib/review.rb +3 -0
  59. data/lib/review/book.rb +43 -0
  60. data/lib/review/book/base.rb +401 -0
  61. data/lib/review/book/chapter.rb +100 -0
  62. data/lib/review/book/compilable.rb +184 -0
  63. data/lib/review/book/image_finder.rb +71 -0
  64. data/lib/review/book/index.rb +413 -0
  65. data/lib/review/book/page_metric.rb +47 -0
  66. data/lib/review/book/part.rb +54 -0
  67. data/lib/review/book/volume.rb +67 -0
  68. data/lib/review/builder.rb +452 -0
  69. data/lib/review/catalog.rb +52 -0
  70. data/lib/review/compiler.rb +5183 -0
  71. data/lib/review/compiler/literals_1_9.kpeg +22 -0
  72. data/lib/review/compiler/literals_1_9.rb +435 -0
  73. data/lib/review/configure.rb +64 -0
  74. data/lib/review/epubbuilder.rb +18 -0
  75. data/lib/review/epubmaker.rb +480 -0
  76. data/lib/review/ewbbuilder.rb +381 -0
  77. data/lib/review/exception.rb +21 -0
  78. data/lib/review/extentions.rb +4 -0
  79. data/lib/review/extentions/array.rb +25 -0
  80. data/lib/review/extentions/object.rb +9 -0
  81. data/lib/review/extentions/string.rb +33 -0
  82. data/lib/review/htmlbuilder.rb +1166 -0
  83. data/lib/review/htmllayout.rb +41 -0
  84. data/lib/review/htmltoc.rb +45 -0
  85. data/lib/review/htmlutils.rb +90 -0
  86. data/lib/review/i18n.rb +96 -0
  87. data/lib/review/i18n.yml +169 -0
  88. data/lib/review/idgxmlbuilder.rb +1233 -0
  89. data/lib/review/inaobuilder.rb +357 -0
  90. data/lib/review/latexbuilder.rb +941 -0
  91. data/lib/review/latexindex.rb +35 -0
  92. data/lib/review/latexutils.rb +95 -0
  93. data/lib/review/layout.tex.erb +340 -0
  94. data/lib/review/lineinput.rb +17 -0
  95. data/lib/review/location.rb +24 -0
  96. data/lib/review/makerhelper.rb +67 -0
  97. data/lib/review/markdownbuilder.rb +339 -0
  98. data/lib/review/node.rb +288 -0
  99. data/lib/review/pdfmaker.rb +332 -0
  100. data/lib/review/preprocessor.rb +530 -0
  101. data/lib/review/review.kpeg +745 -0
  102. data/lib/review/sec_counter.rb +69 -0
  103. data/lib/review/template.rb +21 -0
  104. data/lib/review/textbuilder.rb +17 -0
  105. data/lib/review/textutils.rb +16 -0
  106. data/lib/review/tocparser.rb +348 -0
  107. data/lib/review/tocprinter.rb +205 -0
  108. data/lib/review/topbuilder.rb +796 -0
  109. data/lib/review/unfold.rb +138 -0
  110. data/lib/review/version.rb +3 -0
  111. data/lib/uuid.rb +312 -0
  112. data/review.gemspec +32 -0
  113. data/templates/html/layout-html5.html.erb +17 -0
  114. data/templates/html/layout-xhtml1.html.erb +20 -0
  115. data/templates/ncx/epubv2.ncx.erb +11 -0
  116. data/templates/opf/epubv2.opf.erb +21 -0
  117. data/templates/opf/epubv3.opf.erb +18 -0
  118. data/templates/xml/container.xml.erb +6 -0
  119. data/test/CHAPS +2 -0
  120. data/test/assets/test.xml.erb +3 -0
  121. data/test/assets/test_template.tex +255 -0
  122. data/test/assets/test_template_backmatter.tex +32 -0
  123. data/test/bib.re +13 -0
  124. data/test/book_test_helper.rb +35 -0
  125. data/test/sample-book/README.md +7 -0
  126. data/test/sample-book/src/Rakefile +58 -0
  127. data/test/sample-book/src/_cover.html +3 -0
  128. data/test/sample-book/src/catalog.yml +10 -0
  129. data/test/sample-book/src/ch01.re +71 -0
  130. data/test/sample-book/src/ch02.re +3 -0
  131. data/test/sample-book/src/config.yml +186 -0
  132. data/test/sample-book/src/images/ch01-imgsample.jpg +0 -0
  133. data/test/sample-book/src/images/cover.jpg +0 -0
  134. data/test/sample-book/src/preface.re +15 -0
  135. data/test/sample-book/src/sty/jumoline.sty +310 -0
  136. data/test/sample-book/src/sty/reviewmacro.sty +39 -0
  137. data/test/sample-book/src/style.css +251 -0
  138. data/test/sample-book/src/vendor/jumoline/README +29 -0
  139. data/test/sample-book/src/vendor/jumoline/jumoline.dtx +2988 -0
  140. data/test/sample-book/src/vendor/jumoline/jumoline.ins +6 -0
  141. data/test/test.re +43 -0
  142. data/test/test_book.rb +556 -0
  143. data/test/test_book_chapter.rb +280 -0
  144. data/test/test_book_part.rb +54 -0
  145. data/test/test_builder.rb +80 -0
  146. data/test/test_catalog.rb +119 -0
  147. data/test/test_catalog_converter_cmd.rb +73 -0
  148. data/test/test_compiler.rb +92 -0
  149. data/test/test_configure.rb +50 -0
  150. data/test/test_epub3maker.rb +529 -0
  151. data/test/test_epubmaker.rb +569 -0
  152. data/test/test_epubmaker_cmd.rb +40 -0
  153. data/test/test_helper.rb +92 -0
  154. data/test/test_htmlbuilder.rb +1114 -0
  155. data/test/test_htmltoc.rb +32 -0
  156. data/test/test_htmlutils.rb +50 -0
  157. data/test/test_i18n.rb +180 -0
  158. data/test/test_idgxmlbuilder.rb +608 -0
  159. data/test/test_image_finder.rb +82 -0
  160. data/test/test_inaobuilder.rb +245 -0
  161. data/test/test_index.rb +174 -0
  162. data/test/test_latexbuilder.rb +732 -0
  163. data/test/test_lineinput.rb +182 -0
  164. data/test/test_makerhelper.rb +66 -0
  165. data/test/test_markdownbuilder.rb +125 -0
  166. data/test/test_pdfmaker.rb +171 -0
  167. data/test/test_pdfmaker_cmd.rb +40 -0
  168. data/test/test_preprocessor.rb +23 -0
  169. data/test/test_review_ext.rb +31 -0
  170. data/test/test_template.rb +26 -0
  171. data/test/test_textutils.rb +32 -0
  172. data/test/test_topbuilder.rb +291 -0
  173. data/test/test_uuid.rb +157 -0
  174. metadata +357 -0
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2009 Narihiro Nakamura <authornari@gmail.com>
2
+ require 'erb'
3
+
4
+ class HTMLLayout
5
+ include ERB::Util
6
+
7
+ def initialize(params, template)
8
+ @body = params['body']
9
+ @title = params['title']
10
+ @toc = params['toc']
11
+ @next = params['next']
12
+ @prev = params['prev']
13
+ @builder = params['builder']
14
+ @template = template
15
+ end
16
+ attr_reader :body, :title, :toc
17
+
18
+ def next_chapter
19
+ if @next.present?
20
+ "<a href='#{h @next.id}.html'>#{h @builder.compile_inline @next.title}</a>"
21
+ else
22
+ ""
23
+ end
24
+ end
25
+
26
+ def prev_chapter
27
+ if @prev.present?
28
+ "<a href='#{h @prev.id}.html'>#{h @builder.compile_inline @prev.title}</a>"
29
+ else
30
+ ""
31
+ end
32
+ end
33
+
34
+ def result
35
+ if File.exist?(@template)
36
+ return ERB.new(IO.read(@template)).result(binding)
37
+ else
38
+ return @src
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ require 'review'
2
+ module ReVIEW
3
+ class HTMLToc
4
+ def initialize(basedir)
5
+ @tochtmltxt = "toc-html.txt"
6
+ @basedir = basedir
7
+ end
8
+
9
+ def add_item(level, filename, title, args)
10
+ args_str = encode_args(args)
11
+ line = [level, filename, title, args_str].join("\t")
12
+ File.open(tocfilename, "a") do |f|
13
+ f.write "#{line}\n"
14
+ end
15
+ end
16
+
17
+ def each_item
18
+ File.open(tocfilename) do |f|
19
+ f.each_line do |line|
20
+ level, file, title, args_str = line.chomp.split("\t")
21
+ args = decode_args(args_str)
22
+ yield level, file, title, args
23
+ end
24
+ end
25
+ end
26
+
27
+ def tocfilename
28
+ File.join(@basedir, @tochtmltxt)
29
+ end
30
+
31
+ def decode_args(args_str)
32
+ args = Hash.new
33
+ args_str.split(/,\s*/).each do |pair|
34
+ key, val = pair.split("=")
35
+ args[key.to_sym] = val
36
+ end
37
+ args
38
+ end
39
+
40
+ def encode_args(args)
41
+ args.map{|k,v| "#{k}=#{v}"}.join(",")
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,90 @@
1
+ #
2
+ # $Id: htmlutils.rb 2227 2006-05-13 00:09:08Z aamine $
3
+ #
4
+ # Copyright (c) 2002-2006 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ module ReVIEW
12
+
13
+ module HTMLUtils
14
+ ESC = {
15
+ '&' => '&amp;',
16
+ '<' => '&lt;',
17
+ '>' => '&gt;',
18
+ '"' => '&quot;'
19
+ }
20
+
21
+ def escape_html(str)
22
+ t = ESC
23
+ str.gsub(/[&"<>]/) {|c| t[c] }
24
+ end
25
+
26
+ alias_method :escape, :escape_html
27
+
28
+ def unescape_html(str)
29
+ # FIXME better code
30
+ str.gsub('&quot;', '"').gsub('&gt;', '>').gsub('&lt;', '<').gsub('&amp;', '&')
31
+ end
32
+
33
+ alias_method :unescape, :unescape_html
34
+
35
+ def strip_html(str)
36
+ str.gsub(/<\/?[^>]*>/, "")
37
+ end
38
+
39
+ def escape_comment(str)
40
+ str.gsub('-', '&#45;')
41
+ end
42
+
43
+ def highlight?
44
+ @book.config["pygments"].present? ||
45
+ @book.config["highlight"] && @book.config["highlight"]["html"] == "pygments"
46
+ end
47
+
48
+ def highlight(ops)
49
+ body = ops[:body] || ''
50
+ if @book.config["highlight"] && @book.config["highlight"]["lang"]
51
+ lexer = @book.config["highlight"]["lang"] # default setting
52
+ else
53
+ lexer = 'text'
54
+ end
55
+ lexer = ops[:lexer] if ops[:lexer].present?
56
+ format = ops[:format] || ''
57
+ options = {:nowrap => true, :noclasses => true}
58
+ if ops[:options] && ops[:options].kind_of?(Hash)
59
+ options.merge!(ops[:options])
60
+ end
61
+ return body if !highlight?
62
+
63
+ begin
64
+ require 'pygments'
65
+ begin
66
+ Pygments.highlight(
67
+ unescape_html(body),
68
+ :options => options,
69
+ :formatter => format,
70
+ :lexer => lexer)
71
+ rescue MentosError
72
+ body
73
+ end
74
+ rescue LoadError
75
+ body
76
+ end
77
+ end
78
+
79
+ def normalize_id(id)
80
+ if id =~ /\A[a-z][a-z0-9_.-]*\Z/i
81
+ return id
82
+ elsif id =~ /\A[0-9_.-][a-z0-9_.-]*\Z/i
83
+ return "id_#{id}" # dummy prefix
84
+ else
85
+ return "id_#{CGI.escape(id.gsub("_", "__")).gsub("%", "_").gsub("+", "-")}" # escape all
86
+ end
87
+ end
88
+ end
89
+
90
+ end # module ReVIEW
@@ -0,0 +1,96 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'yaml'
3
+
4
+ module ReVIEW
5
+ class I18n
6
+ def self.setup(locale="ja", ymlfile = "locale.yml")
7
+ @i18n = ReVIEW::I18n.new(locale)
8
+
9
+ lfile = nil
10
+ if ymlfile
11
+ lfile = File.expand_path(ymlfile, Dir.pwd)
12
+
13
+ # backward compatibility
14
+ if !File.exist?(lfile) && (ymlfile == "locale.yml")
15
+ lfile = File.expand_path("locale.yaml", Dir.pwd)
16
+ end
17
+ end
18
+
19
+ if lfile && File.file?(lfile)
20
+ @i18n.update_localefile(lfile)
21
+ end
22
+ end
23
+
24
+ def self.i18n(*args)
25
+ raise NotImplementedError, "I18n.i18n is obsoleted. Please use I18n.setup(locale, [ymlfile])"
26
+ end
27
+
28
+ def self.t(str, args = nil)
29
+ @i18n.t(str, args)
30
+ end
31
+
32
+ def self.locale=(locale)
33
+ if @i18n
34
+ @i18n.locale = locale
35
+ else
36
+ I18n.setup(locale)
37
+ end
38
+ end
39
+
40
+ class << self
41
+ alias_method :v, :t ## for EPUBMaker backward compatibility
42
+ end
43
+
44
+ def self.update(user_i18n, locale = nil)
45
+ @i18n.update(user_i18n, locale)
46
+ end
47
+
48
+ attr_accessor :locale
49
+
50
+ def initialize(locale = nil)
51
+ @locale = locale
52
+ load_default
53
+ end
54
+
55
+ def load_default
56
+ load_file(File.expand_path "i18n.yml", File.dirname(__FILE__))
57
+ end
58
+
59
+ def load_file(path)
60
+ @store = YAML.load_file(path)
61
+ end
62
+
63
+ def update_localefile(path)
64
+ user_i18n = YAML.load_file(path)
65
+ locale = user_i18n["locale"]
66
+ if locale
67
+ user_i18n.delete("locale")
68
+ if @store[locale]
69
+ @store[locale].merge!(user_i18n)
70
+ else
71
+ @store[locale] = user_i18n
72
+ end
73
+ else
74
+ user_i18n.each do |key, values|
75
+ raise KeyError, "Invalid locale file: #{path}" unless values.kind_of? Hash
76
+ @store[key].merge!(values)
77
+ end
78
+ end
79
+ end
80
+
81
+ def update(user_i18n, locale = nil)
82
+ locale ||= @locale
83
+ if @store[locale]
84
+ @store[locale].merge!(user_i18n)
85
+ else
86
+ @store[locale] = user_i18n
87
+ end
88
+ end
89
+
90
+ def t(str, args = nil)
91
+ @store[@locale][str] % args
92
+ rescue
93
+ str
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,169 @@
1
+ ja:
2
+ image: 図
3
+ table: 表
4
+ list: リスト
5
+ column: "コラム「%s」"
6
+ columnname: "コラム"
7
+ column_head: "■コラム"
8
+ part: 第%d部
9
+ chapter: 第%d章
10
+ chapter_postfix: " "
11
+ chapter_quote: "「%s」"
12
+ appendix: 付録%s
13
+ numberless_image: "図:"
14
+ memo_head: ■メモ
15
+ format_number: "%s.%d"
16
+ format_number_header: "%s.%d:"
17
+ format_number_without_chapter: "%d"
18
+ format_number_header_without_chapter: "%d:"
19
+ image_quote: "「%s」"
20
+ caption_prefix: " "
21
+ caption_prefix_idgxml: " "
22
+ ruby_prefix: "("
23
+ ruby_postfix: ")"
24
+ label_marker: "●● "
25
+ aut: "著 者"
26
+ csl: "監 修"
27
+ dsr: "デザイン"
28
+ ill: "イラスト"
29
+ cov: "表 紙"
30
+ edt: "編 集"
31
+ pht: "撮 影"
32
+ trl: "翻 訳"
33
+ ## XXX Backward Compatibility: `prt` should be "印刷所"
34
+ prt: "発行所"
35
+ pbl: "発行所"
36
+ contact: "連絡先"
37
+ author_with_label: "%s 著"
38
+ supervisor_with_label: "%s 監修"
39
+ translator_with_label: "%s 訳"
40
+ names_splitter: "、"
41
+ edition: "版"
42
+ nth_edition: "第%s版"
43
+ first_edition: "初版"
44
+ nth_impression: "第%s刷"
45
+ published_by: "%s 発行"
46
+ published_by1: "%s %s 発行"
47
+ published_by2: "%s 発行"
48
+ published_by3: "%s %s"
49
+ date_format: '%%Y年%%-m月%%-d日'
50
+ toctitle: "目次"
51
+ covertitle: "表紙"
52
+ titlepagetitle: "大扉"
53
+ originaltitle: "原書大扉"
54
+ credittitle: "クレジット"
55
+ colophontitle: "奥付"
56
+ advtitle: "広告"
57
+ profiletitle: "著者紹介"
58
+ backcovertitle: "裏表紙"
59
+
60
+ en:
61
+ image: "Figure "
62
+ table: "Table "
63
+ list: "List "
64
+ column: "Column %s"
65
+ columnname: "Column"
66
+ column_head: "Column"
67
+ part: "Part %s"
68
+ chapter: Chapter %d
69
+ chapter_postfix: ". "
70
+ chapter_quote: '"%s"'
71
+ appendix: Appendix %s
72
+ numberless_image: "Figure:"
73
+ memo_head: Note
74
+ format_number: "%s.%d"
75
+ format_number_header: "%s.%d:"
76
+ format_number_without_chapter: "%d"
77
+ format_number_header_without_chapter: "%d:"
78
+ image_quote: '"%s"'
79
+ caption_prefix: " "
80
+ caption_prefix_idgxml: " "
81
+ ruby_prefix: "("
82
+ ruby_postfix: ")"
83
+ label_marker: "●● "
84
+ aut: "Author"
85
+ csl: "Consultant"
86
+ dsr: "Design"
87
+ ill: "Illustrator"
88
+ cov: "Cover"
89
+ edt: "Editor"
90
+ pht: "Director of Photography"
91
+ trl: "Translator"
92
+ prt: "Printer"
93
+ pbl: "Publisher"
94
+ contact: "Contact"
95
+ author_with_label: "Author: %s"
96
+ supervisor_with_label: "Supervisor: %s"
97
+ translator_with_label: "Translator: %s"
98
+ names_splitter: ", "
99
+ edition: "edition"
100
+ impression: "impression"
101
+ nth_edition: "%s edition"
102
+ first_edition: "first edition"
103
+ nth_impression: "%s impression"
104
+ published_by: "%s"
105
+ published_by1: "published by %s %s"
106
+ published_by2: "published by %s"
107
+ published_by3: "%s %s"
108
+ date_format: '%%b. %%e, %%Y'
109
+ toctitle: "Table of Contents"
110
+ covertitle: "Cover"
111
+ titlepagetitle: "Title Page"
112
+ originaltitle: "Title Page of Original"
113
+ credittitle: "Credit"
114
+ colophontitle: "Colophon"
115
+ advtitle: "Advertisement"
116
+ profiletitle: "Profile"
117
+ backcovertitle: "Back Cover"
118
+
119
+ zh-TW:
120
+ image: 圖
121
+ table: 表
122
+ list: List
123
+ part: 第%d部份
124
+ chapter: 第%d章
125
+ chapter_postfix: " "
126
+ chapter_quote: "「%s」"
127
+ appendix: 附錄%s
128
+ numberless_image: "圖:"
129
+ format_number: "%s.%d"
130
+ format_number_header: "%s.%d:"
131
+ format_number_without_chapter: "%d"
132
+ format_number_header_without_chapter: "%d:"
133
+ image_quote: '"%s"'
134
+ caption_prefix: " "
135
+ caption_prefix_idgxml: " "
136
+ ruby_prefix: "("
137
+ ruby_postfix: ")"
138
+ label_marker: "●● "
139
+ aut: "著作人"
140
+ csl: "監 修"
141
+ dsr: "美術編輯"
142
+ ill: "插 畫"
143
+ cov: "封面設計"
144
+ edt: "編 輯"
145
+ pht: "攝 影"
146
+ trl: "翻 譯"
147
+ prt: "印刷所"
148
+ pbl: "發行所"
149
+ contact: "联系方式"
150
+ author_with_label: "%s 著"
151
+ supervisor_with_label: "%s 監修"
152
+ translator_with_label: "%s 譯"
153
+ names_splitter: ", "
154
+ edition: "版"
155
+ published_by: "%s 出版"
156
+ published_by1: "%s %s 出版"
157
+ published_by2: "%s 出版"
158
+ published_by3: "%s %s"
159
+ date_format: '%%Y年%%-m月%%-d日'
160
+ impression: "刷"
161
+ toctitle: "目次"
162
+ covertitle: "封面"
163
+ titlepagetitle: "標題頁"
164
+ originaltitle: "原標題頁"
165
+ credittitle: "Credit"
166
+ colophontitle: "版權頁"
167
+ advtitle: "廣告"
168
+ profiletitle: "作者介紹"
169
+ backcovertitle: "封底"
@@ -0,0 +1,1233 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2002-2007 Minero Aoki
4
+ # 2008-2014 Minero Aoki, Kenshi Muto
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ require 'review/builder'
12
+ require 'review/htmlutils'
13
+ require 'review/textutils'
14
+ require 'nkf'
15
+
16
+ module ReVIEW
17
+
18
+ class IDGXMLBuilder < Builder
19
+
20
+ include TextUtils
21
+ include HTMLUtils
22
+
23
+ [:ttbold, :hint, :maru, :keytop, :labelref, :ref, :pageref, :balloon].each {|e| Compiler.definline(e) }
24
+ Compiler.defsingle(:dtp, 1)
25
+
26
+ Compiler.defcodeblock(:insn, 1)
27
+ Compiler.defblock(:memo, 0..1)
28
+ Compiler.defblock(:tip, 0..1)
29
+ Compiler.defblock(:info, 0..1)
30
+ Compiler.defblock(:planning, 0..1)
31
+ Compiler.defblock(:best, 0..1)
32
+ Compiler.defblock(:important, 0..1)
33
+ Compiler.defblock(:security, 0..1)
34
+ Compiler.defblock(:caution, 0..1)
35
+ Compiler.defblock(:notice, 0..1)
36
+ Compiler.defblock(:point, 0..1)
37
+ Compiler.defblock(:shoot, 0..1)
38
+ Compiler.defblock(:reference, 0)
39
+ Compiler.defblock(:term, 0)
40
+ Compiler.defblock(:link, 0..1)
41
+ Compiler.defblock(:practice, 0)
42
+ Compiler.defblock(:expert, 0)
43
+ Compiler.defblock(:rawblock, 0)
44
+
45
+ def extname
46
+ '.xml'
47
+ end
48
+
49
+ def builder_init(no_error = false)
50
+ @no_error = no_error
51
+ end
52
+ private :builder_init
53
+
54
+ def builder_init_file
55
+ @warns = []
56
+ @errors = []
57
+ @section = 0
58
+ @subsection = 0
59
+ @subsubsection = 0
60
+ @subsubsubsection = 0
61
+ @sec_counter = SecCounter.new(5, @chapter)
62
+ @column = 0
63
+ @noindent = nil
64
+ @rootelement = "doc"
65
+ @secttags = nil
66
+ @tsize = nil
67
+ @texblockequation = 0
68
+ @texinlineequation = 0
69
+
70
+ @output << %Q(<?xml version="1.0" encoding="UTF-8"?>\n)
71
+ @output << %Q(<#{@rootelement} xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/">)
72
+ if @book.config["nolf"].present?
73
+ @lf = ""
74
+ else
75
+ @lf = "\n"
76
+ end
77
+ @secttags = true unless @book.config["structuredxml"].nil?
78
+ end
79
+ private :builder_init_file
80
+
81
+ def result
82
+ s = ""
83
+ unless @secttags.nil?
84
+ s += "</sect4>" if @subsubsubsection > 0
85
+ s += "</sect3>" if @subsubsection > 0
86
+ s += "</sect2>" if @subsection > 0
87
+ s += "</sect>" if @section > 0
88
+ s += "</chapter>" if @chapter.number > 0
89
+ end
90
+ messages() + @output.string + s + "</#{@rootelement}>\n"
91
+ end
92
+
93
+ def warn(msg)
94
+ if @no_error
95
+ @warns.push [@location.filename, @location.lineno, msg]
96
+ buf << "----WARNING: #{escape_html(msg)}----" << @lf
97
+ else
98
+ $stderr.puts "#{@location}: warning: #{msg}"
99
+ end
100
+ end
101
+
102
+ def error(msg)
103
+ if @no_error
104
+ @errors.push [@location.filename, @location.lineno, msg]
105
+ buf << "----ERROR: #{escape_html(msg)}----" << @lf
106
+ else
107
+ $stderr.puts "#{@location}: error: #{msg}"
108
+ end
109
+ end
110
+
111
+ def messages
112
+ error_messages() + warning_messages()
113
+ end
114
+
115
+ def error_messages
116
+ return '' if @errors.empty?
117
+ "<h2>Syntax Errors</h2>\n" +
118
+ "<ul>\n" +
119
+ @errors.map {|file, line, msg|
120
+ "<li>#{escape_html(file)}:#{line}: #{escape_html(msg.to_s)}</li>\n"
121
+ }.join('') +
122
+ "</ul>\n"
123
+ end
124
+
125
+ def warning_messages
126
+ return '' if @warns.empty?
127
+ "<h2>Warnings</h2>\n" +
128
+ "<ul>\n" +
129
+ @warns.map {|file, line, msg|
130
+ "<li>#{escape_html(file)}:#{line}: #{escape_html(msg)}</li>\n"
131
+ }.join('') +
132
+ "</ul>\n"
133
+ end
134
+
135
+ def headline(level, label, caption)
136
+ buf = ""
137
+ case level
138
+ when 1
139
+ unless @secttags.nil?
140
+ buf << "</sect4>" if @subsubsubsection > 0
141
+ buf << "</sect3>" if @subsubsection > 0
142
+ buf << "</sect2>" if @subsection > 0
143
+ buf << "</sect>" if @section > 0
144
+ end
145
+ buf << %Q(<chapter id="chap:#{@chapter.number}">) unless @secttags.nil?
146
+ @section = 0
147
+ @subsection = 0
148
+ @subsubsection = 0
149
+ @subsubsubsection = 0
150
+ when 2
151
+ unless @secttags.nil?
152
+ buf << "</sect4>" if @subsubsubsection > 0
153
+ buf << "</sect3>" if @subsubsection > 0
154
+ buf << "</sect2>" if @subsection > 0
155
+ buf << "</sect>" if @section > 0
156
+ end
157
+ @section += 1
158
+ buf << %Q(<sect id="sect:#{@chapter.number}.#{@section}">) unless @secttags.nil?
159
+ @subsection = 0
160
+ @subsubsection = 0
161
+ @subsubsubsection = 0
162
+ when 3
163
+ unless @secttags.nil?
164
+ buf << "</sect4>" if @subsubsubsection > 0
165
+ buf << "</sect3>" if @subsubsection > 0
166
+ buf << "</sect2>" if @subsection > 0
167
+ end
168
+ @subsection += 1
169
+ buf << %Q(<sect2 id="sect:#{@chapter.number}.#{@section}.#{@subsection}">) unless @secttags.nil?
170
+ @subsubsection = 0
171
+ @subsubsubsection = 0
172
+ when 4
173
+ unless @secttags.nil?
174
+ buf << "</sect4>" if @subsubsubsection > 0
175
+ buf << "</sect3>" if @subsubsection > 0
176
+ end
177
+ @subsubsection += 1
178
+ buf << %Q(<sect3 id="sect:#{@chapter.number}.#{@section}.#{@subsection}.#{@subsubsection}">) unless @secttags.nil?
179
+ @subsubsubsection = 0
180
+ when 5
181
+ unless @secttags.nil?
182
+ buf << "</sect4>" if @subsubsubsection > 0
183
+ end
184
+
185
+ @subsubsubsection += 1
186
+ buf << %Q(<sect4 id="sect:#{@chapter.number}.#{@section}.#{@subsection}.#{@subsubsection}.#{@subsubsubsection}">) unless @secttags.nil?
187
+ else
188
+ raise "caption level too deep or unsupported: #{level}"
189
+ end
190
+
191
+ prefix, anchor = headline_prefix(level)
192
+
193
+ label = label.nil? ? "" : " id=\"#{label}\""
194
+ toccaption = escape_html(caption.gsub(/@<fn>\{.+?\}/, '').gsub(/<[^>]+>/, ''))
195
+ buf << %Q(<title#{label} aid:pstyle="h#{level}">#{prefix}#{caption}</title><?dtp level="#{level}" section="#{prefix}#{toccaption}"?>) << @lf
196
+
197
+ buf
198
+ end
199
+
200
+ def ul_begin
201
+ level = block_given? ? yield : ""
202
+ level = nil if level == 1
203
+ "<ul#{level == 1 ? nil : level}>" + @lf
204
+ end
205
+
206
+ def ul_item(lines)
207
+ %Q(<li aid:pstyle="ul-item">#{lines.join.chomp}</li>) + @lf
208
+ end
209
+
210
+ def ul_item_begin(lines)
211
+ %Q(<li aid:pstyle="ul-item">#{lines.join.chomp})
212
+ end
213
+
214
+ def ul_item_end
215
+ "</li>" + @lf
216
+ end
217
+
218
+ def choice_single_begin
219
+ "<choice type='single'>" + @lf
220
+ end
221
+
222
+ def choice_multi_begin
223
+ "<choice type='multi'>" + @lf
224
+ end
225
+
226
+ def choice_single_end
227
+ "</choice>" + @lf
228
+ end
229
+
230
+ def choice_multi_end
231
+ "</choice>" + @lf
232
+ end
233
+
234
+ def ul_end
235
+ level = block_given? ? yield : ""
236
+ level = nil if level == 1
237
+ "</ul#{level}>" + @lf
238
+ end
239
+
240
+ def ol_begin
241
+ if !@ol_num
242
+ @ol_num = 1
243
+ end
244
+ '<ol>' + @lf
245
+ end
246
+
247
+ def ol_item(lines, num)
248
+ buf = %Q(<li aid:pstyle="ol-item" olnum="#{@ol_num}" num="#{num}">#{lines.join.chomp}</li>) + @lf
249
+ @ol_num += 1
250
+ buf
251
+ end
252
+
253
+ def ol_end
254
+ @ol_num = nil
255
+ '</ol>' + @lf
256
+ end
257
+
258
+ def olnum(num)
259
+ @ol_num = num.to_i
260
+ end
261
+
262
+ def dl_begin
263
+ '<dl>' + @lf
264
+ end
265
+
266
+ def dt(line)
267
+ "<dt>#{line}</dt>" + @lf
268
+ end
269
+
270
+ def dd(lines)
271
+ "<dd>#{lines.join.chomp}</dd>" + @lf
272
+ end
273
+
274
+ def dl_end
275
+ '</dl>' + @lf
276
+ end
277
+
278
+ def paragraph(lines)
279
+ buf = ""
280
+ if @noindent.nil?
281
+ if lines[0] =~ /\A(\t+)/
282
+ buf << %Q(<p inlist="#{$1.size}">#{lines.join('').sub(/\A\t+/, "")}</p>) << @lf
283
+ else
284
+ buf << "<p>#{lines.join}</p>" << @lf
285
+ end
286
+ else
287
+ buf << %Q(<p aid:pstyle="noindent" noindent='1'>#{lines.join}</p>) << @lf
288
+ @noindent = nil
289
+ end
290
+ buf
291
+ end
292
+
293
+ def read(lines)
294
+ if @book.config["deprecated-blocklines"].nil?
295
+ %Q[<lead>#{lines.join}</lead>] + @lf
296
+ else
297
+ str = lines.map{|l| l.sub(/^<p>/,"").sub(/<\/p>$/,"")}.join()
298
+ %Q[<p aid:pstyle="lead">#{str}</p>] + @lf
299
+ end
300
+ end
301
+
302
+ alias_method :lead, :read
303
+
304
+ def column_label(id)
305
+ num = @chapter.column(id).number
306
+ "column-#{num}"
307
+ end
308
+ private :column_label
309
+
310
+ def inline_column(id)
311
+ if @book.config["chapterlink"]
312
+ %Q(<link href="#{column_label(id)}">#{escape_html(@chapter.column(id).caption)}</link>)
313
+ else
314
+ escape_html(@chapter.column(id).caption)
315
+ end
316
+ rescue KeyError
317
+ error "unknown column: #{id}"
318
+ nofunc_text("[UnknownColumn:#{id}]")
319
+ end
320
+
321
+ def inline_list(id)
322
+ chapter, id = extract_chapter_id(id)
323
+ if get_chap(chapter).nil?
324
+ "<span type='list'>#{I18n.t("list")}#{I18n.t("format_number_without_chapter", [chapter.list(id).number])}</span>"
325
+ else
326
+ "<span type='list'>#{I18n.t("list")}#{I18n.t("format_number", [get_chap(chapter), chapter.list(id).number])}</span>"
327
+ end
328
+ end
329
+
330
+ def list_header(id, caption, lang)
331
+ buf = ""
332
+ buf << %Q[<codelist>] << @lf
333
+ if get_chap.nil?
334
+ buf << %Q[<caption>#{I18n.t("list")}#{I18n.t("format_number_without_chapter", [@chapter.list(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] << @lf
335
+ else
336
+ buf << %Q[<caption>#{I18n.t("list")}#{I18n.t("format_number", [get_chap, @chapter.list(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] << @lf
337
+ end
338
+ buf
339
+ end
340
+
341
+ def codelines_body(lines)
342
+ buf = ""
343
+ no = 1
344
+ lines.each do |line|
345
+ unless @book.config["listinfo"].nil?
346
+ buf << "<listinfo line=\"#{no}\""
347
+ buf << " begin=\"1\"" if no == 1
348
+ buf << " end=\"#{no}\"" if no == lines.size
349
+ buf << ">"
350
+ end
351
+ buf << detab(line)
352
+ buf << "\n"
353
+ buf << "</listinfo>" unless @book.config["listinfo"].nil?
354
+ no += 1
355
+ end
356
+ buf
357
+ end
358
+
359
+ def list_body(id, lines, lang)
360
+ buf = ""
361
+ buf << %Q(<pre>)
362
+ buf << codelines_body(lines)
363
+ buf << "</pre></codelist>" << @lf
364
+ buf
365
+ end
366
+
367
+ def emlist(lines, caption = nil, lang = nil)
368
+ quotedlist lines, 'emlist', caption
369
+ end
370
+
371
+ def emlistnum(lines, caption = nil, lang = nil)
372
+ _lines = []
373
+ lines.each_with_index do |line, i|
374
+ line.chomp! ## new parser don't remove LF in table (code block)
375
+ _lines << detab("<span type='lineno'>" + (i + 1).to_s.rjust(2) + ": </span>" + line)
376
+ end
377
+ quotedlist _lines, 'emlistnum', caption
378
+ end
379
+
380
+ def listnum_body(lines, lang)
381
+ buf = ""
382
+ buf << %Q(<pre>)
383
+ no = 1
384
+ lines.each_with_index do |line, i|
385
+ unless @book.config["listinfo"].nil?
386
+ buf << "<listinfo line=\"#{no}\""
387
+ buf << " begin=\"1\"" if no == 1
388
+ buf << " end=\"#{no}\"" if no == lines.size
389
+ buf << ">"
390
+ end
391
+ buf << detab("<span type='lineno'>" + (i + 1).to_s.rjust(2) + ": </span>" + line)
392
+ buf << "\n"
393
+ buf << "</listinfo>" unless @book.config["listinfo"].nil?
394
+ no += 1
395
+ end
396
+ buf << "</pre></codelist>" << @lf
397
+ buf
398
+ end
399
+
400
+ def cmd(lines, caption = nil)
401
+ quotedlist lines, 'cmd', caption
402
+ end
403
+
404
+ def quotedlist(lines, css_class, caption)
405
+ buf = ""
406
+ buf << %Q[<list type='#{css_class}'>]
407
+ buf << "<caption aid:pstyle='#{css_class}-title'>#{caption}</caption>" + @lf unless caption.nil?
408
+ buf << %Q[<pre>]
409
+ no = 1
410
+ lines.each do |line|
411
+ unless @book.config["listinfo"].nil?
412
+ buf << "<listinfo line=\"#{no}\""
413
+ buf << " begin=\"1\"" if no == 1
414
+ buf << " end=\"#{no}\"" if no == lines.size
415
+ buf << ">"
416
+ end
417
+ buf << detab(line)
418
+ buf << "\n"
419
+ buf << "</listinfo>" unless @book.config["listinfo"].nil?
420
+ no += 1
421
+ end
422
+ buf << '</pre></list>' << @lf
423
+ buf
424
+ end
425
+ private :quotedlist
426
+
427
+ def quote(lines)
428
+ if @book.config["deprecated-blocklines"].nil?
429
+ "<quote>#{lines.join("")}</quote>" + @lf
430
+ else
431
+ str = lines.map{|l| l.sub(/^<p>/,"").sub(/<\/p>$/,"")}.join("\n")
432
+ "<quote>#{str}</quote>" + @lf
433
+ end
434
+ end
435
+
436
+ def inline_table(id)
437
+ chapter, id = extract_chapter_id(id)
438
+ if get_chap(chapter).nil?
439
+ "<span type='table'>#{I18n.t("table")}#{I18n.t("format_number_without_chapter", [chapter.table(id).number])}</span>"
440
+ else
441
+ "<span type='table'>#{I18n.t("table")}#{I18n.t("format_number", [get_chap(chapter), chapter.table(id).number])}</span>"
442
+ end
443
+ end
444
+
445
+ def inline_img(id)
446
+ chapter, id = extract_chapter_id(id)
447
+ if get_chap(chapter).nil?
448
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number_without_chapter", [chapter.image(id).number])}</span>"
449
+ else
450
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number", [get_chap(chapter), chapter.image(id).number])}</span>"
451
+ end
452
+ end
453
+
454
+ def inline_imgref(id)
455
+ chapter, id = extract_chapter_id(id)
456
+ if chapter.image(id).caption.blank?
457
+ inline_img(id)
458
+ else
459
+ if get_chap(chapter).nil?
460
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number_without_chapter", [chapter.image(id).number])}#{I18n.t('image_quote', chapter.image(id).caption)}</span>"
461
+ else
462
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number", [get_chap(chapter), chapter.image(id).number])}#{I18n.t('image_quote', chapter.image(id).caption)}</span>"
463
+ end
464
+ end
465
+ end
466
+
467
+ def handle_metric(str)
468
+ k, v = str.split('=', 2)
469
+ return %Q|#{k}=\"#{v.sub(/\A["']/, '').sub(/["']\Z/, '')}\"|
470
+ end
471
+
472
+ def result_metric(array)
473
+ " #{array.join(' ')}"
474
+ end
475
+
476
+ def image_image(id, caption, metric=nil)
477
+ buf = ""
478
+ metrics = parse_metric("idgxml", metric)
479
+ buf << "<img>" << @lf
480
+ buf << %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A.\//, "")}"#{metrics} />] << @lf
481
+ buf << image_header(id, caption)
482
+ buf << "</img>" << @lf
483
+ buf
484
+ end
485
+
486
+ def image_dummy(id, caption, lines)
487
+ buf << "<img>" << @lf
488
+ buf << %Q[<pre aid:pstyle="dummyimage">]
489
+ lines.each do |line|
490
+ buf << detab(line)
491
+ buf << "\n"
492
+ end
493
+ buf << %Q[</pre>]
494
+ image_header id, caption
495
+ buf << "</img>" << @lf
496
+ warn "no such image: #{id}"
497
+ buf
498
+ end
499
+
500
+ def image_header(id, caption)
501
+ if get_chap.nil?
502
+ %Q[<caption>#{I18n.t("image")}#{I18n.t("format_number_without_chapter", [@chapter.image(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] + @lf
503
+ else
504
+ %Q[<caption>#{I18n.t("image")}#{I18n.t("format_number", [get_chap, @chapter.image(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] + @lf
505
+ end
506
+ end
507
+
508
+ def texequation(lines)
509
+ buf = ""
510
+ @texblockequation += 1
511
+ buf << %Q[<replace idref="texblock-#{@texblockequation}">] << @lf
512
+ buf << '<pre>' << @lf
513
+ buf << "#{lines.join("\n")}" << @lf
514
+ buf << '</pre>' << @lf
515
+ buf << '</replace>' << @lf
516
+ end
517
+
518
+ def table(lines, id = nil, caption = nil)
519
+ buf = ""
520
+ tablewidth = nil
521
+ col = 0
522
+ unless @book.config["tableopt"].nil?
523
+ tablewidth = @book.config["tableopt"].split(",")[0].to_f / 0.351 # mm -> pt
524
+ end
525
+ buf << "<table>"
526
+ rows = []
527
+ sepidx = nil
528
+ lines.each_with_index do |line, idx|
529
+ line.chomp! ## new parser don't remove LF in table (code block)
530
+ if /\A[\=\-]{12}/ =~ line
531
+ sepidx ||= idx
532
+ next
533
+ end
534
+ if tablewidth.nil?
535
+ rows.push(line.gsub(/\t\.\t/, "\t\t").gsub(/\t\.\.\t/, "\t.\t").gsub(/\t\.\Z/, "\t").gsub(/\t\.\.\Z/, "\t.").gsub(/\A\./, ""))
536
+ else
537
+ rows.push(line.gsub(/\t\.\t/, "\tDUMMYCELLSPLITTER\t").gsub(/\t\.\.\t/, "\t.\t").gsub(/\t\.\Z/, "\tDUMMYCELLSPLITTER").gsub(/\t\.\.\Z/, "\t.").gsub(/\A\./, ""))
538
+ end
539
+ _col = rows[rows.length - 1].split(/\t/).length
540
+ col = _col if _col > col
541
+ end
542
+
543
+ cellwidth = []
544
+ unless tablewidth.nil?
545
+ if @tsize.nil?
546
+ col.times {|n| cellwidth[n] = tablewidth / col }
547
+ else
548
+ cellwidth = @tsize.split(/\s*,\s*/)
549
+ totallength = 0
550
+ cellwidth.size.times do |n|
551
+ cellwidth[n] = cellwidth[n].to_f / 0.351 # mm -> pt
552
+ totallength += cellwidth[n]
553
+ warn "total length exceeds limit for table: #{id}" if totallength > tablewidth
554
+ end
555
+ if cellwidth.size < col
556
+ cw = (tablewidth - totallength) / (col - cellwidth.size)
557
+ warn "auto cell sizing exceeds limit for table: #{id}" if cw <= 0
558
+ for i in cellwidth.size..(col - 1)
559
+ cellwidth[i] = cw
560
+ end
561
+ end
562
+ end
563
+ end
564
+
565
+ begin
566
+ buf << table_header(id, caption) unless caption.nil?
567
+ rescue KeyError
568
+ error "no such table: #{id}"
569
+ end
570
+ return if rows.empty?
571
+
572
+ if tablewidth.nil?
573
+ buf << "<tbody>"
574
+ else
575
+ buf << %Q[<tbody xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/" aid:table="table" aid:trows="#{rows.length}" aid:tcols="#{col}">]
576
+ end
577
+
578
+ if sepidx
579
+ sepidx.times do |y|
580
+ if tablewidth.nil?
581
+ buf << %Q[<tr type="header">#{rows.shift}</tr>] << @lf
582
+ else
583
+ i = 0
584
+ rows.shift.split(/\t/).each_with_index do |cell, x|
585
+ buf << %Q[<td xyh="#{x + 1},#{y + 1},#{sepidx}" aid:table="cell" aid:theader="1" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
586
+ i += 1
587
+ end
588
+ end
589
+ end
590
+ end
591
+ buf << trputs(tablewidth, rows, cellwidth, sepidx)
592
+ buf << "</tbody></table>" << @lf
593
+ @tsize = nil
594
+ buf
595
+ end
596
+
597
+ def trputs(tablewidth, rows, cellwidth, sepidx)
598
+ buf = ""
599
+ sepidx = 0 if sepidx.nil?
600
+ if tablewidth.nil?
601
+ lastline = rows.pop
602
+ rows.each {|row| buf << %Q[<tr>#{row}</tr>] }
603
+ buf << %Q[<tr type="lastline">#{lastline}</tr>] + @lf unless lastline.nil?
604
+ else
605
+ rows.each_with_index do |row, y|
606
+ i = 0
607
+ row.split(/\t/).each_with_index do |cell, x|
608
+ buf << %Q[<td xyh="#{x + 1},#{y + 1 + sepidx},#{sepidx}" aid:table="cell" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
609
+ i += 1
610
+ end
611
+ end
612
+ end
613
+ buf
614
+ end
615
+
616
+ def table_header(id, caption)
617
+ buf = ""
618
+ if get_chap.nil?
619
+ buf << %Q[<caption>#{I18n.t("table")}#{I18n.t("format_number_without_chapter", [@chapter.table(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] + @lf
620
+ else
621
+ buf << %Q[<caption>#{I18n.t("table")}#{I18n.t("format_number", [get_chap, @chapter.table(id).number])}#{I18n.t("caption_prefix_idgxml")}#{caption}</caption>] + @lf
622
+ end
623
+ buf
624
+ end
625
+
626
+ def table_begin(ncols)
627
+ end
628
+
629
+ def tr(rows)
630
+ %Q[<tr>#{rows.join("\t")}</tr>] + @lf
631
+ end
632
+
633
+ def th(str)
634
+ %Q[<?dtp tablerow header?>#{str}]
635
+ end
636
+
637
+ def td(str)
638
+ str
639
+ end
640
+
641
+ def table_end
642
+ "<?dtp tablerow last?>"
643
+ end
644
+
645
+ def comment(str)
646
+ %Q(<!-- [Comment] #{escape_html(str)} -->)
647
+ end
648
+
649
+ def footnote(id, str)
650
+ # see inline_fn
651
+ end
652
+
653
+ def inline_fn(id)
654
+ %Q[<footnote>#{@chapter.footnote(id).content.strip}</footnote>]
655
+ end
656
+
657
+ def compile_ruby(base, ruby)
658
+ %Q[<GroupRuby><aid:ruby xmlns:aid="http://ns.adobe.com/AdobeInDesign/3.0/"><aid:rb>#{escape_html(base.sub(/\A\s+/, "").sub(/\s+$/, ""))}</aid:rb><aid:rt>#{escape_html(ruby.sub(/\A\s+/, "").sub(/\s+$/, ""))}</aid:rt></aid:ruby></GroupRuby>]
659
+ end
660
+
661
+ def compile_kw(word, alt)
662
+ '<keyword>' +
663
+ if alt
664
+ then
665
+ ("#{word}(#{alt.strip})")
666
+ else
667
+ (word)
668
+ end +
669
+ '</keyword>' +
670
+ %Q[<index value="#{word}" />] +
671
+ if alt
672
+ alt.split(/\s*,\s*/).collect! {|e| %Q[<index value="#{(e.strip)}" />] }.join
673
+ else
674
+ ""
675
+ end
676
+ end
677
+
678
+ def compile_href(url, label)
679
+ %Q[<a linkurl='#{url}'>#{label.nil? ? url : label}</a>]
680
+ end
681
+
682
+ def inline_sup(str)
683
+ %Q[<sup>#{str}</sup>]
684
+ end
685
+
686
+ def inline_sub(str)
687
+ %Q[<sub>#{str}</sub>]
688
+ end
689
+
690
+ def inline_raw(str)
691
+ %Q[#{super(str).gsub("\\n", "\n")}]
692
+ end
693
+
694
+ def inline_hint(str)
695
+ if @book.config["nolf"].nil?
696
+ %Q[\n<hint>#{str}</hint>]
697
+ else
698
+ %Q[<hint>#{str}</hint>]
699
+ end
700
+ end
701
+
702
+ def inline_maru(str)
703
+ if str =~ /\A\d+\Z/
704
+ sprintf("&#x%x;", 9311 + str.to_i)
705
+ elsif str =~ /\A[A-Z]\Z/
706
+ begin
707
+ sprintf("&#x%x;", 9398 + str.codepoints.to_a[0] - 65)
708
+ rescue NoMethodError
709
+ sprintf("&#x%x;", 9398 + str[0] - 65)
710
+ end
711
+ elsif str =~ /\A[a-z]\Z/
712
+ begin
713
+ sprintf("&#x%x;", 9392 + str.codepoints.to_a[0] - 65)
714
+ rescue NoMethodError
715
+ sprintf("&#x%x;", 9392 + str[0] - 65)
716
+ end
717
+ else
718
+ raise "can't parse maru: #{str}"
719
+ end
720
+ end
721
+
722
+ def inline_idx(str)
723
+ %Q(#{str}<index value="#{str}" />)
724
+ end
725
+
726
+ def inline_hidx(str)
727
+ %Q(<index value="#{str}" />)
728
+ end
729
+
730
+ def inline_ami(str)
731
+ %Q(<ami>#{str}</ami>)
732
+ end
733
+
734
+ def inline_i(str)
735
+ %Q(<i>#{str}</i>)
736
+ end
737
+
738
+ def inline_b(str)
739
+ %Q(<b>#{str}</b>)
740
+ end
741
+
742
+ def inline_tt(str)
743
+ %Q(<tt>#{str}</tt>)
744
+ end
745
+
746
+ def inline_ttb(str)
747
+ %Q(<tt style='bold'>#{str}</tt>)
748
+ end
749
+
750
+ alias_method :inline_ttbold, :inline_ttb
751
+
752
+ def inline_tti(str)
753
+ %Q(<tt style='italic'>#{str}</tt>)
754
+ end
755
+
756
+ def inline_u(str)
757
+ %Q(<underline>#{str}</underline>)
758
+ end
759
+
760
+ def inline_icon(id)
761
+ begin
762
+ %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A\.\//, "")}" type="inline" />]
763
+ rescue
764
+ warn "no such icon image: #{id}"
765
+ ""
766
+ end
767
+ end
768
+
769
+ def inline_bou(str)
770
+ %Q[<bou>#{str}</bou>]
771
+ end
772
+
773
+ def inline_keytop(str)
774
+ %Q[<keytop>#{str}</keytop>]
775
+ end
776
+
777
+ def inline_labelref(idref)
778
+ %Q[<ref idref='#{(idref)}'>「#{I18n.t("label_marker")}#{(idref)}」</ref>] # FIXME:節名とタイトルも込みで要出力
779
+ end
780
+
781
+ alias_method :inline_ref, :inline_labelref
782
+
783
+ def inline_pageref(idref)
784
+ %Q[<pageref idref='#{(idref)}'>●●</pageref>] # ページ番号を参照
785
+ end
786
+
787
+ def inline_balloon(str)
788
+ %Q[<balloon>#{str.gsub(/@maru\[(\d+)\]/) {|m| inline_maru($1)}}</balloon>]
789
+ end
790
+
791
+ def inline_uchar(str)
792
+ %Q[&#x#{str};]
793
+ end
794
+
795
+ def inline_m(str)
796
+ @texinlineequation += 1
797
+ %Q[<replace idref="texinline-#{@texinlineequation}"><pre>#{str}</pre></replace>]
798
+ end
799
+
800
+ def noindent
801
+ @noindent = true
802
+ ""
803
+ end
804
+
805
+ def linebreak
806
+ # FIXME:pが閉じちゃってるので一度戻らないといけないが、難しい…。
807
+ "<br />" + @lf
808
+ end
809
+
810
+ def pagebreak
811
+ "<pagebreak />" + @lf
812
+ end
813
+
814
+ def nonum_begin(level, label, caption)
815
+ %Q[<title aid:pstyle="h#{level}">#{caption}</title><?dtp level="#{level}" section="#{caption}"?>] + @lf
816
+ end
817
+
818
+ def nonum_end(level)
819
+ end
820
+
821
+ def circle_begin(level, label, caption)
822
+ %Q[<title aid:pstyle="smallcircle">&#x2022;#{caption}</title>] + @lf
823
+ end
824
+
825
+ def circle_end(level)
826
+ end
827
+
828
+ def common_column_begin(type, caption)
829
+ buf = ""
830
+ @column += 1
831
+ a_id = %Q[id="column-#{@column}"]
832
+ buf << "<#{type}column #{a_id}>"
833
+ buf << %Q[<title aid:pstyle="#{type}column-title">#{compile_inline(caption)}</title>] << @lf
834
+ buf
835
+ end
836
+
837
+ def common_column_end(type)
838
+ "</#{type}column>" + @lf
839
+ end
840
+
841
+ def column_begin(level, label, caption)
842
+ common_column_begin("", caption)
843
+ end
844
+
845
+ def column_end(level)
846
+ common_column_end("")
847
+ end
848
+
849
+ def xcolumn_begin(level, label, caption)
850
+ common_column_begin("x", caption)
851
+ end
852
+
853
+ def xcolumn_end(level)
854
+ common_column_end("x")
855
+ end
856
+
857
+ def world_begin(level, label, caption)
858
+ common_column_begin("world", caption)
859
+ end
860
+
861
+ def world_end(level)
862
+ common_column_end("world")
863
+ end
864
+
865
+ def hood_begin(level, label, caption)
866
+ common_column_begin("hood", caption)
867
+ end
868
+
869
+ def hood_end(level)
870
+ common_column_end("hood")
871
+ end
872
+
873
+ def edition_begin(level, label, caption)
874
+ common_column_begin("edition", caption)
875
+ end
876
+
877
+ def edition_end(level)
878
+ common_column_end("edition")
879
+ end
880
+
881
+ def insideout_begin(level, label, caption)
882
+ common_column_begin("insideout", caption)
883
+ end
884
+
885
+ def insideout_end(level)
886
+ common_column_end("insideout")
887
+ end
888
+
889
+ def ref_begin(level, label, caption)
890
+ if !label.nil?
891
+ "<reference id='#{label}'>" + @lf
892
+ else
893
+ "<reference>" + @lf
894
+ end
895
+ end
896
+
897
+ def ref_end(level)
898
+ "</reference>" + @lf
899
+ end
900
+
901
+ def sup_begin(level, label, caption)
902
+ if !label.nil?
903
+ "<supplement id='#{label}'>" + @lf
904
+ else
905
+ "<supplement>" + @lf
906
+ end
907
+ end
908
+
909
+ def sup_end(level)
910
+ "</supplement>" + @lf
911
+ end
912
+
913
+ def flushright(lines)
914
+ if @book.config["deprecated-blocklines"].nil?
915
+ lines.join("").gsub("<p>", "<p align='right'>") + @lf
916
+ else
917
+ str = lines.map{|l| l.sub(/^<p>/,"").sub(/<\/p>$/,"")}.join("\n")
918
+ "<p align='right'>#{str}</p>" + @lf
919
+ end
920
+ end
921
+
922
+ def centering(lines)
923
+ lines.join("").gsub("<p>", "<p align='center'>") + @lf
924
+ end
925
+
926
+ def captionblock(type, lines, caption, specialstyle = nil)
927
+ buf = ""
928
+ buf << "<#{type}>"
929
+ style = specialstyle.nil? ? "#{type}-title" : specialstyle
930
+ buf << "<title aid:pstyle='#{style}'>#{(caption)}</title>" + @lf unless caption.nil?
931
+ if @book.config["deprecated-blocklines"].nil?
932
+ buf << "#{lines.join}</#{type}>" << @lf
933
+ else
934
+ str = lines.map{|l| l.sub(/^<p>/,"").sub(/<\/p>$/,"")}.join("\n")
935
+ buf << "#{str}</#{type}>" << @lf
936
+ end
937
+ buf
938
+ end
939
+
940
+ def note(lines, caption = nil)
941
+ captionblock("note", lines, caption)
942
+ end
943
+
944
+ def memo(lines, caption = nil)
945
+ captionblock("memo", lines, caption)
946
+ end
947
+
948
+ def tip(lines, caption = nil)
949
+ captionblock("tip", lines, caption)
950
+ end
951
+
952
+ def info(lines, caption = nil)
953
+ captionblock("info", lines, caption)
954
+ end
955
+
956
+ def planning(lines, caption = nil)
957
+ captionblock("planning", lines, caption)
958
+ end
959
+
960
+ def best(lines, caption = nil)
961
+ captionblock("best", lines, caption)
962
+ end
963
+
964
+ def important(lines, caption = nil)
965
+ captionblock("important", lines, caption)
966
+ end
967
+
968
+ def security(lines, caption = nil)
969
+ captionblock("security", lines, caption)
970
+ end
971
+
972
+ def caution(lines, caption = nil)
973
+ captionblock("caution", lines, caption)
974
+ end
975
+
976
+ def term(lines)
977
+ captionblock("term", lines, nil)
978
+ end
979
+
980
+ def link(lines, caption = nil)
981
+ captionblock("link", lines, caption)
982
+ end
983
+
984
+ def notice(lines, caption = nil)
985
+ if caption.nil?
986
+ captionblock("notice", lines, nil)
987
+ else
988
+ captionblock("notice-t", lines, caption, "notice-title")
989
+ end
990
+ end
991
+
992
+ def point(lines, caption = nil)
993
+ if caption.nil?
994
+ captionblock("point", lines, nil)
995
+ else
996
+ captionblock("point-t", lines, caption, "point-title")
997
+ end
998
+ end
999
+
1000
+ def shoot(lines, caption = nil)
1001
+ if caption.nil?
1002
+ captionblock("shoot", lines, nil)
1003
+ else
1004
+ captionblock("shoot-t", lines, caption, "shoot-title")
1005
+ end
1006
+ end
1007
+
1008
+ def reference(lines)
1009
+ captionblock("reference", lines, nil)
1010
+ end
1011
+
1012
+ def practice(lines)
1013
+ captionblock("practice", lines, nil)
1014
+ end
1015
+
1016
+ def expert(lines)
1017
+ captionblock("expert", lines, nil)
1018
+ end
1019
+
1020
+ def syntaxblock(type, lines, caption)
1021
+ buf = ""
1022
+ if caption.nil?
1023
+ buf << %Q[<#{type}>] << @lf
1024
+ else
1025
+ titleopentag = %Q[caption aid:pstyle="#{type}-title"]
1026
+ titleclosetag = "caption"
1027
+ if type == "insn"
1028
+ titleopentag = %Q[floattitle type="insn"]
1029
+ titleclosetag = "floattitle"
1030
+ end
1031
+ buf << %Q[<#{type}><#{titleopentag}>#{caption}</#{titleclosetag}>] << @lf
1032
+ end
1033
+ no = 1
1034
+ lines.each do |line|
1035
+ line.chomp!
1036
+ unless @book.config["listinfo"].nil?
1037
+ buf << %Q[<listinfo line="#{no}"]
1038
+ buf << %Q[ begin="1"] if no == 1
1039
+ buf << %Q[ end="#{no}"] if no == lines.size
1040
+ buf << %Q[>]
1041
+ end
1042
+ buf << detab(line)
1043
+ buf << "\n"
1044
+ buf << "</listinfo>" unless @book.config["listinfo"].nil?
1045
+ no += 1
1046
+ end
1047
+ buf << "</#{type}>" << @lf
1048
+ buf
1049
+ end
1050
+
1051
+ def insn(lines, caption = nil)
1052
+ syntaxblock("insn", lines, caption)
1053
+ end
1054
+
1055
+ def box(lines, caption = nil)
1056
+ syntaxblock("box", lines, caption)
1057
+ end
1058
+
1059
+ def indepimage(id, caption=nil, metric=nil)
1060
+ buf = ""
1061
+ metrics = parse_metric("idgxml", metric)
1062
+ buf << "<img>" << @lf
1063
+ begin
1064
+ buf << %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A\.\//, "")}"#{metrics} />] << @lf
1065
+ rescue
1066
+ warn %Q[no such image: #{id}]
1067
+ end
1068
+ buf << %Q[<caption>#{caption}</caption>] + @lf if caption.present?
1069
+ buf << "</img>" << @lf
1070
+ buf
1071
+ end
1072
+
1073
+ alias_method :numberlessimage, :indepimage
1074
+
1075
+ def label(id)
1076
+ # FIXME
1077
+ "<label id='#{id}' />"
1078
+ end
1079
+
1080
+ def tsize(str)
1081
+ @tsize = str
1082
+ end
1083
+
1084
+ def dtp(str)
1085
+ %Q(<?dtp #{str} ?>)
1086
+ end
1087
+
1088
+ def hr
1089
+ "<hr />"
1090
+ end
1091
+
1092
+ def bpo(lines)
1093
+ %Q[<bpo>#{lines.join("\n")}</bpo>] + @lf
1094
+ end
1095
+
1096
+ def inline_dtp(str)
1097
+ "<?dtp #{str} ?>"
1098
+ end
1099
+
1100
+ def inline_code(str)
1101
+ %Q[<tt type='inline-code'>#{str}</tt>]
1102
+ end
1103
+
1104
+ def inline_br(str)
1105
+ "\n"
1106
+ end
1107
+
1108
+ def rawblock(lines)
1109
+ buf = ""
1110
+ no = 1
1111
+ lines.each do |l|
1112
+ buf << l.gsub("&lt;", "<").gsub("&gt;", ">").gsub("&quot;", "\"").gsub("&amp;", "&")
1113
+ buf << "\n" unless lines.length == no
1114
+ no += 1
1115
+ end
1116
+ buf
1117
+ end
1118
+
1119
+ def text(str)
1120
+ str
1121
+ end
1122
+
1123
+ def inline_chapref(id)
1124
+ chs = ["", "「", "」"]
1125
+ unless @book.config["chapref"].nil?
1126
+ _chs = @book.config["chapref"].split(",")
1127
+ if _chs.size != 3
1128
+ error "--chapsplitter must have exactly 3 parameters with comma."
1129
+ else
1130
+ chs = _chs
1131
+ end
1132
+ else
1133
+ end
1134
+ s = "#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
1135
+ if @book.config["chapterlink"]
1136
+ %Q(<link href="#{id}">#{s}</link>)
1137
+ else
1138
+ s
1139
+ end
1140
+ rescue KeyError
1141
+ error "unknown chapter: #{id}"
1142
+ nofunc_text("[UnknownChapter:#{id}]")
1143
+ end
1144
+
1145
+ def inline_chap(id)
1146
+ if @book.config["chapterlink"]
1147
+ %Q(<link href="#{id}">#{@book.chapter_index.number(id)}</link>)
1148
+ else
1149
+ @book.chapter_index.number(id)
1150
+ end
1151
+ rescue KeyError
1152
+ error "unknown chapter: #{id}"
1153
+ nofunc_text("[UnknownChapter:#{id}]")
1154
+ end
1155
+
1156
+ def inline_title(id)
1157
+ title = super
1158
+ if @book.config["chapterlink"]
1159
+ %Q(<link href="#{id}">#{title}</link>)
1160
+ else
1161
+ title
1162
+ end
1163
+ rescue KeyError
1164
+ error "unknown chapter: #{id}"
1165
+ nofunc_text("[UnknownChapter:#{id}]")
1166
+ end
1167
+
1168
+ def source_header(caption)
1169
+ buf = ""
1170
+ buf << %Q[<source>] << @lf
1171
+ buf << %Q[<caption>#{caption}</caption>] << @lf
1172
+ buf
1173
+ end
1174
+
1175
+ def source_body(lines, lang)
1176
+ buf = ""
1177
+ buf << %Q[<pre>] << @lf
1178
+ buf << codelines_body(lines)
1179
+ buf << %Q[</pre></source>] << @lf
1180
+ buf
1181
+ end
1182
+
1183
+ def bibpaper(lines, id, caption)
1184
+ buf = ""
1185
+ buf << bibpaper_header(id, caption)
1186
+ unless lines.empty?
1187
+ buf << bibpaper_bibpaper(id, caption, lines)
1188
+ end
1189
+ buf << %Q(</bibitem>) << @lf
1190
+ buf
1191
+ end
1192
+
1193
+ def bibpaper_header(id, caption)
1194
+ buf = ""
1195
+ buf << %Q(<bibitem id="bib-#{id}">) << @lf
1196
+ buf << "<caption><span type='bibno'>[#{@chapter.bibpaper(id).number}] </span>#{caption}</caption>" << @lf
1197
+ buf
1198
+ end
1199
+
1200
+ def bibpaper_bibpaper(id, caption, lines)
1201
+ lines.join("")
1202
+ end
1203
+
1204
+ def inline_bib(id)
1205
+ %Q(<span type='bibref' idref='#{id}'>[#{@chapter.bibpaper(id).number}]</span>)
1206
+ end
1207
+
1208
+ def inline_hd_chap(chap, id)
1209
+ if chap.number
1210
+ n = chap.headline_index.number(id)
1211
+ if @book.config["secnolevel"] >= n.split('.').size
1212
+ return I18n.t("chapter_quote", "#{n} #{chap.headline(id).caption}")
1213
+ end
1214
+ end
1215
+ I18n.t("chapter_quote", chap.headline(id).caption)
1216
+ end
1217
+
1218
+ def inline_recipe(id)
1219
+ # FIXME
1220
+ %Q(<recipe idref="#{id}">[XXX]「#{id}」 p.XX</recipe>)
1221
+ end
1222
+
1223
+ def nofunc_text(str)
1224
+ escape_html(str)
1225
+ end
1226
+
1227
+ def image_ext
1228
+ "eps"
1229
+ end
1230
+
1231
+ end
1232
+
1233
+ end # module ReVIEW