review-peg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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