xpub 0.0.1

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.
@@ -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
+