xpub 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ <%- @book.identifiers.each do |identifier| -%>
2
+ <dc:identifier<%- if identifier.scheme -%> opf:scheme="<%= identifier.scheme %>"<%- end -%>><%= identifier.identifier %></dc:identifier>
3
+ <%- end -%>
4
+ <%- if @book.lang -%>
5
+ <dc:language><%= @book.lang %></dc:language>
6
+ <%- end -%>
7
+ <dc:title opf:type="main"><%= @book.title %></dc:title>
8
+ <%- if @book.subtitle -%>
9
+ <dc:title opf:type="subtitle"><%= @book.subtitle %></dc:title>
10
+ <%- end -%>
11
+ <%- if @book.short -%>
12
+ <dc:title opf:type="short"><%= @book.short %></dc:title>
13
+ <%- end -%>
14
+ <%- if @book.collection -%>
15
+ <dc:title opf:type="collection"><%= @book.collection %></dc:title>
16
+ <%- end -%>
17
+ <%- if @book.edition -%>
18
+ <dc:title opf:type="edition"><%= @book.edition %></dc:title>
19
+ <%- end -%>
20
+ <%- if @book.extended -%>
21
+ <dc:title opf:type="extended"><%= @book.extended %></dc:title>
22
+ <%- end -%>
23
+ <%- if @book.publisher -%>
24
+ <dc:publisher><%= @book.publisher %></dc:publisher>
25
+ <%- end -%>
26
+ <%- @book.creators.each do |c| -%>
27
+ <dc:creator<%- if c.role -%> opf:role="<%= c.role %>"<%- end -%>><%= c.name %></dc:creator>
28
+ <%- end -%>
29
+ <%- @book.contributors.each do |c| -%>
30
+ <dc:contributor<%- if c.role -%> opf:role="<%= c.role %>"<%- end -%>><%= c.name %></dc:contributor>
31
+ <%- end -%>
32
+ <%- if @book.description -%>
33
+ <dc:description><%= @book.description %></dc:description>
34
+ <%- end -%>
35
+ <%- if @book.rights -%>
36
+ <dc:rights><%= @book.rights %></dc:rights>
37
+ <%- end -%>
38
+ <%- if @book.publication -%>
39
+ <dc:date><%= Time.parse(@book.publication).utc.iso8601 %></dc:date>
40
+ <%- end -%>
41
+ <%- if @book.modification -%>
42
+ <meta property="dcterms:modified"><%= Time.parse(@book.modification).utc.iso8601 %></meta>
43
+ <%- end -%>
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+
5
+ class PandocFilter
6
+
7
+ def initialize filters
8
+ @filters = filters
9
+ end
10
+
11
+ def filter_str str
12
+ doc = JSON.parse str
13
+ doc.each { |child|
14
+ filter_node doc, child
15
+ }
16
+ JSON.generate doc
17
+ end
18
+
19
+ def before_filter doc, node
20
+ @filters.each { |f|
21
+ f.filter doc, node, "before"
22
+ }
23
+ end
24
+
25
+ def after_filter doc, node
26
+ @filters.each { |f|
27
+ f.filter doc, node, "after"
28
+ }
29
+ end
30
+
31
+ def filter_node doc, node
32
+ if node.kind_of?(String)
33
+ elsif node.kind_of?(Array)
34
+ before_filter doc, node
35
+ node.each { |child|
36
+ filter_node doc, child
37
+ }
38
+ after_filter doc, node
39
+ elsif node.kind_of?(Hash)
40
+ if node.has_key? "t"
41
+ before_filter doc, node
42
+ filter_node doc, node["c"]
43
+ after_filter doc, node
44
+ end
45
+ else
46
+ end
47
+ end
48
+ end
49
+
50
+
51
+
52
+ # ルビフィルタ
53
+ # グループルビ
54
+ # {電子出版|でんししゅっぱん}を手軽に
55
+ # <ruby>電子出版<rt>でんししゅっぱん</rt></ruby>を手軽に
56
+ # 熟語ルビ
57
+ # {電子出版|でん|し|しゅっ|ぱん}を手軽に
58
+ # <ruby>電<rt>でん</rt>子<rt>し</rt>出<rt>しゅっ</rt>版<rt>ぱん</rt>を手軽に</p>
59
+ class FuriganaFilter
60
+
61
+ def pattern
62
+ /{([^|]+)\|([^|}]+(\|[^|}]+)*)}/
63
+ end
64
+
65
+ def split pattern, str
66
+ if str.match pattern
67
+ if $` == ""
68
+ [[$&,true]].concat split(pattern, $')
69
+ else
70
+ [[$`, false],[$&,true]].concat split(pattern, $')
71
+ end
72
+ else
73
+ if str == ""
74
+ []
75
+ else
76
+ [[str, false]]
77
+ end
78
+ end
79
+ end
80
+
81
+
82
+ def replace str
83
+ str.match(pattern) { |md|
84
+ phrase = md[1]
85
+ ruby_chars = md[2].split('|')
86
+ if phrase.length == ruby_chars.length
87
+ # 熟語ルビ
88
+ "<ruby>" + phrase.split("").zip(ruby_chars).map {|c,r|
89
+ "#{c}<rt>#{r}</rt>"
90
+ }.join("") + "</ruby>"
91
+ else
92
+ # グループルビ
93
+ "<ruby>#{phrase}<rt>#{ruby_chars.join("")}</rt></ruby>"
94
+ end
95
+ }
96
+ end
97
+
98
+ def filter doc, node, mode
99
+ if mode == "before" && node.kind_of?(Array)
100
+ new_node = []
101
+ node.each { |child|
102
+ if child.kind_of?(Hash) &&
103
+ child["t"] == "Str" &&
104
+ child["c"].match(pattern)
105
+ split(pattern, child["c"]).map { |str, flag|
106
+ if flag
107
+ new_node << { "t" => "RawInline","c" => ["html",replace(str)]}
108
+ else
109
+ new_node << { "t" => "Str", "c" => str }
110
+ end
111
+ }
112
+ else
113
+ new_node << child
114
+ end
115
+ }
116
+ node.replace new_node
117
+ end
118
+ end
119
+ end
120
+
121
+ # 改ページフィルタ
122
+ # なにもうめこまない。chapter単位で分割する
123
+ class NewPageFilter
124
+
125
+ def pattern
126
+ /^===.*$/
127
+ end
128
+
129
+ def filter doc, node, mode
130
+ if mode == "before" && node.kind_of?(Hash)
131
+ if node["t"] == "Para" &&
132
+ node["c"].count == 1 &&
133
+ node["c"][0]["t"] == "Str" &&
134
+ node["c"][0]["c"].match(pattern)
135
+ node["c"][0]["t"] = "RawInline"
136
+
137
+ l = node["c"][0]["c"].length
138
+ node["c"][0]["c"] = ["html",""]
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ # 縦横中フィルタ
145
+ class TateNakaYokoFilter
146
+
147
+ def pattern
148
+ /\^([^^]+)\^/
149
+ end
150
+
151
+ def split pattern, str
152
+ if str.match pattern
153
+ if $` == ""
154
+ [[$&,true]].concat split(pattern, $')
155
+ else
156
+ [[$`, false],[$&,true]].concat split(pattern, $')
157
+ end
158
+ else
159
+ if str == ""
160
+ []
161
+ else
162
+ [[str, false]]
163
+ end
164
+ end
165
+ end
166
+
167
+
168
+ def replace str
169
+ str.match(pattern) { |md|
170
+ word = md[1]
171
+ "<span class=\"tcy\">#{word}</span>"
172
+ }
173
+ end
174
+
175
+ def filter doc, node, mode
176
+ if mode == "before" && node.kind_of?(Array)
177
+ new_node = []
178
+ node.each { |child|
179
+ if child.kind_of?(Hash) &&
180
+ child["t"] == "Str" &&
181
+ child["c"].match(pattern)
182
+ split(pattern, child["c"]).map { |str, flag|
183
+ if flag
184
+ new_node << { "t" => "RawInline","c" => ["html",replace(str)]}
185
+ else
186
+ new_node << { "t" => "Str", "c" => str }
187
+ end
188
+ }
189
+ else
190
+ new_node << child
191
+ end
192
+ }
193
+ node.replace new_node
194
+ end
195
+ end
196
+ end
197
+
198
+ filters = [
199
+ FuriganaFilter.new,
200
+ TateNakaYokoFilter.new,
201
+ NewPageFilter.new
202
+ ]
203
+
204
+ puts PandocFilter.new(filters).filter_str STDIN.read
205
+
206
+
@@ -0,0 +1,57 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html>
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"$if(lang)$ xml:lang="$lang$"$endif$>
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="generator" content="pandoc" />
7
+ <meta name="generator" content="ebc" />
8
+ <title>$pagetitle$</title>
9
+ $if(quotes)$
10
+ <style type="text/css">
11
+ q { quotes: "“" "”" "‘" "’"; }
12
+ </style>
13
+ $endif$
14
+ $if(highlighting-css)$
15
+ <style type="text/css">
16
+ $highlighting-css$
17
+ </style>
18
+ $endif$
19
+ $for(css)$
20
+ <link rel="stylesheet" type="text/css" href="$css$" />
21
+ $endfor$
22
+ </head>
23
+ <body$if(coverpage)$ id="cover"$endif$>
24
+ $if(titlepage)$
25
+ <section epub:type="titlepage">
26
+ $for(title)$
27
+ $if(title.type)$
28
+ <h1 class="$title.type$">$title.text$</h1>
29
+ $else$
30
+ <h1 class="title">$title$</h1>
31
+ $endif$
32
+ $endfor$
33
+ $if(subtitle)$
34
+ <h1 class="subtitle">$subtitle$</h1>
35
+ $endif$
36
+ $for(author)$
37
+ <h2 class="author">$author$</h2>
38
+ $endfor$
39
+ $for(creator)$
40
+ <h2 class="$creator.type$">$creator.text$</h2>
41
+ $endfor$
42
+ $if(publisher)$
43
+ <p class="publisher">$publisher$</p>
44
+ $endif$
45
+ $if(date)$
46
+ <p class="date">$date$</p>
47
+ $endif$
48
+ $if(rights)$
49
+ <p class="rights">$rights$</p>
50
+ $endif$
51
+ </section>
52
+ $else$
53
+ $body$
54
+ $endif$
55
+ </body>
56
+ </html>
57
+
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+
5
+ class PandocFilter
6
+
7
+ def initialize filters
8
+ @filters = filters
9
+ end
10
+
11
+ def filter_str str
12
+ doc = JSON.parse str
13
+ doc.each { |child|
14
+ filter_node doc, child
15
+ }
16
+ JSON.generate doc
17
+ end
18
+
19
+ def before_filter doc, node
20
+ @filters.each { |f|
21
+ f.filter doc, node, "before"
22
+ }
23
+ end
24
+
25
+ def after_filter doc, node
26
+ @filters.each { |f|
27
+ f.filter doc, node, "after"
28
+ }
29
+ end
30
+
31
+ def filter_node doc, node
32
+ if node.kind_of?(String)
33
+ elsif node.kind_of?(Array)
34
+ before_filter doc, node
35
+ node.each { |child|
36
+ filter_node doc, child
37
+ }
38
+ after_filter doc, node
39
+ elsif node.kind_of?(Hash)
40
+ if node.has_key? "t"
41
+ before_filter doc, node
42
+ filter_node doc, node["c"]
43
+ after_filter doc, node
44
+ end
45
+ else
46
+ end
47
+ end
48
+ end
49
+
50
+
51
+
52
+ # ルビフィルタ
53
+ # グループルビ
54
+ # {電子出版|でんししゅっぱん}を手軽に
55
+ # \ruby{>電子出版}{でんししゅっぱん}を手軽に
56
+ # 熟語ルビ
57
+ # {電子出版|でん|し|しゅっ|ぱん}を手軽に
58
+ # \ruby{電}{でん}\ruby{子}{し}\ruby{出}{しゅっ}\ruby{版}{ぱん}を手軽に</p>
59
+ class FuriganaFilter
60
+
61
+ def pattern
62
+ /{(([^|]|\s)+)\|(([^|}]|\s)+(\|([^|}]|\s)+)*)}/
63
+ end
64
+
65
+ def split pattern, str
66
+ if str.match pattern
67
+ if $` == ""
68
+ [[$&,true]].concat split(pattern, $')
69
+ else
70
+ [[$`, false],[$&,true]].concat split(pattern, $')
71
+ end
72
+ else
73
+ if str == ""
74
+ []
75
+ else
76
+ [[str, false]]
77
+ end
78
+ end
79
+ end
80
+
81
+
82
+ def replace str
83
+ str.match(pattern) { |md|
84
+ phrase = md[1]
85
+ ruby_chars = md[3].split('|')
86
+ if phrase.length == ruby_chars.length
87
+ # 熟語ルビ
88
+ phrase.split("").zip(ruby_chars).map {|c,r|
89
+ "\\ruby{#{c}}{#{r}}"
90
+ }.join ""
91
+ else
92
+ # グループルビ
93
+ "\\ruby{#{phrase}}{#{ruby_chars.join("")}}"
94
+ end
95
+ }
96
+ end
97
+
98
+ def filter doc, node, mode
99
+ if mode == "before" && node.kind_of?(Array)
100
+ new_node = []
101
+ node.each { |child|
102
+ if child.kind_of?(Hash) &&
103
+ child["t"] == "Str" &&
104
+ child["c"].match(pattern)
105
+ split(pattern, child["c"]).map { |str, flag|
106
+ if flag
107
+ new_node << { "t" => "RawInline","c" => ["tex",replace(str)]}
108
+ else
109
+ new_node << { "t" => "Str", "c" => str }
110
+ end
111
+ }
112
+ else
113
+ new_node << child
114
+ end
115
+ }
116
+ node.replace new_node
117
+ end
118
+ end
119
+ end
120
+
121
+ # 改ページフィルタ
122
+ # === だと\\newpage
123
+ # ==== だと\\clearpage
124
+ # ===== かそれ以上だと \\cleardoublepage
125
+ class NewPageFilter
126
+
127
+ def pattern
128
+ /^===.*$/
129
+ end
130
+
131
+ def filter doc, node, mode
132
+ if mode == "before" && node.kind_of?(Hash)
133
+ if node["t"] == "Para" &&
134
+ node["c"].count == 1 &&
135
+ node["c"][0]["t"] == "Str" &&
136
+ node["c"][0]["c"].match(pattern)
137
+ node["c"][0]["t"] = "RawInline"
138
+
139
+ l = node["c"][0]["c"].length
140
+ if l == 3
141
+ node["c"][0]["c"] = ["tex","\\newpage"]
142
+ elsif l == 4
143
+ node["c"][0]["c"] = ["tex","\\clearpage"]
144
+ else
145
+ node["c"][0]["c"] = ["tex","\\cleardoublepage"]
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ # 縦横中フィルタ
153
+ class TateNakaYokoFilter
154
+
155
+ def pattern
156
+ /\^([^^]+)\^/
157
+ end
158
+
159
+ def split pattern, str
160
+ if str.match pattern
161
+ if $` == ""
162
+ [[$&,true]].concat split(pattern, $')
163
+ else
164
+ [[$`, false],[$&,true]].concat split(pattern, $')
165
+ end
166
+ else
167
+ if str == ""
168
+ []
169
+ else
170
+ [[str, false]]
171
+ end
172
+ end
173
+ end
174
+
175
+
176
+ def replace str
177
+ str.match(pattern) { |md|
178
+ word = md[1]
179
+ "\\pbox<y>{#{word}}"
180
+ }
181
+ end
182
+
183
+ def filter doc, node, mode
184
+ if mode == "before" && node.kind_of?(Array)
185
+ new_node = []
186
+ node.each { |child|
187
+ if child.kind_of?(Hash) &&
188
+ child["t"] == "Str" &&
189
+ child["c"].match(pattern)
190
+ split(pattern, child["c"]).map { |str, flag|
191
+ if flag
192
+ new_node << { "t" => "RawInline","c" => ["tex",replace(str)]}
193
+ else
194
+ new_node << { "t" => "Str", "c" => str }
195
+ end
196
+ }
197
+ else
198
+ new_node << child
199
+ end
200
+ }
201
+ node.replace new_node
202
+ end
203
+ end
204
+ end
205
+
206
+
207
+ # 改行フィルタ
208
+ # Markdownで文章を改行したあとに、空行を挿入せずに文章を続けるときに、単なる改行になるようなフィルタ
209
+ # Pandocに同様のオプションがあるためこのフィルタは使わない
210
+ class NewLineFilter
211
+ def filter doc, node, mode
212
+ if mode == "before" && node.kind_of?(Hash)
213
+ if node["t"] == "Para"
214
+ node["c"].each { |child|
215
+ if child.kind_of?(Hash)
216
+ if child["t"] == "Space"
217
+ child["t"] = "RawInline"
218
+ child["c"] = ["tex", "\\\\"]
219
+ end
220
+ end
221
+ }
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ class ColumnFilter
228
+ def pattern
229
+ /\s*<!--\s*%%(twocolumn|onecolumn)%%\s*-->\s*/
230
+ end
231
+ def filter doc, node, mode
232
+ if mode == "before" && node.kind_of?(Hash)
233
+ if node["t"] == "RawBlock" && node["c"][0] == "html" && node["c"][1].match(pattern)
234
+ node["c"][0] = "tex"
235
+ node["c"][1].match(pattern) { |md|
236
+ node["c"][1] = "\\" + md[1]
237
+ }
238
+ end
239
+ end
240
+ end
241
+ end
242
+
243
+ class TocFilter
244
+ def pattern
245
+ /\s*<!--\s*%%toc%%\s*-->\s*/
246
+ end
247
+ def filter doc, node, mode
248
+ if mode == "before" && node.kind_of?(Hash)
249
+ if node["t"] == "RawBlock" && node["c"][0] == "html" && node["c"][1].match(pattern)
250
+ node["c"][0] = "tex"
251
+ node["c"][1] = "\\tableofcontents"
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+
258
+ filters = [
259
+ FuriganaFilter.new,
260
+ TateNakaYokoFilter.new,
261
+ NewPageFilter.new,
262
+ ColumnFilter.new,
263
+ TocFilter.new,
264
+ # NewLineFilter.new
265
+ ]
266
+
267
+ puts PandocFilter.new(filters).filter_str STDIN.read
268
+
269
+