gepub 0.6.4.6 → 0.6.5.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.
- data/gepub.gemspec +3 -3
- data/lib/gepub/book.rb +43 -15
- data/lib/gepub/builder.rb +163 -0
- data/lib/gepub/item.rb +58 -21
- data/lib/gepub/rubyzip_patch.rb +11 -0
- data/lib/gepub/version.rb +2 -1
- data/lib/gepub.rb +1 -1
- data/spec/builder_spec.rb +60 -0
- data/spec/gepub_spec.rb +7 -1
- metadata +13 -12
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", "
|
22
|
-
s.add_runtime_dependency "nokogiri", "
|
23
|
-
s.add_runtime_dependency "rubyzip", "
|
21
|
+
s.add_development_dependency "rspec", "~> 2"
|
22
|
+
s.add_runtime_dependency "nokogiri", "~> 1.5.0"
|
23
|
+
s.add_runtime_dependency "rubyzip", "= 0.9.6.1"
|
24
24
|
end
|
data/lib/gepub/book.rb
CHANGED
@@ -7,19 +7,23 @@ require 'fileutils'
|
|
7
7
|
# = GEPUB
|
8
8
|
# Author:: KOJIMA Satoshi
|
9
9
|
# namespace for gepub library.
|
10
|
-
# GEPUB::Book
|
11
|
-
# GEPUB::
|
10
|
+
# The core class is GEPUB::Book. It holds metadata and contents of EPUB file. metadata and contents can be accessed
|
11
|
+
# through GEPUB::Meta and GEPUB::Item.
|
12
|
+
# For generating EPUB file, use GEPUB::Builder.
|
13
|
+
# GEPUB::Item holds information and data of resources like xhtml text, css, scripts, images, videos, etc.
|
12
14
|
# GEPUB::Meta holds metadata(title, creator, publisher, etc.) with its information (alternate script, display sequence, etc.)
|
13
15
|
|
14
16
|
module GEPUB
|
15
|
-
# Book is the
|
17
|
+
# Book is the class to hold data in EPUB files.
|
16
18
|
#
|
17
|
-
# It can generate and parse EPUB2/EPUB3 files.
|
18
|
-
#
|
19
|
-
#
|
19
|
+
# It can generate and parse EPUB2/EPUB3 files.
|
20
|
+
#
|
21
|
+
# If you want to generate a new EPUB file, consider using GEPUB::Builder instead
|
22
|
+
# of using Book directly.
|
23
|
+
# Builder is a wrapper class of Book specialized for generating EPUB.
|
20
24
|
#
|
21
25
|
# Book delegates many methods to objects in other class, so you can't find
|
22
|
-
# them in Book#methods or in ri/rdoc documentation. Their
|
26
|
+
# them in Book#methods or in ri/rdoc documentation. Their descriptions are below.
|
23
27
|
#
|
24
28
|
# == \Package Attributes
|
25
29
|
# === Book#version (delegated to Package#version)
|
@@ -133,7 +137,7 @@ module GEPUB
|
|
133
137
|
end
|
134
138
|
}
|
135
139
|
book = Book.new(package.path)
|
136
|
-
book.instance_eval { @package = package; @
|
140
|
+
book.instance_eval { @package = package; @optional_files = files }
|
137
141
|
book
|
138
142
|
}
|
139
143
|
end
|
@@ -150,6 +154,22 @@ module GEPUB
|
|
150
154
|
yield book if block_given?
|
151
155
|
end
|
152
156
|
|
157
|
+
|
158
|
+
# Get optional(not required in EPUB specification) files in the container.
|
159
|
+
def optional_files
|
160
|
+
@optional_files || {}
|
161
|
+
end
|
162
|
+
|
163
|
+
# Add an optional file to the container
|
164
|
+
def add_optional_file(path, io_or_filename)
|
165
|
+
io = io_or_filename
|
166
|
+
if io_or_filename.class == String
|
167
|
+
io = File.new(io_or_filename)
|
168
|
+
end
|
169
|
+
io.binmode
|
170
|
+
(@optional_files ||= {})[path] = io.read
|
171
|
+
end
|
172
|
+
|
153
173
|
# add navigation text (which will appear on navigation document or table of contents) to an item.
|
154
174
|
# DEPRECATED: please use Item#toc_text or Item#toc_text_with_id, or Builder#heading
|
155
175
|
|
@@ -236,22 +256,30 @@ module GEPUB
|
|
236
256
|
end
|
237
257
|
|
238
258
|
# write EPUB to stream specified by the argument.
|
239
|
-
def write_to_epub_container(epub)
|
259
|
+
def write_to_epub_container(epub)
|
240
260
|
epub.put_next_entry('mimetype', '', '', Zip::ZipEntry::STORED)
|
241
261
|
epub << "application/epub+zip"
|
242
|
-
epub.put_next_entry('META-INF/container.xml')
|
243
|
-
epub << container_xml.force_to_bin
|
244
262
|
|
245
|
-
|
246
|
-
|
263
|
+
entries = {}
|
264
|
+
optional_files.each {
|
265
|
+
|k, content|
|
266
|
+
entries[k] = content
|
267
|
+
}
|
247
268
|
|
269
|
+
entries['META-INF/container.xml'] = container_xml
|
270
|
+
entries[@package.path] = opf_xml
|
248
271
|
@package.manifest.item_list.each {
|
249
272
|
|k, item|
|
250
273
|
if item.content != nil
|
251
|
-
|
252
|
-
epub << item.content.force_to_bin
|
274
|
+
entries[@package.contents_prefix + item.href] = item.content
|
253
275
|
end
|
254
276
|
}
|
277
|
+
|
278
|
+
entries.sort_by { |k,v| k }.each {
|
279
|
+
|k,v|
|
280
|
+
epub.put_next_entry(k)
|
281
|
+
epub << v.force_to_bin
|
282
|
+
}
|
255
283
|
end
|
256
284
|
|
257
285
|
# generates and returns StringIO contains EPUB.
|
data/lib/gepub/builder.rb
CHANGED
@@ -1,4 +1,152 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module GEPUB
|
3
|
+
#
|
4
|
+
# Builder is a wrapper class of Book. It provides DSL to create new EPUB file.
|
5
|
+
#
|
6
|
+
# = Synopsys
|
7
|
+
# # -*- coding: utf-8 -*-
|
8
|
+
# # GEPUB::Builder example.
|
9
|
+
# require 'ruby gem'
|
10
|
+
# require 'gepub'
|
11
|
+
#
|
12
|
+
# builder = GEPUB::Builder.new {
|
13
|
+
# # In the root block, you can define metadata.
|
14
|
+
# # You can define title, creator(s), contributor(s), publisher(s), date, unique_identifier, identifier, language.
|
15
|
+
# # Title can be specified with title, subtitle, collection, short_title, expanded_title, edition.
|
16
|
+
# # You can also define description, format, relation, right, source, subject, type.
|
17
|
+
# # You can 'refine' last-defined metadata by refiner/attributes methods
|
18
|
+
# # Refiner methods contains : file_as, alt
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# language 'ja'
|
22
|
+
#
|
23
|
+
# title 'タイトル'
|
24
|
+
# alt 'en' => 'main title'
|
25
|
+
# file_as 'main title'
|
26
|
+
#
|
27
|
+
# subtitle 'サブタイトル'
|
28
|
+
# alt 'en' => 'subtitle'
|
29
|
+
#
|
30
|
+
# # collection title and position in the collection:
|
31
|
+
# collection 'gepub sample book series', 2
|
32
|
+
#
|
33
|
+
# #specifying creator
|
34
|
+
# creator 'author1','aut'
|
35
|
+
# alt 'ja' =>'日本語名' ,'en' =>'english name for author1'
|
36
|
+
# id 'the_first_author'
|
37
|
+
#
|
38
|
+
# #specifying multiple creator
|
39
|
+
# creators 'author1', 'author2', ['editor1', 'edt']
|
40
|
+
#
|
41
|
+
# contributor 'contributor'
|
42
|
+
# contributors 'contributor1', 'contributor2'
|
43
|
+
# # easy way to write alt {'ja' =>'日本語 for contributor1'}, {'ja' => '日本語 for contributor2'}
|
44
|
+
# alts 'ja' => ['日本語 for contributor1','日本語 for contributor2']
|
45
|
+
#
|
46
|
+
# publisher '出版社'
|
47
|
+
# alt 'en' => 'ThePublisher'
|
48
|
+
#
|
49
|
+
# date '2012-02-21T00:00:00Z'
|
50
|
+
#
|
51
|
+
# unique_identifier 'the_unique_id_in_uuid', 'uuid'
|
52
|
+
# identifier 'http://other_id','url'
|
53
|
+
# identifier 'http://another_id','url'
|
54
|
+
#
|
55
|
+
# # in resources block, you can define resources by its relative path and datasource.
|
56
|
+
# # item creator methods are: files, file.
|
57
|
+
# resources(:workdir => '~/epub_source') {
|
58
|
+
# # Reads from file. in EPUB container, they are placed at the same path.
|
59
|
+
# file 'img/image0.jpg'
|
60
|
+
# files('img/image.jpg','img/image2.jpg')
|
61
|
+
# glob 'img/*.jpg' # means files(Dir.glob('img/*.jpg'))
|
62
|
+
#
|
63
|
+
# # Reads from file. will be placed at path indicated by key.
|
64
|
+
# files('img/image.jpg' => 'imgage.jpg')
|
65
|
+
#
|
66
|
+
# # Read from IO object.
|
67
|
+
# files('img/image.png' => supplied_io, 'img/image2.png' => supplied_io2)
|
68
|
+
#
|
69
|
+
# # this will be end in error:
|
70
|
+
# # files(io1, io2)
|
71
|
+
#
|
72
|
+
# # specify remote resource.
|
73
|
+
# # only referenced from the EPUB package.
|
74
|
+
# file 'http://example.com/video/remote_video.qt'
|
75
|
+
# media_type('video/quicktime')
|
76
|
+
#
|
77
|
+
# # specify media type.
|
78
|
+
# file 'resources/pv.mp4'
|
79
|
+
# media_type('video/mp4')
|
80
|
+
#
|
81
|
+
# files('audio/voice1.mp4','audio/music1.mp4')
|
82
|
+
# media_type('audio/mp4') # applied to all items in the line above.
|
83
|
+
#
|
84
|
+
# # media_type to some file
|
85
|
+
# with_media_type('video/mp4') {
|
86
|
+
# file 'resources/v1.mp4'
|
87
|
+
# file 'resources/v2.mp4'
|
88
|
+
# file 'resources/v3.mp4'
|
89
|
+
# }
|
90
|
+
#
|
91
|
+
# # with_media_type and media_type
|
92
|
+
# with_media_type('video/mp4') {
|
93
|
+
# file 'resources/v1.mp4'
|
94
|
+
# file 'resources/v2.mp4'
|
95
|
+
# file 'resources/a4.mp4'
|
96
|
+
# media_type 'audio/mp4' # override with_media_type
|
97
|
+
# }
|
98
|
+
#
|
99
|
+
# # Read from IO object: loop
|
100
|
+
# # supplied_IOs = { 'path' => io, 'path' => io... }
|
101
|
+
# supplied_IOs.each {
|
102
|
+
# |name, io|
|
103
|
+
# file name => io
|
104
|
+
# }
|
105
|
+
#
|
106
|
+
# file 'css/default.css'
|
107
|
+
#
|
108
|
+
# # indicate property.
|
109
|
+
# # this is cover image.
|
110
|
+
# cover_image 'img/cover.jpg'
|
111
|
+
#
|
112
|
+
# # this is navigation document.
|
113
|
+
# nav 'text/toc.xhtml'
|
114
|
+
#
|
115
|
+
# # ordered item. will be added to spine.
|
116
|
+
# ordered {
|
117
|
+
# # specify texts on table of contents for auto-generated toc.
|
118
|
+
# # (if you supply navigation document with method 'nav', 'heading' has no effect.)
|
119
|
+
# file('text/chap1.xhtml')
|
120
|
+
# heading 'Chapter 1'
|
121
|
+
# file 'text/chap2.xhtml'
|
122
|
+
#
|
123
|
+
# # fallback chain: style 1
|
124
|
+
# fallback_group {
|
125
|
+
# file 'chap3_docbook.xhtml'
|
126
|
+
# mimetype('application/docbook+xml')
|
127
|
+
# file 'chap3.xml'
|
128
|
+
# mimetype "application/z3986-auth+xml"
|
129
|
+
# file 'chap3.xhtml'
|
130
|
+
# }
|
131
|
+
#
|
132
|
+
# # fallback chain: style 2
|
133
|
+
# fallback_chain_files 'chap4_docbook.xhtml', 'chap4.xml', 'chap4.xhtml'
|
134
|
+
# mimetype('application/docbook+xml','application/z3986-auth+xml' 'application/xhtml+xml')
|
135
|
+
#
|
136
|
+
# # fallback chain: style 3 + with_mimetype
|
137
|
+
# with_mimetype('application/docbook+xml','application/z3986-auth+xml' 'application/xhtml+xml') {
|
138
|
+
# fallback_chain_files 'chap5_docbook.xhtml', 'chap5.xml', 'chap5.xhtml'
|
139
|
+
# fallback_chain_files 'chap6_docbook.xhtml', 'chap6.xml', 'chap6.xhtml'
|
140
|
+
# fallback_chain_files 'chap7_docbook.xhtml', 'chap7.xml', 'chap7.xhtml'
|
141
|
+
# }
|
142
|
+
#
|
143
|
+
# }
|
144
|
+
# }
|
145
|
+
# }
|
146
|
+
#
|
147
|
+
# builder.generate_epub('sample.epub')
|
148
|
+
|
149
|
+
|
2
150
|
class Builder
|
3
151
|
include BuilderMixin
|
4
152
|
class MetaItem
|
@@ -112,6 +260,21 @@ module GEPUB
|
|
112
260
|
MetaItem.new(@book.add_contributor(val, nil, role))
|
113
261
|
end
|
114
262
|
|
263
|
+
# set optional file.
|
264
|
+
# val should be String or Hash.
|
265
|
+
# if val is String, file is read from the File specified by string and stored in EPUB to the path specified by string.
|
266
|
+
# if val is Hash, file is read from the value and stored in EPUB to the path specified by the key.
|
267
|
+
def optional_file(val)
|
268
|
+
path = val
|
269
|
+
io = val if String === val
|
270
|
+
if Hash === val
|
271
|
+
raise 'argument to optional_file should be length 1' if val.size != 1
|
272
|
+
path = val.first[0]
|
273
|
+
io = val.first[1]
|
274
|
+
end
|
275
|
+
@book.add_optional_file(path, io)
|
276
|
+
end
|
277
|
+
|
115
278
|
def generate_epub(path_to_epub)
|
116
279
|
@book.generate_epub(path_to_epub)
|
117
280
|
end
|
data/lib/gepub/item.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
module GEPUB
|
2
|
+
#
|
3
|
+
# an Object to hold metadata and content of item in manifest.
|
4
|
+
#
|
5
|
+
# following methods are created dynamically.
|
6
|
+
# #id, #id=, #set_id, #href, #href=, #set_href, #media_type, #media_type=, #set_media_type,
|
7
|
+
# #fallback, #fallback=, #set_fallback, #media_overlay, #media_overlay=, #set_media_overlay
|
2
8
|
class Item
|
3
9
|
attr_accessor :content
|
4
10
|
def self.create(parent, attributes = {})
|
@@ -6,6 +12,12 @@ module GEPUB
|
|
6
12
|
attributes.reject { |k,v| ['id','href','media-type'].member?(k) })
|
7
13
|
end
|
8
14
|
|
15
|
+
#
|
16
|
+
# create Item.
|
17
|
+
#
|
18
|
+
# if mediatype is not specified, it will be guessed from extension name.
|
19
|
+
# Item can't guess media type for videos and audios, so you should specify one.
|
20
|
+
#
|
9
21
|
def initialize(itemid, itemhref, itemmediatype = nil, parent = nil, attributes = {})
|
10
22
|
if attributes['properties'].class == String
|
11
23
|
attributes['properties'] = attributes['properties'].split(' ')
|
@@ -14,7 +26,6 @@ module GEPUB
|
|
14
26
|
@attributes['media-type'] = guess_mediatype if media_type.nil?
|
15
27
|
@parent = parent
|
16
28
|
@parent.register_item(self) unless @parent.nil?
|
17
|
-
@content_callback = []
|
18
29
|
self
|
19
30
|
end
|
20
31
|
|
@@ -25,14 +36,16 @@ module GEPUB
|
|
25
36
|
define_method(methodbase) { @attributes[name] }
|
26
37
|
}
|
27
38
|
|
39
|
+
# get item's id
|
28
40
|
def itemid
|
29
41
|
id
|
30
42
|
end
|
31
43
|
|
44
|
+
# get mediatype of the item.
|
32
45
|
def mediatype
|
33
46
|
media_type
|
34
47
|
end
|
35
|
-
|
48
|
+
|
36
49
|
def [](x)
|
37
50
|
@attributes[x]
|
38
51
|
end
|
@@ -40,28 +53,61 @@ module GEPUB
|
|
40
53
|
def []=(x,y)
|
41
54
|
@attributes[x] = y
|
42
55
|
end
|
43
|
-
|
56
|
+
|
57
|
+
# add value to properties attribute.
|
44
58
|
def add_property(property)
|
45
59
|
(@attributes['properties'] ||=[]) << property
|
46
60
|
self
|
47
61
|
end
|
48
62
|
|
63
|
+
# set 'cover-image' property to the Item.
|
64
|
+
# On generating EPUB, EPUB2-style cover image meta item will be added.
|
49
65
|
def cover_image
|
50
66
|
add_property('cover-image')
|
51
67
|
end
|
52
68
|
|
69
|
+
# set 'nav' property to the Item.
|
53
70
|
def nav
|
54
71
|
add_property('nav')
|
55
72
|
end
|
56
73
|
|
57
|
-
|
58
|
-
|
74
|
+
# guess and set content property from contents.
|
75
|
+
def guess_content_property
|
76
|
+
if File.extname(self.href) =~ /.x?html/
|
77
|
+
@attributes['properties'] = (@attributes['properties'] || []).reject {
|
78
|
+
|x| x == 'svg' || x == 'mathml' || x == 'switch' || x == 'remote-resources'
|
79
|
+
}
|
80
|
+
parsed = Nokogiri::XML::Document.parse(@content)
|
81
|
+
ns_prefix = parsed.namespaces.invert['http://www.w3.org/1999/xhtml']
|
82
|
+
if ns_prefix.nil?
|
83
|
+
prefix = ''
|
84
|
+
else
|
85
|
+
prefix = "#{ns_prefix}:"
|
86
|
+
end
|
87
|
+
videos = parsed.xpath("//#{prefix}video[starts-with(@src,'http')]")
|
88
|
+
audios = parsed.xpath("//#{prefix}audio[starts-with(@src,'http')]")
|
89
|
+
if videos.size > 0 || audios.size > 0
|
90
|
+
self.add_property('remote-resources')
|
91
|
+
end
|
92
|
+
if parsed.xpath("//p:math", { 'p' => 'http://www.w3.org/1998/Math/MathML' }).size > 0
|
93
|
+
self.add_property('mathml')
|
94
|
+
end
|
95
|
+
if parsed.xpath("//s:svg", { 's' => 'http://www.w3.org/2000/svg' }).size > 0
|
96
|
+
self.add_property('svg')
|
97
|
+
end
|
98
|
+
if parsed.xpath("//epub:switch", { 'epub' => 'http://www.idpf.org/2007/ops' }).size > 0
|
99
|
+
self.add_property('switch')
|
100
|
+
end
|
101
|
+
end
|
59
102
|
end
|
60
103
|
|
61
|
-
|
62
|
-
|
104
|
+
# add content data to the item.
|
105
|
+
def add_raw_content(data)
|
106
|
+
@content = data
|
107
|
+
guess_content_property
|
63
108
|
end
|
64
109
|
|
110
|
+
# add content form io or file to the item
|
65
111
|
def add_content(io_or_filename)
|
66
112
|
io = io_or_filename
|
67
113
|
if io_or_filename.class == String
|
@@ -69,23 +115,11 @@ module GEPUB
|
|
69
115
|
end
|
70
116
|
io.binmode
|
71
117
|
@content = io.read
|
72
|
-
|
73
|
-
parsed = Nokogiri::XML::Document.parse(@content)
|
74
|
-
ns_prefix = parsed.namespaces.invert['http://www.w3.org/1999/xhtml']
|
75
|
-
if ns_prefix.nil?
|
76
|
-
prefix = ''
|
77
|
-
else
|
78
|
-
prefix = "#{ns_prefix}:"
|
79
|
-
end
|
80
|
-
videos = parsed.xpath("//#{prefix}video[starts-with(@src,'http')]")
|
81
|
-
audios = parsed.xpath("//#{prefix}audio[starts-with(@src,'http')]")
|
82
|
-
if videos.size > 0 || audios.size > 0
|
83
|
-
self.add_property('remote-resources')
|
84
|
-
end
|
85
|
-
end
|
118
|
+
guess_content_property
|
86
119
|
self
|
87
120
|
end
|
88
121
|
|
122
|
+
# generate xml to supplied Nokogiri builder.
|
89
123
|
def to_xml(builder, opf_version = '3.0')
|
90
124
|
attr = @attributes.dup
|
91
125
|
if opf_version.to_f < 3.0
|
@@ -93,6 +127,9 @@ module GEPUB
|
|
93
127
|
end
|
94
128
|
if !attr['properties'].nil?
|
95
129
|
attr['properties'] = attr['properties'].join(' ')
|
130
|
+
if attr['properties'].size == 0
|
131
|
+
attr.delete 'properties'
|
132
|
+
end
|
96
133
|
end
|
97
134
|
builder.item(attr)
|
98
135
|
end
|
data/lib/gepub/version.rb
CHANGED
data/lib/gepub.rb
CHANGED
data/spec/builder_spec.rb
CHANGED
@@ -437,5 +437,65 @@ describe GEPUB::Builder do
|
|
437
437
|
}
|
438
438
|
# this should not raise 'No such file or directory'
|
439
439
|
end
|
440
|
+
|
441
|
+
it 'should handle mathml' do
|
442
|
+
builder = GEPUB::Builder.new {
|
443
|
+
unique_identifier 'uid'
|
444
|
+
resources {
|
445
|
+
file 'mathml.xhtml' => StringIO.new('<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"><head></head><body><div><p><math xmlns="http://www.w3.org/1998/Math/MathML"></math></p></div></body></html>')
|
446
|
+
}
|
447
|
+
}
|
448
|
+
builder.instance_eval {
|
449
|
+
@book.item_by_href('mathml.xhtml').properties[0].should == 'mathml'
|
450
|
+
}
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'should handle svg' do
|
454
|
+
builder = GEPUB::Builder.new {
|
455
|
+
unique_identifier 'uid'
|
456
|
+
resources {
|
457
|
+
file 'svg.xhtml' => StringIO.new('<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"><head></head><body><div><p><svg xmlns="http://www.w3.org/2000/svg"></svg></p></div></body></html>')
|
458
|
+
}
|
459
|
+
}
|
460
|
+
builder.instance_eval {
|
461
|
+
@book.item_by_href('svg.xhtml').properties[0].should == 'svg'
|
462
|
+
}
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'should handle epub:switch' do
|
466
|
+
builder = GEPUB::Builder.new {
|
467
|
+
unique_identifier 'uid'
|
468
|
+
resources {
|
469
|
+
file 'switch.xhtml' => StringIO.new('<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"><head></head><body><div><p>
|
470
|
+
<epub:switch>
|
471
|
+
<epub:case required-namespace="http://www.xml-cml.org/schema">
|
472
|
+
<cml xmlns="http://www.xml-cml.org/schema">
|
473
|
+
<molecule id="sulfuric-acid">
|
474
|
+
<formula id="f1" concise="H 2 S 1 O 4"/>
|
475
|
+
</molecule>
|
476
|
+
</cml>
|
477
|
+
</epub:case>
|
478
|
+
<epub:default>
|
479
|
+
<p>H<sub>2</sub>SO<sub>4</sub></p>
|
480
|
+
</epub:default>
|
481
|
+
</epub:switch></p></div></body></html>')
|
482
|
+
}
|
483
|
+
}
|
484
|
+
builder.instance_eval {
|
485
|
+
@book.item_by_href('switch.xhtml').properties[0].should == 'switch'
|
486
|
+
}
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'should handle optional file' do
|
490
|
+
builder = GEPUB::Builder.new {
|
491
|
+
optional_file 'META-INF/test.xml' => StringIO.new('<test></test>')
|
492
|
+
}
|
493
|
+
builder.instance_eval {
|
494
|
+
@book.optional_files.size.should == 1
|
495
|
+
}
|
496
|
+
builder.instance_eval {
|
497
|
+
@book.optional_files['META-INF/test.xml']
|
498
|
+
}.should_not be_nil
|
499
|
+
end
|
440
500
|
end
|
441
501
|
end
|
data/spec/gepub_spec.rb
CHANGED
@@ -189,6 +189,12 @@ EOF
|
|
189
189
|
jar = File.join(File.dirname(__FILE__), 'fixtures/epubcheck-3.0b4/epubcheck-3.0b4.jar')
|
190
190
|
system 'java', '-jar', jar, epubname
|
191
191
|
end
|
192
|
-
|
192
|
+
it 'should generate epub with extra file' do
|
193
|
+
epubname = File.join(File.dirname(__FILE__), 'testepub3.epub')
|
194
|
+
@book.add_optional_file('META-INF/foobar.xml', StringIO.new('<foo></foo>'))
|
195
|
+
@book.generate_epub(epubname)
|
196
|
+
jar = File.join(File.dirname(__FILE__), 'fixtures/epubcheck-3.0b4/epubcheck-3.0b4.jar')
|
197
|
+
system 'java', '-jar', jar, epubname
|
198
|
+
end
|
193
199
|
|
194
200
|
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.
|
4
|
+
version: 0.6.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,41 +9,41 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70119775057080 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '2'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70119775057080
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: nokogiri
|
27
|
-
requirement: &
|
27
|
+
requirement: &70119775056340 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.5.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70119775056340
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rubyzip
|
38
|
-
requirement: &
|
38
|
+
requirement: &70119775055860 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - =
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.9.6
|
43
|
+
version: 0.9.6.1
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70119775055860
|
47
47
|
description: gepub is a generic EPUB parser/generator. Generates and parse EPUB2 and
|
48
48
|
EPUB3
|
49
49
|
email:
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/gepub/metadata.rb
|
77
77
|
- lib/gepub/package.rb
|
78
78
|
- lib/gepub/resource_builder.rb
|
79
|
+
- lib/gepub/rubyzip_patch.rb
|
79
80
|
- lib/gepub/spine.rb
|
80
81
|
- lib/gepub/version.rb
|
81
82
|
- lib/gepub/xml_util.rb
|