gepub 0.6.8.5 → 0.6.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/gepub.gemspec +1 -1
- data/lib/gepub/book.rb +82 -65
- data/lib/gepub/builder_mixin.rb +2 -2
- data/lib/gepub/meta.rb +9 -1
- data/lib/gepub/meta_array.rb +10 -0
- data/lib/gepub/metadata.rb +74 -16
- data/lib/gepub/package.rb +39 -2
- data/lib/gepub/rendition.rb +49 -0
- data/lib/gepub/resource_builder.rb +25 -2
- data/lib/gepub/sorted_array.rb +20 -0
- data/lib/gepub/spine.rb +17 -1
- data/lib/gepub/version.rb +1 -1
- data/lib/gepub.rb +1 -0
- data/spec/book_spec.rb +292 -0
- data/spec/builder_spec.rb +19 -0
- data/spec/fixtures/testdata/test.opf +11 -2
- data/spec/fixtures/testdata/wasteland-20120118.epub +0 -0
- data/spec/package_spec.rb +42 -2
- metadata +32 -10
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# gepub [<img src="https://secure.travis-ci.org/skoji/gepub.png" />](http://travis-ci.org/skoji/gepub)
|
1
|
+
# gepub [<img src="https://secure.travis-ci.org/skoji/gepub.png" />](http://travis-ci.org/skoji/gepub)
|
2
2
|
|
3
3
|
* http://en.skoji.jp/category/gepub/
|
4
4
|
|
data/gepub.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_development_dependency "rspec", "~> 2"
|
21
|
+
s.add_development_dependency "rspec", "~> 2.11"
|
22
22
|
s.add_runtime_dependency "nokogiri", "~> 1.5.0"
|
23
23
|
s.add_runtime_dependency "rubyzip", "~> 0.9.7"
|
24
24
|
end
|
data/lib/gepub/book.rb
CHANGED
@@ -104,41 +104,9 @@ module GEPUB
|
|
104
104
|
package_path = nil
|
105
105
|
Zip::ZipInputStream::open_buffer(io) {
|
106
106
|
|zis|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
case entry.name
|
111
|
-
when MIMETYPE then
|
112
|
-
if files[MIMETYPE] != MIMETYPE_CONTENTS
|
113
|
-
warn "#{MIMETYPE} is not valid: should be #{MIMETYPE_CONTENTS} but was #{files[MIMETYPE]}"
|
114
|
-
end
|
115
|
-
files.delete(MIMETYPE)
|
116
|
-
when CONTAINER then
|
117
|
-
package_path = rootfile_from_container(files[CONTAINER])
|
118
|
-
files.delete(CONTAINER)
|
119
|
-
when ROOTFILE_PATTERN then
|
120
|
-
package = Package.parse_opf(files[entry.name], entry.name)
|
121
|
-
files.delete(entry.name)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
if package.nil?
|
127
|
-
raise 'this container do not cotains publication information file'
|
128
|
-
end
|
129
|
-
|
130
|
-
if package_path != package.path
|
131
|
-
warn 'inconsistend EPUB file: container says opf is #{package_path}, but actually #{package.path}'
|
132
|
-
end
|
133
|
-
|
134
|
-
files.each {
|
135
|
-
|k, content|
|
136
|
-
item = package.manifest.item_by_href(k.sub(/^#{package.contents_prefix}/,''))
|
137
|
-
if !item.nil?
|
138
|
-
files.delete(k)
|
139
|
-
item.add_raw_content(content)
|
140
|
-
end
|
141
|
-
}
|
107
|
+
package, package_path = parse_container(zis, files)
|
108
|
+
check_consistency_of_package(package, package_path)
|
109
|
+
parse_files_into_package(files, package)
|
142
110
|
book = Book.new(package.path)
|
143
111
|
book.instance_eval { @package = package; @optional_files = files }
|
144
112
|
book
|
@@ -226,8 +194,8 @@ module GEPUB
|
|
226
194
|
items[@package.bindings.handler_by_media_type[media_type]]
|
227
195
|
end
|
228
196
|
|
229
|
-
def method_missing(name,*args)
|
230
|
-
@package.send(name, *args)
|
197
|
+
def method_missing(name,*args, &block)
|
198
|
+
@package.send(name, *args, &block)
|
231
199
|
end
|
232
200
|
|
233
201
|
# should call ordered() with block.
|
@@ -239,34 +207,8 @@ module GEPUB
|
|
239
207
|
# clenup and maintain consistency of metadata and items included in the Book
|
240
208
|
# object.
|
241
209
|
def cleanup
|
242
|
-
|
243
|
-
|
244
|
-
|x,item|
|
245
|
-
item.media_type == 'application/x-dtbncx+xml'
|
246
|
-
}.size == 0
|
247
|
-
if (@toc.size == 0)
|
248
|
-
@toc << { :item => @package.manifest.item_list[@package.spine.itemref_list[0].idref] }
|
249
|
-
end
|
250
|
-
add_item('toc.ncx', StringIO.new(ncx_xml), 'ncx')
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
if version.to_f >=3.0
|
255
|
-
@package.metadata.set_lastmodified
|
256
|
-
|
257
|
-
if @package.manifest.item_list.select {
|
258
|
-
|href, item|
|
259
|
-
(item.properties||[]).member? 'nav'
|
260
|
-
}.size == 0
|
261
|
-
generate_nav_doc
|
262
|
-
end
|
263
|
-
|
264
|
-
@package.spine.remove_with_idlist @package.manifest.item_list.map {
|
265
|
-
|href, item|
|
266
|
-
item.fallback
|
267
|
-
}.reject(&:nil?)
|
268
|
-
|
269
|
-
end
|
210
|
+
cleanup_for_epub2
|
211
|
+
cleanup_for_epub3
|
270
212
|
end
|
271
213
|
|
272
214
|
# write EPUB to stream specified by the argument.
|
@@ -388,5 +330,80 @@ EOF
|
|
388
330
|
}
|
389
331
|
builder.to_xml(:encoding => 'utf-8')
|
390
332
|
end
|
333
|
+
|
334
|
+
private
|
335
|
+
def self.parse_container(zis, files)
|
336
|
+
package_path = nil
|
337
|
+
package = nil
|
338
|
+
while entry = zis.get_next_entry
|
339
|
+
if !entry.directory?
|
340
|
+
files[entry.name] = zis.read
|
341
|
+
case entry.name
|
342
|
+
when MIMETYPE then
|
343
|
+
if files[MIMETYPE] != MIMETYPE_CONTENTS
|
344
|
+
warn "#{MIMETYPE} is not valid: should be #{MIMETYPE_CONTENTS} but was #{files[MIMETYPE]}"
|
345
|
+
end
|
346
|
+
files.delete(MIMETYPE)
|
347
|
+
when CONTAINER then
|
348
|
+
package_path = rootfile_from_container(files[CONTAINER])
|
349
|
+
files.delete(CONTAINER)
|
350
|
+
when ROOTFILE_PATTERN then
|
351
|
+
package = Package.parse_opf(files[entry.name], entry.name)
|
352
|
+
files.delete(entry.name)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
return package, package_path
|
357
|
+
end
|
358
|
+
|
359
|
+
def self.check_consistency_of_package(package, package_path)
|
360
|
+
if package.nil?
|
361
|
+
raise 'this container do not cotains publication information file'
|
362
|
+
end
|
363
|
+
|
364
|
+
if package_path != package.path
|
365
|
+
warn 'inconsistend EPUB file: container says opf is #{package_path}, but actually #{package.path}'
|
366
|
+
end
|
367
|
+
end
|
368
|
+
def self.parse_files_into_package(files, package)
|
369
|
+
files.each {
|
370
|
+
|k, content|
|
371
|
+
item = package.manifest.item_by_href(k.sub(/^#{package.contents_prefix}/,''))
|
372
|
+
if !item.nil?
|
373
|
+
files.delete(k)
|
374
|
+
item.add_raw_content(content)
|
375
|
+
end
|
376
|
+
}
|
377
|
+
end
|
378
|
+
def cleanup_for_epub2
|
379
|
+
if version.to_f < 3.0 || @package.epub_backward_compat
|
380
|
+
if @package.manifest.item_list.select {
|
381
|
+
|x,item|
|
382
|
+
item.media_type == 'application/x-dtbncx+xml'
|
383
|
+
}.size == 0
|
384
|
+
if (@toc.size == 0)
|
385
|
+
@toc << { :item => @package.manifest.item_list[@package.spine.itemref_list[0].idref] }
|
386
|
+
end
|
387
|
+
add_item('toc.ncx', StringIO.new(ncx_xml), 'ncx')
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
def cleanup_for_epub3
|
392
|
+
if version.to_f >=3.0
|
393
|
+
@package.metadata.set_lastmodified
|
394
|
+
|
395
|
+
if @package.manifest.item_list.select {
|
396
|
+
|href, item|
|
397
|
+
(item.properties||[]).member? 'nav'
|
398
|
+
}.size == 0
|
399
|
+
generate_nav_doc
|
400
|
+
end
|
401
|
+
|
402
|
+
@package.spine.remove_with_idlist @package.manifest.item_list.map {
|
403
|
+
|href, item|
|
404
|
+
item.fallback
|
405
|
+
}.reject(&:nil?)
|
406
|
+
end
|
407
|
+
end
|
391
408
|
end
|
392
409
|
end
|
data/lib/gepub/builder_mixin.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module GEPUB
|
2
2
|
module BuilderMixin
|
3
|
-
def method_missing(name, *args)
|
3
|
+
def method_missing(name, *args, &block)
|
4
4
|
if Array === @last_defined_item &&
|
5
5
|
@last_defined_item.size > 0 &&
|
6
6
|
@last_defined_item[0].respond_to?(name.to_sym)
|
@@ -20,7 +20,7 @@ module GEPUB
|
|
20
20
|
end
|
21
21
|
}
|
22
22
|
elsif @last_defined_item.respond_to?(name.to_sym)
|
23
|
-
@last_defined_item.send(name, *args)
|
23
|
+
@last_defined_item.send(name, *args, &block)
|
24
24
|
else
|
25
25
|
super
|
26
26
|
end
|
data/lib/gepub/meta.rb
CHANGED
@@ -48,7 +48,7 @@ module GEPUB
|
|
48
48
|
|
49
49
|
# add a refiner.
|
50
50
|
def add_refiner(property, content, attributes = {})
|
51
|
-
(@refiners[property] ||= []) <<
|
51
|
+
(@refiners[property] ||= []) << Meta.new('meta', content, @parent, { 'property' => property }.merge(attributes)) unless content.nil?
|
52
52
|
self
|
53
53
|
end
|
54
54
|
|
@@ -69,6 +69,14 @@ module GEPUB
|
|
69
69
|
define_method(methodbase) { refiner(name) }
|
70
70
|
}
|
71
71
|
|
72
|
+
def lang=(lang)
|
73
|
+
@attributes['xml:lang'] = lang
|
74
|
+
end
|
75
|
+
|
76
|
+
def lang
|
77
|
+
@attributes['xml:lang']
|
78
|
+
end
|
79
|
+
|
72
80
|
# add alternate script refiner.
|
73
81
|
def add_alternates(alternates = {})
|
74
82
|
alternates.each {
|
data/lib/gepub/metadata.rb
CHANGED
@@ -12,6 +12,11 @@ module GEPUB
|
|
12
12
|
end
|
13
13
|
# Holds data in /package/metadata
|
14
14
|
class Metadata
|
15
|
+
class NilContent
|
16
|
+
def self.content
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
15
20
|
include XMLUtil
|
16
21
|
attr_accessor :opf_version
|
17
22
|
# parse metadata element. metadata_xml should be Nokogiri::XML::Node object.
|
@@ -23,18 +28,26 @@ module GEPUB
|
|
23
28
|
@namespaces = @xml.namespaces
|
24
29
|
CONTENT_NODE_LIST.each {
|
25
30
|
|node|
|
26
|
-
|
27
|
-
@content_nodes[node] = parse_node(DC_NS, node).sort_by {
|
28
|
-
|v|
|
29
|
-
[v.refiner('display-seq').to_s.to_i || 2 ** (0.size * 8 - 2) - 1, i += 1]
|
30
|
-
}
|
31
|
+
@content_nodes[node] = parse_node(DC_NS, node).sort_as_meta
|
31
32
|
}
|
32
33
|
@xml.xpath("#{ns_prefix(OPF_NS)}:meta[not(@refines) and @property]", @namespaces).each {
|
33
34
|
|node|
|
34
|
-
@
|
35
|
+
(@content_nodes['meta'] ||= []) << create_meta(node)
|
35
36
|
}
|
36
37
|
|
37
38
|
@oldstyle_meta = parse_opf2_meta
|
39
|
+
|
40
|
+
meta_list.each {
|
41
|
+
|metanode|
|
42
|
+
case metanode['property']
|
43
|
+
when 'rendition:layout'
|
44
|
+
@layout = metanode
|
45
|
+
when 'rendition:orientation'
|
46
|
+
@orientation = metanode
|
47
|
+
when 'rendition:spread'
|
48
|
+
@spread = metanode
|
49
|
+
end
|
50
|
+
}
|
38
51
|
}
|
39
52
|
}
|
40
53
|
end
|
@@ -43,15 +56,20 @@ module GEPUB
|
|
43
56
|
@id_pool = id_pool
|
44
57
|
@metalist = {}
|
45
58
|
@content_nodes = {}
|
46
|
-
@meta = {}
|
47
59
|
@oldstyle_meta = []
|
48
60
|
@opf_version = opf_version
|
49
61
|
@namespaces = { 'xmlns:dc' => DC_NS }
|
50
62
|
@namespaces['xmlns:opf'] = OPF_NS if @opf_version.to_f < 3.0
|
63
|
+
@default_layout = 'reflowable'
|
64
|
+
@default_orientation = 'auto'
|
65
|
+
@spread = 'auto'
|
66
|
+
@layout = NilContent
|
67
|
+
@orientation = NilContent
|
68
|
+
@spread = NilContent
|
51
69
|
yield self if block_given?
|
52
70
|
end
|
53
71
|
|
54
|
-
def to_xml(builder)
|
72
|
+
def to_xml(builder)
|
55
73
|
builder.metadata(@namespaces) {
|
56
74
|
@content_nodes.each {
|
57
75
|
|name, list|
|
@@ -86,7 +104,7 @@ module GEPUB
|
|
86
104
|
|
87
105
|
CONTENT_NODE_LIST = ['identifier','title', 'language', 'contributor', 'creator', 'coverage', 'date','description','format','publisher','relation','rights','source','subject','type'].each {
|
88
106
|
|node|
|
89
|
-
define_method(node + '_list') { @content_nodes[node].dup }
|
107
|
+
define_method(node + '_list') { @content_nodes[node].dup.sort_as_meta }
|
90
108
|
define_method(node + '_clear') {
|
91
109
|
if !@content_nodes[node].nil?
|
92
110
|
@content_nodes[node].each { |x| unregister_meta(x) };
|
@@ -115,6 +133,17 @@ module GEPUB
|
|
115
133
|
}
|
116
134
|
}
|
117
135
|
|
136
|
+
def meta_list
|
137
|
+
(@content_nodes['meta'] || []).sort_as_meta.dup
|
138
|
+
end
|
139
|
+
|
140
|
+
def meta_clear
|
141
|
+
if !@content_nodes['meta'].nil?
|
142
|
+
@content_nodes['meta'].each { |x| unregister_meta(x) };
|
143
|
+
@content_nodes['meta'] = []
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
118
147
|
def title
|
119
148
|
if !@content_nodes['title'].nil?
|
120
149
|
@content_nodes['title'].each do
|
@@ -127,12 +156,13 @@ module GEPUB
|
|
127
156
|
|
128
157
|
def get_first_node(node)
|
129
158
|
if !@content_nodes[node].nil? && @content_nodes[node].size > 0
|
130
|
-
@content_nodes[node][0]
|
159
|
+
@content_nodes[node].sort_as_meta[0]
|
131
160
|
end
|
132
161
|
end
|
133
162
|
|
134
|
-
def add_identifier(string, id, type=nil)
|
135
|
-
|
163
|
+
def add_identifier(string, id=nil, type=nil)
|
164
|
+
id = @id_pool.generate_key(:prefix => 'BookId') if id.nil?
|
165
|
+
raise "id #{id} is already in use" if @id_pool[id]
|
136
166
|
identifier = add_metadata('identifier', string, id)
|
137
167
|
identifier.refine('identifier-type', type) unless type.nil?
|
138
168
|
identifier
|
@@ -147,12 +177,13 @@ module GEPUB
|
|
147
177
|
|x|
|
148
178
|
return x.content if x['id'] == id
|
149
179
|
}
|
180
|
+
return nil
|
150
181
|
end
|
151
182
|
|
152
183
|
def add_metadata(name, content, id = nil, itemclass = Meta)
|
153
184
|
meta = itemclass.new(name, content, self, { 'id' => id })
|
154
185
|
(@content_nodes[name] ||= []) << meta
|
155
|
-
yield
|
186
|
+
yield meta if block_given?
|
156
187
|
meta
|
157
188
|
end
|
158
189
|
|
@@ -227,15 +258,42 @@ module GEPUB
|
|
227
258
|
@id_pool[meta['id']] = nil
|
228
259
|
end
|
229
260
|
end
|
261
|
+
|
262
|
+
def rendition_layout
|
263
|
+
@layout.content || @default_layout
|
264
|
+
end
|
265
|
+
|
266
|
+
def rendition_layout=(val)
|
267
|
+
@layout = Meta.new('meta', val, self, { 'property' => 'rendition:layout' })
|
268
|
+
(@content_nodes['meta'] ||= []) << @layout
|
269
|
+
end
|
270
|
+
|
271
|
+
def rendition_orientation
|
272
|
+
@orientation.content || @default_orientation
|
273
|
+
end
|
274
|
+
|
275
|
+
def rendition_orientation=(val)
|
276
|
+
@orientation = Meta.new('meta', val, self, { 'property' => 'rendition:orientation' })
|
277
|
+
(@content_nodes['meta'] ||= []) << @orientation
|
278
|
+
end
|
279
|
+
|
280
|
+
def rendition_spread
|
281
|
+
@spread.content || @default_spread
|
282
|
+
end
|
283
|
+
|
284
|
+
def rendition_spread=(val)
|
285
|
+
@spread = Meta.new('meta', val, self, { 'property' => 'rendition:spread' })
|
286
|
+
(@content_nodes['meta'] ||= []) << @spread
|
287
|
+
end
|
230
288
|
|
231
289
|
private
|
232
290
|
def parse_node(ns, node)
|
233
291
|
@xml.xpath("#{ns_prefix(ns)}:#{node}", @namespaces).map {
|
234
|
-
|
|
235
|
-
create_meta(
|
292
|
+
|n|
|
293
|
+
create_meta(n)
|
236
294
|
}
|
237
295
|
end
|
238
|
-
|
296
|
+
|
239
297
|
def create_meta(node)
|
240
298
|
Meta.new(node.name, node.content, self, attr_to_hash(node.attributes), collect_refiners(node['id']))
|
241
299
|
end
|
data/lib/gepub/package.rb
CHANGED
@@ -7,12 +7,21 @@ module GEPUB
|
|
7
7
|
class Package
|
8
8
|
include XMLUtil
|
9
9
|
extend Forwardable
|
10
|
-
attr_accessor :path, :metadata, :manifest, :spine, :bindings, :epub_backward_compat, :contents_prefix
|
10
|
+
attr_accessor :path, :metadata, :manifest, :spine, :bindings, :epub_backward_compat, :contents_prefix, :prefixes
|
11
11
|
def_delegators :@manifest, :item_by_href
|
12
12
|
def_delegators :@metadata, *Metadata::CONTENT_NODE_LIST.map {
|
13
13
|
|x|
|
14
14
|
["#{x}", "#{x}_list", "set_#{x}", "#{x}=", "add_#{x}"]
|
15
15
|
}.flatten
|
16
|
+
def_delegators :@metadata, :set_lastmodified
|
17
|
+
def_delegators :@metadata, :lastmodified
|
18
|
+
def_delegators :@metadata, :rendition_layout
|
19
|
+
def_delegators :@metadata, :rendition_layout=
|
20
|
+
def_delegators :@metadata, :rendition_orientation
|
21
|
+
def_delegators :@metadata, :rendition_orientation=
|
22
|
+
def_delegators :@metadata, :rendition_spread
|
23
|
+
def_delegators :@metadata, :rendition_spread=
|
24
|
+
|
16
25
|
def_delegators :@spine, :page_progression_direction=
|
17
26
|
def_delegators :@spine, :page_progression_direction
|
18
27
|
|
@@ -59,6 +68,12 @@ module GEPUB
|
|
59
68
|
@pool[k] = v
|
60
69
|
end
|
61
70
|
end
|
71
|
+
|
72
|
+
def parse_prefixes(prefix)
|
73
|
+
return {} if prefix.nil?
|
74
|
+
m = prefix.scan(/([\S]+): +(\S+)[\s]*/)
|
75
|
+
Hash[*m.flatten]
|
76
|
+
end
|
62
77
|
|
63
78
|
# parse OPF data. opf should be io or string object.
|
64
79
|
def self.parse_opf(opf, path)
|
@@ -73,6 +88,7 @@ module GEPUB
|
|
73
88
|
@manifest = Manifest.parse(@xml.at_xpath("//#{ns_prefix(OPF_NS)}:manifest"), @attributes['version'], @id_pool)
|
74
89
|
@spine = Spine.parse(@xml.at_xpath("//#{ns_prefix(OPF_NS)}:spine"), @attributes['version'], @id_pool)
|
75
90
|
@bindings = Bindings.parse(@xml.at_xpath("//#{ns_prefix(OPF_NS)}:bindings"))
|
91
|
+
@prefixes = parse_prefixes(@attributes['prefix'])
|
76
92
|
}
|
77
93
|
}
|
78
94
|
end
|
@@ -86,6 +102,7 @@ module GEPUB
|
|
86
102
|
end
|
87
103
|
@contents_prefix = File.dirname(@path).sub(/^\.$/,'')
|
88
104
|
@contents_prefix = @contents_prefix + '/' if @contents_prefix.size > 0
|
105
|
+
@prefixes = {}
|
89
106
|
@namespaces = {'xmlns' => OPF_NS }
|
90
107
|
@attributes = attributes
|
91
108
|
@attributes['version'] ||= '3.0'
|
@@ -120,10 +137,15 @@ module GEPUB
|
|
120
137
|
end
|
121
138
|
|
122
139
|
def identifier=(identifier)
|
123
|
-
|
140
|
+
set_primary_identifier(identifier, nil, nil)
|
124
141
|
end
|
125
142
|
|
126
143
|
def set_main_id(identifier, id = nil, type = nil)
|
144
|
+
warn 'set_main_id is deprecated. use set_primary_identifier instead.'
|
145
|
+
set_primary_identifier(identifier, id, type)
|
146
|
+
end
|
147
|
+
|
148
|
+
def set_primary_identifier(identifier, id = nil, type = nil)
|
127
149
|
set_unique_identifier(id || @id_pool.generate_key(:prefix => 'BookId', :without_count => true))
|
128
150
|
@metadata.add_identifier identifier, unique_identifier, type
|
129
151
|
end
|
@@ -187,6 +209,7 @@ module GEPUB
|
|
187
209
|
@metadata.language
|
188
210
|
end
|
189
211
|
|
212
|
+
#TODO maybe it should be 'epub_version'
|
190
213
|
def version
|
191
214
|
@attributes['version']
|
192
215
|
end
|
@@ -212,6 +235,14 @@ module GEPUB
|
|
212
235
|
version
|
213
236
|
end
|
214
237
|
|
238
|
+
def enable_rendition
|
239
|
+
@prefixes['rendition'] = 'http://www.idpf.org/vocab/rendition/#'
|
240
|
+
end
|
241
|
+
|
242
|
+
def rendition_enabled?
|
243
|
+
@prefixes['rendition'] == 'http://www.idpf.org/vocab/rendition/#'
|
244
|
+
end
|
245
|
+
|
215
246
|
def opf_xml
|
216
247
|
if version.to_f < 3.0 || @epub_backward_compat
|
217
248
|
spine.toc ||= 'ncx'
|
@@ -230,6 +261,12 @@ module GEPUB
|
|
230
261
|
end
|
231
262
|
builder = Nokogiri::XML::Builder.new {
|
232
263
|
|xml|
|
264
|
+
if @prefixes.size == 0
|
265
|
+
@attributes.delete 'prefix'
|
266
|
+
else
|
267
|
+
@attributes['prefix'] = @prefixes.map { |k, v| "#{k}: #{v}" }.join(' ')
|
268
|
+
end
|
269
|
+
|
233
270
|
xml.package(@namespaces.merge(@attributes)) {
|
234
271
|
@metadata.to_xml(xml)
|
235
272
|
@manifest.to_xml(xml)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GEPUB
|
2
|
+
class Rendition
|
3
|
+
class NilContent
|
4
|
+
def self.content
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
@default_layout = 'reflowable'
|
11
|
+
@default_orientation = 'auto'
|
12
|
+
@default_spread = 'auto'
|
13
|
+
@layout = NilContent
|
14
|
+
@orientation = NilContent
|
15
|
+
@spread = NilContent
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_metadata(metadata)
|
19
|
+
@metadata = metadata
|
20
|
+
@metadata.meta_list.each {
|
21
|
+
|metanode|
|
22
|
+
case metanode['property']
|
23
|
+
when 'rendition:layout'
|
24
|
+
@layout = metanode
|
25
|
+
when 'rendition:orientation'
|
26
|
+
@orientation = metanode
|
27
|
+
when 'rendition:spread'
|
28
|
+
@spread = metanode
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def layout
|
34
|
+
@layout.content || @default_layout
|
35
|
+
end
|
36
|
+
|
37
|
+
def orientation
|
38
|
+
@orientation.content || @default_orientation
|
39
|
+
end
|
40
|
+
|
41
|
+
def spread
|
42
|
+
@spread.content || @default_spread
|
43
|
+
end
|
44
|
+
|
45
|
+
def value_map
|
46
|
+
{ 'layout' => layout, 'orientation' => orientation, 'spread' => spread }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -15,8 +15,8 @@ module GEPUB
|
|
15
15
|
@item.set_media_type(val)
|
16
16
|
end
|
17
17
|
|
18
|
-
def method_missing(name, *args)
|
19
|
-
@item.send(name.to_sym, *args)
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
@item.send(name.to_sym, *args, &block)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -83,6 +83,22 @@ module GEPUB
|
|
83
83
|
itemref.page_spread_right
|
84
84
|
end
|
85
85
|
|
86
|
+
def rendition_layout val
|
87
|
+
itemref = @book.spine.itemref_by_id[@last_defined_item.item.id]
|
88
|
+
raise 'rendition should be called inside ordered' if (itemref.nil?)
|
89
|
+
itemref.rendition_layout = val
|
90
|
+
end
|
91
|
+
def rendition_orientation val
|
92
|
+
itemref = @book.spine.itemref_by_id[@last_defined_item.item.id]
|
93
|
+
raise 'rendition should be called inside ordered' if (itemref.nil?)
|
94
|
+
itemref.rendition_orientation = val
|
95
|
+
end
|
96
|
+
def rendition_spread val
|
97
|
+
itemref = @book.spine.itemref_by_id[@last_defined_item.item.id]
|
98
|
+
raise 'rendition should be called inside ordered' if (itemref.nil?)
|
99
|
+
itemref.rendition_spread = val
|
100
|
+
end
|
101
|
+
|
86
102
|
def linear val
|
87
103
|
itemref = @book.spine.itemref_by_id[@last_defined_item.item.id]
|
88
104
|
raise 'linear should be called inside ordered' if (itemref.nil?)
|
@@ -105,6 +121,13 @@ module GEPUB
|
|
105
121
|
def add_resource_dir(name)
|
106
122
|
import "#{name}/resources.conf", :dir_prefix => name
|
107
123
|
end
|
124
|
+
|
125
|
+
def add_resource_dirs(dirs)
|
126
|
+
dirs.each do
|
127
|
+
|dir|
|
128
|
+
add_resource_dir dir
|
129
|
+
end
|
130
|
+
end
|
108
131
|
|
109
132
|
def cover_image(val)
|
110
133
|
file(val)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class SortedArray < Array
|
2
|
+
def initialize(*args, &sort_by)
|
3
|
+
@sort_by = sort_by || Proc.new { |x,y| x <=> y }
|
4
|
+
super(*args)
|
5
|
+
self.sort!() &sort_by
|
6
|
+
end
|
7
|
+
|
8
|
+
def insert(i, v)
|
9
|
+
insert_before = index(find { |x| @sort_by.call(x, v) == 1 })
|
10
|
+
super(insert_before ? insert_before : -1, v)
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(v)
|
14
|
+
insert(0, v)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias push <<
|
18
|
+
alias unshift <<
|
19
|
+
|
20
|
+
end
|
data/lib/gepub/spine.rb
CHANGED
@@ -46,6 +46,22 @@ module GEPUB
|
|
46
46
|
add_property 'page-spread-left'
|
47
47
|
end
|
48
48
|
|
49
|
+
def set_rendition_param(name, val)
|
50
|
+
add_property "rendition:#{name}-#{val}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def rendition_layout=(val)
|
54
|
+
set_rendition_param('layout', val)
|
55
|
+
end
|
56
|
+
|
57
|
+
def rendition_orientation=(val)
|
58
|
+
set_rendition_param('orientation', val)
|
59
|
+
end
|
60
|
+
|
61
|
+
def rendition_spread=(val)
|
62
|
+
set_rendition_param('spread', val)
|
63
|
+
end
|
64
|
+
|
49
65
|
def to_xml(builder, opf_version)
|
50
66
|
attr = @attributes.dup
|
51
67
|
if opf_version.to_f < 3.0
|
@@ -68,7 +84,7 @@ module GEPUB
|
|
68
84
|
@xml = spine_xml
|
69
85
|
@namespaces = @xml.namespaces
|
70
86
|
@attributes = attr_to_hash(@xml.attributes)
|
71
|
-
|
87
|
+
@item_refs = []
|
72
88
|
@xml.xpath("//#{ns_prefix(OPF_NS)}:spine/#{ns_prefix(OPF_NS)}:itemref", @namespaces).map {
|
73
89
|
|itemref|
|
74
90
|
i = Itemref.create(self, attr_to_hash(itemref.attributes))
|
data/lib/gepub/version.rb
CHANGED
data/lib/gepub.rb
CHANGED
data/spec/book_spec.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe GEPUB::Book do
|
6
|
+
context 'on creating new book' do
|
7
|
+
describe 'initialize' do
|
8
|
+
context 'without parameter' do
|
9
|
+
it 'returns empty book' do
|
10
|
+
book = GEPUB::Book.new()
|
11
|
+
expect(book.path) .to eq('OEBPS/package.opf')
|
12
|
+
expect(book.version).to eq('3.0')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
context 'with path' do
|
16
|
+
it 'returns empty book with path' do
|
17
|
+
book = GEPUB::Book.new('mypath/foo.opf')
|
18
|
+
expect(book.path) .to eq('mypath/foo.opf')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
context 'with path and attributes' do
|
22
|
+
it 'returns empty book with path and attributes' do
|
23
|
+
book = GEPUB::Book.new('mypath/book.opf', {'version' => '2.1'});
|
24
|
+
expect(book.path) .to eq('mypath/book.opf')
|
25
|
+
expect(book.version).to eq('2.1')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
describe 'version=' do
|
30
|
+
context 'overwrite version' do
|
31
|
+
it 'will hold new version' do
|
32
|
+
book = GEPUB::Book.new()
|
33
|
+
book.version = '2.1'
|
34
|
+
expect(book.version).to eq('2.1')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
describe 'identifer=' do
|
39
|
+
context 'set identifier' do
|
40
|
+
it 'will set unique-identifier and related attributes' do
|
41
|
+
book = GEPUB::Book.new()
|
42
|
+
book.identifier = 'the-book-identifier'
|
43
|
+
|
44
|
+
expect(book.identifier).to eq('the-book-identifier')
|
45
|
+
expect(book.identifier_list[0]['id']).to eq(book.unique_identifier)
|
46
|
+
expect(book.identifier_list[0].refiner('identifier-type')).to be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
describe 'set_primary_identifier=' do
|
51
|
+
context 'set identifier with id and type' do
|
52
|
+
it 'will set unique-identifier and related attributes' do
|
53
|
+
book = GEPUB::Book.new()
|
54
|
+
book.set_primary_identifier 'http//example.com/the-identifier', 'MyBookID', 'URL'
|
55
|
+
|
56
|
+
expect(book.identifier).to eq('http//example.com/the-identifier')
|
57
|
+
expect(book.unique_identifier).to eq('MyBookID')
|
58
|
+
expect(book.identifier_list[0]['id']).to eq('MyBookID')
|
59
|
+
expect(book.identifier_list[0].identifier_type.content).to eq('URL')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe 'add_identifier' do
|
64
|
+
context 'add new identifier to new book' do
|
65
|
+
it 'will set identifier, and not set unique-identifier' do
|
66
|
+
book = GEPUB::Book.new()
|
67
|
+
book.add_identifier 'newid'
|
68
|
+
expect(book.unique_identifier).to be_nil
|
69
|
+
expect(book.identifier).to be_nil
|
70
|
+
expect(book.identifier_list[0].content).to eq('newid')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
context 'add new identifier to existing book' do
|
74
|
+
it 'will set new identifier' do
|
75
|
+
book = GEPUB::Book.new()
|
76
|
+
book.identifier = 'theIdentifier'
|
77
|
+
book.add_identifier 'http://example.jp/additional_identifier', nil, 'URL'
|
78
|
+
expect(book.identifier).to eq('theIdentifier')
|
79
|
+
expect(book.identifier_list[1].content).to eq('http://example.jp/additional_identifier')
|
80
|
+
expect(book.identifier_list[1].identifier_type.content).to eq('URL')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
describe 'add_title' do
|
85
|
+
context 'add title' do
|
86
|
+
it 'adds new title' do
|
87
|
+
book = GEPUB::Book.new()
|
88
|
+
book.title = 'the title'
|
89
|
+
book.add_title 'new title'
|
90
|
+
expect(book.title.to_s).to eq('the title')
|
91
|
+
expect(book.title_list[1].to_s).to eq('new title')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
describe 'title =' do
|
96
|
+
context 'set first title' do
|
97
|
+
it 'will add new title' do
|
98
|
+
book = GEPUB::Book.new()
|
99
|
+
book.title = 'the title'
|
100
|
+
expect(book.title.to_s).to eq('the title')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
context 'clear and set title' do
|
104
|
+
it 'will clear title and add new title' do
|
105
|
+
book = GEPUB::Book.new()
|
106
|
+
book.add_title 'the title'
|
107
|
+
book.title = 'new title'
|
108
|
+
expect(book.title.to_s).to eq('new title')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
describe 'title' do
|
113
|
+
context 'main title is specified' do
|
114
|
+
it 'returns main title' do
|
115
|
+
book = GEPUB::Book.new()
|
116
|
+
book.add_title 'sub title'
|
117
|
+
book.add_title('the main title', nil, GEPUB::TITLE_TYPE::MAIN)
|
118
|
+
expect(book.title.to_s).to eq('the main title')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
context 'display_seq is specified' do
|
122
|
+
it 'returns first title' do
|
123
|
+
book = GEPUB::Book.new()
|
124
|
+
book.add_title 'second title'
|
125
|
+
book.add_title('first title') do
|
126
|
+
|title|
|
127
|
+
title.display_seq = 1
|
128
|
+
end
|
129
|
+
expect(book.title.to_s).to eq('first title')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
describe 'title_list' do
|
134
|
+
context 'main title is specified' do
|
135
|
+
it 'returns titles in defined order' do
|
136
|
+
book = GEPUB::Book.new()
|
137
|
+
book.add_title 'sub title'
|
138
|
+
book.add_title('the main title', nil, GEPUB::TITLE_TYPE::MAIN)
|
139
|
+
expect(book.title_list[0].to_s).to eq('sub title')
|
140
|
+
expect(book.title_list[1].to_s).to eq('the main title')
|
141
|
+
end
|
142
|
+
context 'display seq is specified' do
|
143
|
+
it 'returns titles in display-seq order' do
|
144
|
+
book = GEPUB::Book.new()
|
145
|
+
book.add_title 'third title'
|
146
|
+
book.add_title 'fourth title'
|
147
|
+
book.add_title 'second title' do
|
148
|
+
|title|
|
149
|
+
title.display_seq = 2
|
150
|
+
end
|
151
|
+
book.add_title('first title') do
|
152
|
+
|title|
|
153
|
+
title.display_seq = 1
|
154
|
+
end
|
155
|
+
expect(book.title_list[0].to_s).to eq('first title')
|
156
|
+
expect(book.title_list[1].to_s).to eq('second title')
|
157
|
+
expect(book.title_list[2].to_s).to eq('third title')
|
158
|
+
expect(book.title_list[3].to_s).to eq('fourth title')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
describe 'add_creator' do
|
164
|
+
it 'adds new creator' do
|
165
|
+
book = GEPUB::Book.new()
|
166
|
+
book.creator = 'the creator'
|
167
|
+
book.add_creator 'new creator'
|
168
|
+
expect(book.creator.to_s).to eq('the creator')
|
169
|
+
expect(book.creator_list[1].to_s).to eq('new creator')
|
170
|
+
end
|
171
|
+
end
|
172
|
+
describe 'creator=' do
|
173
|
+
it 'set first creator' do
|
174
|
+
book = GEPUB::Book.new()
|
175
|
+
book.creator = 'the creator'
|
176
|
+
expect(book.creator.to_s).to eq('the creator')
|
177
|
+
end
|
178
|
+
it 'clear and set creator' do
|
179
|
+
book = GEPUB::Book.new()
|
180
|
+
book.creator = 'the creator'
|
181
|
+
book.creator = 'new creator'
|
182
|
+
expect(book.creator.to_s).to eq('new creator')
|
183
|
+
expect(book.creator_list.size).to eq(1)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
describe 'creator' do
|
187
|
+
context 'display seq is specified' do
|
188
|
+
it 'shows creator with smallest display-seq' do
|
189
|
+
book = GEPUB::Book.new()
|
190
|
+
book.add_creator 'a creator'
|
191
|
+
book.add_creator('second creator') do
|
192
|
+
|creator|
|
193
|
+
creator.display_seq = 2
|
194
|
+
end
|
195
|
+
expect(book.creator.to_s).to eq('second creator')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe 'creator_list' do
|
201
|
+
context 'display seq is specified' do
|
202
|
+
it 'returns creators in display-seq order' do
|
203
|
+
book = GEPUB::Book.new()
|
204
|
+
book.add_creator 'a creator'
|
205
|
+
book.add_creator('second creator') do
|
206
|
+
|creator|
|
207
|
+
creator.display_seq = 2
|
208
|
+
end
|
209
|
+
book.add_creator 'another creator'
|
210
|
+
book.add_creator('first creator') do
|
211
|
+
|creator|
|
212
|
+
creator.display_seq = 1
|
213
|
+
end
|
214
|
+
book.add_creator('third creator') do
|
215
|
+
|creator|
|
216
|
+
creator.display_seq = 3
|
217
|
+
end
|
218
|
+
expect(book.creator_list[0].to_s).to eq('first creator')
|
219
|
+
expect(book.creator_list[1].to_s).to eq('second creator')
|
220
|
+
expect(book.creator_list[2].to_s).to eq('third creator')
|
221
|
+
expect(book.creator_list[3].to_s).to eq('a creator')
|
222
|
+
expect(book.creator_list[4].to_s).to eq('another creator')
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# omit tests for setter/getter for contributor, publisher, date etc; these methods use same implementation as creator.
|
228
|
+
|
229
|
+
describe 'set_lastmodified' do
|
230
|
+
it 'set current time' do
|
231
|
+
book = GEPUB::Book.new
|
232
|
+
now = Time.now
|
233
|
+
book.set_lastmodified
|
234
|
+
expect((book.lastmodified.content - now).abs).to be < 2
|
235
|
+
end
|
236
|
+
it 'set time in string' do
|
237
|
+
book = GEPUB::Book.new
|
238
|
+
book.set_lastmodified(Time.parse('2012-9-12 00:00:00Z'))
|
239
|
+
expect(book.lastmodified.content).to eq(Time.parse('2012-9-12 00:00:00 UTC'))
|
240
|
+
end
|
241
|
+
end
|
242
|
+
describe 'page_progression_direction=' do
|
243
|
+
it 'set page_progression_direction' do
|
244
|
+
book = GEPUB::Book.new
|
245
|
+
book.page_progression_direction= 'rtl'
|
246
|
+
expect(book.page_progression_direction).to eq('rtl')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
describe 'add_optional_file' do
|
250
|
+
context 'add apple specific option file' do
|
251
|
+
it 'is added to book' do
|
252
|
+
content = <<-EOF
|
253
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
254
|
+
<display_options>
|
255
|
+
<platform name="*">
|
256
|
+
<option name="fixed-layout">true</option>
|
257
|
+
</platform>
|
258
|
+
</display_options>
|
259
|
+
EOF
|
260
|
+
book = GEPUB::Book.new
|
261
|
+
book.add_optional_file('META-INF/com.apple.ibooks.display-options.xm', StringIO.new(content))
|
262
|
+
|
263
|
+
expect(book.optional_files.size).to eq(1)
|
264
|
+
expect(book.optional_files['META-INF/com.apple.ibooks.display-options.xm']).to eq(content)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
describe 'add_item' do
|
269
|
+
end
|
270
|
+
describe 'add_ordered_item' do
|
271
|
+
end
|
272
|
+
describe 'ordered' do
|
273
|
+
end
|
274
|
+
describe 'write_to_epub_container' do
|
275
|
+
context 'create typical book' do
|
276
|
+
end
|
277
|
+
context 'create very complex book' do
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
context 'on parsing existing book' do
|
282
|
+
describe '.parse' do
|
283
|
+
context 'IO Object' do
|
284
|
+
it 'loads book and returns GEPUB::Book object' do
|
285
|
+
filehandle = File.new(File.dirname(__FILE__) + '/fixtures/testdata/wasteland-20120118.epub')
|
286
|
+
book = GEPUB::Book.parse(filehandle)
|
287
|
+
expect(book).to be_instance_of GEPUB::Book
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
data/spec/builder_spec.rb
CHANGED
@@ -356,6 +356,25 @@ describe GEPUB::Builder do
|
|
356
356
|
builder.instance_eval{ @book.spine.itemref_list[1].properties[0] }.should == 'page-spread-right'
|
357
357
|
end
|
358
358
|
|
359
|
+
it 'should add files and rendition property' do
|
360
|
+
workdir = File.join(File.dirname(__FILE__),'fixtures', 'builder')
|
361
|
+
builder = GEPUB::Builder.new {
|
362
|
+
resources(:workdir => workdir) {
|
363
|
+
ordered {
|
364
|
+
file('text/cover.xhtml')
|
365
|
+
file('text/memo.txt')
|
366
|
+
rendition_layout 'pre-paginated'
|
367
|
+
rendition_orientation 'landscape'
|
368
|
+
rendition_spread 'both'
|
369
|
+
}
|
370
|
+
}
|
371
|
+
}
|
372
|
+
builder.instance_eval{ @book.item_by_href('text/memo.txt') }.should_not be_nil
|
373
|
+
builder.instance_eval{ @book.spine.itemref_list[1].properties[0] }.should == 'rendition:layout-pre-paginated'
|
374
|
+
builder.instance_eval{ @book.spine.itemref_list[1].properties[1] }.should == 'rendition:orientation-landscape'
|
375
|
+
builder.instance_eval{ @book.spine.itemref_list[1].properties[2] }.should == 'rendition:spread-both'
|
376
|
+
end
|
377
|
+
|
359
378
|
it 'should handle fallback chain' do
|
360
379
|
workdir = File.join(File.dirname(__FILE__),'fixtures', 'builder')
|
361
380
|
builder = GEPUB::Builder.new {
|
@@ -1,6 +1,11 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
2
|
|
3
|
-
<package xmlns="http://www.idpf.org/2007/opf" version="3.0"
|
3
|
+
<package xmlns="http://www.idpf.org/2007/opf" version="3.0"
|
4
|
+
unique-identifier="pub-id"
|
5
|
+
xml:lang="ja"
|
6
|
+
prefix="foaf: http://xmlns.com/foaf/spec/
|
7
|
+
rendition: http://www.idpf.org/vocab/rendition/#"
|
8
|
+
>
|
4
9
|
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" >
|
5
10
|
<dc:identifier id="pub-id">urn:uuid:1234567890</dc:identifier>
|
6
11
|
<meta refines="#pub-id" property="identifier-type" scheme="xsd:string">uuid</meta>
|
@@ -34,6 +39,10 @@
|
|
34
39
|
|
35
40
|
<meta property="dcterms:issued" id="issued">2012-02-12T15:00:00Z</meta>
|
36
41
|
<meta property="dcterms:modified" id="modified">2012-02-12T19:00:00Z</meta>
|
42
|
+
|
43
|
+
<meta property="rendition:layout">pre-paginated</meta>
|
44
|
+
<meta property="rendition:spread">both</meta>
|
45
|
+
|
37
46
|
<meta name="cover" content="cover-image" />
|
38
47
|
</metadata>
|
39
48
|
|
@@ -57,4 +66,4 @@
|
|
57
66
|
<itemref idref="nav" linear="no" />
|
58
67
|
</spine>
|
59
68
|
|
60
|
-
</package>
|
69
|
+
</package>
|
Binary file
|
data/spec/package_spec.rb
CHANGED
@@ -8,6 +8,7 @@ describe GEPUB::Package do
|
|
8
8
|
opf = GEPUB::Package.new('/package.opf')
|
9
9
|
opf.ns_prefix(GEPUB::XMLUtil::OPF_NS).should == 'xmlns'
|
10
10
|
end
|
11
|
+
|
11
12
|
context 'parse existing opf' do
|
12
13
|
it 'should be initialized with opf' do
|
13
14
|
opf = GEPUB::Package.parse_opf(File.open(File.dirname(__FILE__) + '/fixtures/testdata/test.opf'), '/package.opf')
|
@@ -15,8 +16,24 @@ describe GEPUB::Package do
|
|
15
16
|
opf['version'].should == '3.0'
|
16
17
|
opf['unique-identifier'].should == 'pub-id'
|
17
18
|
opf['xml:lang'].should == 'ja'
|
19
|
+
opf['prefix'].should == 'foaf: http://xmlns.com/foaf/spec/ rendition: http://www.idpf.org/vocab/rendition/#'
|
20
|
+
end
|
21
|
+
it 'should parse prefix data' do
|
22
|
+
package = GEPUB::Package.parse_opf(File.open(File.dirname(__FILE__) + '/fixtures/testdata/test.opf'), '/package.opf')
|
23
|
+
package.prefixes.size.should == 2
|
24
|
+
package.prefixes['foaf'].should == 'http://xmlns.com/foaf/spec/'
|
25
|
+
package.prefixes['rendition'].should == 'http://www.idpf.org/vocab/rendition/#'
|
26
|
+
|
18
27
|
end
|
19
|
-
|
28
|
+
|
29
|
+
it 'should parse rendition metadata' do
|
30
|
+
package = GEPUB::Package.parse_opf(File.open(File.dirname(__FILE__) + '/fixtures/testdata/test.opf'), '/package.opf')
|
31
|
+
package.rendition_layout.should == 'pre-paginated'
|
32
|
+
package.rendition_orientation.should == 'auto'
|
33
|
+
package.rendition_spread.should == 'both'
|
34
|
+
|
35
|
+
end
|
36
|
+
|
20
37
|
end
|
21
38
|
context 'generate new opf' do
|
22
39
|
it 'should generate opf' do
|
@@ -58,6 +75,30 @@ describe GEPUB::Package do
|
|
58
75
|
# TODO: should check all elements
|
59
76
|
end
|
60
77
|
|
78
|
+
it 'should generate package with prefix attribute' do
|
79
|
+
package = GEPUB::Package.new('OEBPS/package.opf') do
|
80
|
+
|package|
|
81
|
+
package.set_main_id('http://example.jp', 'BookID', 'url')
|
82
|
+
package['xml:lang'] = 'ja'
|
83
|
+
package.enable_rendition
|
84
|
+
end
|
85
|
+
xml = Nokogiri::XML::Document.parse package.opf_xml
|
86
|
+
xml.root['prefix'].should == 'rendition: http://www.idpf.org/vocab/rendition/#'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should generate package with rendition attributes' do
|
90
|
+
package = GEPUB::Package.new('OEBPS/package.opf') do
|
91
|
+
|package|
|
92
|
+
package.rendition_layout = 'pre-paginated'
|
93
|
+
package.rendition_orientation = 'portlait'
|
94
|
+
package.rendition_spread = 'landscape'
|
95
|
+
end
|
96
|
+
xml = Nokogiri::XML::Document.parse package.opf_xml
|
97
|
+
xml.at_xpath("//xmlns:meta[@property='rendition:layout']").content.should == 'pre-paginated'
|
98
|
+
xml.at_xpath("//xmlns:meta[@property='rendition:orientation']").content.should == 'portlait'
|
99
|
+
xml.at_xpath("//xmlns:meta[@property='rendition:spread']").content.should == 'landscape'
|
100
|
+
end
|
101
|
+
|
61
102
|
it 'should generate opf2.0' do
|
62
103
|
opf = GEPUB::Package.new('OEBPS/package.opf', { 'version' => '2.0'}) {
|
63
104
|
|opf|
|
@@ -94,6 +135,5 @@ describe GEPUB::Package do
|
|
94
135
|
xml.root['version'].should == '2.0'
|
95
136
|
xml.root['lang'].should == 'ja'
|
96
137
|
end
|
97
|
-
|
98
138
|
end
|
99
139
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gepub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.8.
|
4
|
+
version: 0.6.8.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2'
|
21
|
+
version: '2.11'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.11'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: nokogiri
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ~>
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: 1.5.0
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rubyzip
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,7 +53,12 @@ dependencies:
|
|
43
53
|
version: 0.9.7
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.7
|
47
62
|
description: gepub is a generic EPUB parser/generator. Generates and parse EPUB2 and
|
48
63
|
EPUB3
|
49
64
|
email:
|
@@ -76,13 +91,17 @@ files:
|
|
76
91
|
- lib/gepub/item.rb
|
77
92
|
- lib/gepub/manifest.rb
|
78
93
|
- lib/gepub/meta.rb
|
94
|
+
- lib/gepub/meta_array.rb
|
79
95
|
- lib/gepub/metadata.rb
|
80
96
|
- lib/gepub/package.rb
|
97
|
+
- lib/gepub/rendition.rb
|
81
98
|
- lib/gepub/resource_builder.rb
|
99
|
+
- lib/gepub/sorted_array.rb
|
82
100
|
- lib/gepub/spine.rb
|
83
101
|
- lib/gepub/version.rb
|
84
102
|
- lib/gepub/xml_util.rb
|
85
103
|
- spec/bindings_spec.rb
|
104
|
+
- spec/book_spec.rb
|
86
105
|
- spec/builder_spec.rb
|
87
106
|
- spec/example_spec.rb
|
88
107
|
- spec/fixtures/builder/img/cover.jpg
|
@@ -108,6 +127,7 @@ files:
|
|
108
127
|
- spec/fixtures/testdata/test.opf
|
109
128
|
- spec/fixtures/testdata/test2.opf
|
110
129
|
- spec/fixtures/testdata/test_with_bindings.opf
|
130
|
+
- spec/fixtures/testdata/wasteland-20120118.epub
|
111
131
|
- spec/gepub_spec.rb
|
112
132
|
- spec/manifest_spec.rb
|
113
133
|
- spec/metadata_spec.rb
|
@@ -134,12 +154,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
154
|
version: '0'
|
135
155
|
requirements: []
|
136
156
|
rubyforge_project: gepub
|
137
|
-
rubygems_version: 1.8.
|
157
|
+
rubygems_version: 1.8.23
|
138
158
|
signing_key:
|
139
159
|
specification_version: 3
|
140
160
|
summary: a generic EPUB library for Ruby.
|
141
161
|
test_files:
|
142
162
|
- spec/bindings_spec.rb
|
163
|
+
- spec/book_spec.rb
|
143
164
|
- spec/builder_spec.rb
|
144
165
|
- spec/example_spec.rb
|
145
166
|
- spec/fixtures/builder/img/cover.jpg
|
@@ -165,6 +186,7 @@ test_files:
|
|
165
186
|
- spec/fixtures/testdata/test.opf
|
166
187
|
- spec/fixtures/testdata/test2.opf
|
167
188
|
- spec/fixtures/testdata/test_with_bindings.opf
|
189
|
+
- spec/fixtures/testdata/wasteland-20120118.epub
|
168
190
|
- spec/gepub_spec.rb
|
169
191
|
- spec/manifest_spec.rb
|
170
192
|
- spec/metadata_spec.rb
|