gepub 0.6.8.5 → 0.6.8.6
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.
- 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
|