gepub 0.0.10 → 0.1.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/.document +5 -0
- data/.gitignore +1 -0
- data/README.rdoc +20 -26
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/examples/example.rb +22 -28
- data/gepub.gemspec +67 -0
- data/lib/gepub.rb +2 -0
- data/lib/gepub/book.rb +247 -0
- data/lib/gepub/generator.rb +4 -2
- data/lib/gepub/item.rb +38 -0
- data/spec/gepub_spec.rb +58 -12
- metadata +40 -9
data/.document
ADDED
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -8,38 +8,37 @@ a good-enough EPUB generator library.
|
|
8
8
|
|
9
9
|
== FEATURES/PROBLEMS:
|
10
10
|
|
11
|
-
* GEPUB::
|
11
|
+
* GEPUB::Book provides functionality to create ncx/opf, and epub file.
|
12
12
|
|
13
13
|
* opf: can't specify creators with role
|
14
14
|
* opf: can't specify date with event
|
15
15
|
* opf: unique-identifier's scheme is fixed to 'URL'
|
16
16
|
* ncx: can't nest navPoint elements
|
17
|
+
* opf: oops!! it specifies lang='ja'. it's hardcoded. (*sigh*)
|
17
18
|
* ...and many other restrictions
|
18
19
|
|
20
|
+
* note: GEPUB::Generator is now obsolete. use GEPUB::Book.
|
21
|
+
|
19
22
|
== SYNOPSIS:
|
20
23
|
|
21
24
|
require 'rubygems'
|
22
25
|
require 'gepub'
|
23
26
|
require 'fileutils'
|
24
27
|
|
25
|
-
|
28
|
+
epubname = "testepub.epub"
|
26
29
|
title = "samplepub"
|
27
|
-
FileUtils.rm_rf(epubdir)
|
28
|
-
FileUtils.mkdir(epubdir)
|
29
30
|
|
30
|
-
epub = GEPUB::
|
31
|
+
epub = GEPUB::Book.new(title)
|
31
32
|
epub.author="the author"
|
32
33
|
epub.publisher="the publisher"
|
33
34
|
epub.date = "2010-05-03"
|
34
|
-
epub.identifier = "http://www.skoji.jp/testepub/2010-
|
35
|
+
epub.identifier = "http://www.skoji.jp/testepub/2010-06-26"
|
35
36
|
|
36
37
|
# create test contents files
|
37
|
-
|
38
|
+
contents = {}
|
38
39
|
[ 'coverpage', 'chapter1', 'chapter2' ].each {
|
39
|
-
|
40
|
-
|
41
|
-
|file|
|
42
|
-
file << <<EOF
|
40
|
+
|name|
|
41
|
+
contents[name] = <<EOF
|
43
42
|
<?xml version="1.0" encoding="UTF-8"?>
|
44
43
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
|
45
44
|
<head>
|
@@ -52,26 +51,21 @@ a good-enough EPUB generator library.
|
|
52
51
|
</html>
|
53
52
|
EOF
|
54
53
|
}
|
55
|
-
}
|
56
54
|
|
57
55
|
# coverpage won't appear on toc, so do not call addNav
|
58
|
-
epub.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
epub.
|
63
|
-
epub.
|
64
|
-
epub.addNav('chap1', 'Chapter 1', "chapter1.html")
|
65
|
-
|
66
|
-
epub.addManifest('chap2', "chapter2.html", 'application/xhtml+xml')
|
67
|
-
epub.spine.push('chap2')
|
68
|
-
epub.addNav('chap1', 'Chapter 2', "chapter2.html")
|
56
|
+
epub.add_ordered_item('coverpage.html', StringIO.new(contents['coverpage']))
|
57
|
+
|
58
|
+
chap1 = epub.add_ordered_item("chapter1.html", StringIO.new(contents['chapter1']))
|
59
|
+
epub.add_nav(chap1, 'Chapter 1')
|
60
|
+
chap2 = epub.add_ordered_item("chapter2.html", StringIO.new(contents['chapter2']))
|
61
|
+
epub.add_nav(chap2, 'Chapter 2')
|
69
62
|
|
63
|
+
# GEPUB::Book#add_ordered_item will added on <manifest> and <spine> section.
|
64
|
+
# if you want to add image file, use GEPUB::Book#add_item instead.
|
70
65
|
|
71
|
-
epub.
|
72
|
-
epub.create_epub(epubdir, ".")
|
66
|
+
epub.generate_epub(epubname)
|
73
67
|
|
74
|
-
== REQUIREMENTS:
|
68
|
+
== REQUIREMENTS:
|
75
69
|
|
76
70
|
* libxml-ruby
|
77
71
|
* zipruby
|
data/Rakefile
CHANGED
@@ -11,6 +11,7 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/skoji/gepub"
|
12
12
|
gem.authors = ["KOJIMA Satoshi"]
|
13
13
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_development_dependency "epubcheck", ">= 0.1.0"
|
14
15
|
gem.add_dependency('libxml-ruby', ">= 1.1.4")
|
15
16
|
gem.add_dependency('rubyzip', ">= 0.9.4")
|
16
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
data/examples/example.rb
CHANGED
@@ -3,12 +3,10 @@ require 'rubygems'
|
|
3
3
|
require 'gepub'
|
4
4
|
require 'fileutils'
|
5
5
|
|
6
|
-
|
6
|
+
epubname = "testepub.epub"
|
7
7
|
title = "samplepub"
|
8
|
-
FileUtils.rm_rf(epubdir)
|
9
|
-
FileUtils.mkdir(epubdir)
|
10
8
|
|
11
|
-
epub = GEPUB::
|
9
|
+
epub = GEPUB::Book.new(title)
|
12
10
|
epub.author="the author"
|
13
11
|
epub.publisher="the publisher"
|
14
12
|
epub.date = "2010-05-03"
|
@@ -16,40 +14,36 @@ epub.identifier = "http://www.skoji.jp/testepub/2010-05-03"
|
|
16
14
|
|
17
15
|
# create test contents files
|
18
16
|
|
17
|
+
contents = {}
|
19
18
|
[ 'coverpage', 'chapter1', 'chapter2' ].each {
|
20
19
|
|name|
|
21
|
-
|
22
|
-
|file|
|
23
|
-
file << <<EOF
|
20
|
+
contents[name] = <<EOF
|
24
21
|
<?xml version="1.0" encoding="UTF-8"?>
|
25
22
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
<head>
|
24
|
+
<title>sample #{name} </title>
|
25
|
+
</head>
|
26
|
+
<body>
|
27
|
+
<h1>#{name}</h1>
|
31
28
|
<p>here comes the contents for #{name}</p>
|
32
|
-
|
29
|
+
</body>
|
33
30
|
</html>
|
34
31
|
EOF
|
35
|
-
}
|
36
32
|
}
|
37
33
|
|
38
34
|
# coverpage won't appear on toc, so do not call addNav
|
39
|
-
epub.
|
40
|
-
epub.
|
35
|
+
epub.spine << epub.add_item('coverpage.html', StringIO.new(contents['coverpage']))
|
36
|
+
chap1 = epub.add_item("chapter1.html", StringIO.new(contents['chapter1']))
|
37
|
+
epub.spine << chap1
|
38
|
+
epub.add_nav(chap1, 'Chapter 1')
|
39
|
+
chap2 = epub.add_item("chapter2.html", StringIO.new(contents['chapter2']))
|
40
|
+
epub.spine << chap2
|
41
|
+
# if there are image files, they need not add to spine.
|
42
|
+
epub.add_nav(chap2, 'Chapter 2')
|
43
|
+
|
44
|
+
# GEPUB::Book#add_ordered_item will added on <manifest> and <spine> section.
|
45
|
+
# if you want to add image file, use GEPUB::Book#add_item instead.
|
46
|
+
epub.generate_epub(epubname)
|
41
47
|
|
42
48
|
|
43
|
-
epub.addManifest('chap1', "chapter1.html", 'application/xhtml+xml')
|
44
|
-
epub.spine.push('chap1')
|
45
|
-
epub.addNav('chap1', 'Chapter 1', "chapter1.html")
|
46
|
-
|
47
|
-
epub.addManifest('chap2', "chapter2.html", 'application/xhtml+xml')
|
48
|
-
epub.spine.push('chap2')
|
49
|
-
epub.addNav('chap1', 'Chapter 2', "chapter2.html")
|
50
|
-
|
51
|
-
|
52
|
-
epub.create(epubdir)
|
53
|
-
epub.create_epub(epubdir, ".")
|
54
|
-
|
55
49
|
|
data/gepub.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{gepub}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["KOJIMA Satoshi"]
|
12
|
+
s.date = %q{2010-07-06}
|
13
|
+
s.description = %q{an easy-to-use (and easy-to-implement) EPUB generator.}
|
14
|
+
s.email = %q{skoji@skoji.jp}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".document",
|
20
|
+
".gitignore",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"examples/example.rb",
|
25
|
+
"gepub.gemspec",
|
26
|
+
"lib/gepub.rb",
|
27
|
+
"lib/gepub/book.rb",
|
28
|
+
"lib/gepub/generator.rb",
|
29
|
+
"lib/gepub/item.rb",
|
30
|
+
"spec/gepub_spec.rb",
|
31
|
+
"spec/spec.opts",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/skoji/gepub}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{a good-enough EPUB generator.}
|
39
|
+
s.test_files = [
|
40
|
+
"spec/gepub_spec.rb",
|
41
|
+
"spec/spec_helper.rb",
|
42
|
+
"examples/example.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
51
|
+
s.add_development_dependency(%q<epubcheck>, [">= 0.1.0"])
|
52
|
+
s.add_runtime_dependency(%q<libxml-ruby>, [">= 1.1.4"])
|
53
|
+
s.add_runtime_dependency(%q<rubyzip>, [">= 0.9.4"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
56
|
+
s.add_dependency(%q<epubcheck>, [">= 0.1.0"])
|
57
|
+
s.add_dependency(%q<libxml-ruby>, [">= 1.1.4"])
|
58
|
+
s.add_dependency(%q<rubyzip>, [">= 0.9.4"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
62
|
+
s.add_dependency(%q<epubcheck>, [">= 0.1.0"])
|
63
|
+
s.add_dependency(%q<libxml-ruby>, [">= 1.1.4"])
|
64
|
+
s.add_dependency(%q<rubyzip>, [">= 0.9.4"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/lib/gepub.rb
CHANGED
data/lib/gepub/book.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'xml/libxml'
|
4
|
+
require 'zip/zip'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
|
8
|
+
module GEPUB
|
9
|
+
class Book
|
10
|
+
attr_accessor :spine
|
11
|
+
|
12
|
+
def initialize(title, contents_prefix="")
|
13
|
+
@metadata = {}
|
14
|
+
@metadata[:identifier] = []
|
15
|
+
@manifest = []
|
16
|
+
@spine = []
|
17
|
+
@toc = []
|
18
|
+
@metadata[:title] = title
|
19
|
+
@contents_prefix = contents_prefix # may insert "OEBPS"
|
20
|
+
@contents_prefix = @contents_prefix + "/" if contents_prefix != ""
|
21
|
+
@itemcount = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def title
|
25
|
+
@metadata[:title]
|
26
|
+
end
|
27
|
+
|
28
|
+
def title=(title)
|
29
|
+
@metadata[:title] = title
|
30
|
+
end
|
31
|
+
|
32
|
+
def author
|
33
|
+
@metadata[:creator]
|
34
|
+
end
|
35
|
+
|
36
|
+
def author=(author)
|
37
|
+
@metadata[:creator] = author
|
38
|
+
end
|
39
|
+
|
40
|
+
def contributor
|
41
|
+
@metadata[:contributor]
|
42
|
+
end
|
43
|
+
|
44
|
+
def contributor=(contributor)
|
45
|
+
@metadata[:contributor] = contributor
|
46
|
+
end
|
47
|
+
|
48
|
+
def publisher
|
49
|
+
@metadata[:publisher]
|
50
|
+
end
|
51
|
+
|
52
|
+
def publisher=(publisher)
|
53
|
+
@metadata[:publisher] = publisher
|
54
|
+
end
|
55
|
+
|
56
|
+
def date
|
57
|
+
@metadata[:date]
|
58
|
+
end
|
59
|
+
|
60
|
+
def date=(date)
|
61
|
+
@metadata[:date] = date
|
62
|
+
end
|
63
|
+
|
64
|
+
def identifier
|
65
|
+
@main_identifier
|
66
|
+
end
|
67
|
+
|
68
|
+
def identifier=(id)
|
69
|
+
@metadata[:identifier] << { :scheme => 'URL', :identifier => id, :main_id => true }
|
70
|
+
@main_identifier = id
|
71
|
+
end
|
72
|
+
|
73
|
+
def setIdentifier(scheme, identfier)
|
74
|
+
@metadata[:identifier] << { :scheme => scheme, :identifier => identifier }
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_ref_to_item(href, itemid = nil)
|
78
|
+
itemid ||= 'item' + @itemcount.to_s + "_" + File.basename(href, '.*')
|
79
|
+
@itemcount = @itemcount + 1
|
80
|
+
item = Item.new(itemid, href)
|
81
|
+
@manifest << item
|
82
|
+
item
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_item(href, io, itemid = nil)
|
86
|
+
add_ref_to_item(href, itemid).add_content(io)
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_nav(item, text)
|
90
|
+
@toc.push({ :item => item, :text => text})
|
91
|
+
end
|
92
|
+
|
93
|
+
def specify_cover_image(item)
|
94
|
+
@metadata[:cover] = item.itemid
|
95
|
+
end
|
96
|
+
|
97
|
+
def cover_image_item
|
98
|
+
@metadata[:cover]
|
99
|
+
end
|
100
|
+
|
101
|
+
def generate_epub(path_to_epub)
|
102
|
+
if (@toc.size == 0)
|
103
|
+
@toc << { :item => @spine[0], :text => " " }
|
104
|
+
end
|
105
|
+
|
106
|
+
add_item('toc.ncx', StringIO.new(ncx_xml), 'ncx')
|
107
|
+
|
108
|
+
File.delete(path_to_epub) if File.exist?(path_to_epub)
|
109
|
+
Zip::ZipOutputStream::open(path_to_epub) {
|
110
|
+
|epub|
|
111
|
+
|
112
|
+
# create metadata files
|
113
|
+
epub.put_next_entry('mimetype', '', '', Zip::ZipEntry::STORED)
|
114
|
+
epub << "application/epub+zip"
|
115
|
+
|
116
|
+
epub.put_next_entry('META-INF/container.xml')
|
117
|
+
epub << container_xml
|
118
|
+
|
119
|
+
epub.put_next_entry(@contents_prefix + 'content.opf')
|
120
|
+
epub << opf_xml
|
121
|
+
|
122
|
+
# create items
|
123
|
+
@manifest.each {
|
124
|
+
|item|
|
125
|
+
epub.put_next_entry(@contents_prefix + item.href)
|
126
|
+
epub << item.content
|
127
|
+
}
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def container_xml
|
132
|
+
<<EOF
|
133
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
134
|
+
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
135
|
+
<rootfiles>
|
136
|
+
<rootfile full-path="#{@contents_prefix}content.opf" media-type="application/oebps-package+xml"/>
|
137
|
+
</rootfiles>
|
138
|
+
</container>
|
139
|
+
EOF
|
140
|
+
end
|
141
|
+
|
142
|
+
def opf_xml
|
143
|
+
result = XML::Document.new
|
144
|
+
result.root = XML::Node.new('package')
|
145
|
+
package = result.root
|
146
|
+
XML::Namespace.new(package, nil, 'http://www.idpf.org/2007/opf')
|
147
|
+
package['version'] = '2.0'
|
148
|
+
package['unique-identifier'] = 'BookID'
|
149
|
+
|
150
|
+
|
151
|
+
package << metadataelem = XML::Node.new('metadata')
|
152
|
+
XML::Namespace.new(metadataelem, 'opf', 'http://www.idpf.org/2007/opf')
|
153
|
+
XML::Namespace.new(metadataelem, 'dc', "http://purl.org/dc/elements/1.1/")
|
154
|
+
|
155
|
+
metadataelem << XML::Node.new('dc:language', 'ja')
|
156
|
+
|
157
|
+
@metadata.each { | k, v |
|
158
|
+
if (k == :cover)
|
159
|
+
metadataelem << node = XML::Node.new("meta")
|
160
|
+
node['name'] = 'cover'
|
161
|
+
node['content'] = v
|
162
|
+
elsif (k == :identifier)
|
163
|
+
v.each {
|
164
|
+
|id|
|
165
|
+
metadataelem << node = XML::Node.new("dc:#{k}",id[:identifier])
|
166
|
+
if (id[:main_id])
|
167
|
+
node['id'] = 'BookID'
|
168
|
+
end
|
169
|
+
node['opf:scheme'] = id[:scheme]
|
170
|
+
}
|
171
|
+
else
|
172
|
+
metadataelem << node = XML::Node.new("dc:#{k}",v)
|
173
|
+
end
|
174
|
+
}
|
175
|
+
|
176
|
+
package << manifestelem = XML::Node.new('manifest')
|
177
|
+
@manifest.each {
|
178
|
+
|item|
|
179
|
+
manifestelem << node = XML::Node.new("item")
|
180
|
+
node['id'] = "#{item.itemid}"
|
181
|
+
node['href'] = "#{item.href}"
|
182
|
+
node['media-type'] = "#{item.mediatype}"
|
183
|
+
}
|
184
|
+
|
185
|
+
package << spineelem = XML::Node.new('spine')
|
186
|
+
spineelem['toc'] = 'ncx'
|
187
|
+
|
188
|
+
@spine.each {
|
189
|
+
|v|
|
190
|
+
spineelem << node = XML::Node.new('itemref')
|
191
|
+
node['idref'] = "#{v.itemid}"
|
192
|
+
}
|
193
|
+
|
194
|
+
result.to_s
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
def ncx_xml
|
199
|
+
result = XML::Document.new
|
200
|
+
result.root = XML::Node.new('ncx')
|
201
|
+
root = result.root
|
202
|
+
XML::Namespace.new(root, nil, "http://www.daisy.org/z3986/2005/ncx/")
|
203
|
+
root['version'] = "2005-1"
|
204
|
+
root << head = XML::Node.new('head')
|
205
|
+
head << uid = XML::Node.new('meta')
|
206
|
+
uid['name'] = 'dtb:uid'
|
207
|
+
uid['content'] = "#{@main_identifier}"
|
208
|
+
|
209
|
+
head << depth = XML::Node.new('meta')
|
210
|
+
depth['name'] = 'dtb:depth'
|
211
|
+
depth['content'] = '1'
|
212
|
+
|
213
|
+
head << totalPageCount = XML::Node.new('meta')
|
214
|
+
totalPageCount['name'] = 'dtb:totalPageCount'
|
215
|
+
totalPageCount['content'] = '0'
|
216
|
+
|
217
|
+
head << maxPageNumber = XML::Node.new('meta')
|
218
|
+
maxPageNumber['name'] = 'dtb:maxPageNumber'
|
219
|
+
maxPageNumber['content'] = '0'
|
220
|
+
|
221
|
+
|
222
|
+
root << docTitle = XML::Node.new('docTitle')
|
223
|
+
docTitle << XML::Node.new('text', "#{@metadata[:title]}")
|
224
|
+
|
225
|
+
root << nav_map = XML::Node.new('navMap')
|
226
|
+
count = 1
|
227
|
+
@toc.each {
|
228
|
+
|x|
|
229
|
+
nav_point = XML::Node.new('navPoint')
|
230
|
+
nav_point['id'] = "#{x[:item].itemid}"
|
231
|
+
nav_point['playOrder'] = "#{count}"
|
232
|
+
|
233
|
+
nav_label = XML::Node.new('navLabel')
|
234
|
+
nav_label << XML::Node.new('text', "#{x[:text]}")
|
235
|
+
|
236
|
+
nav_content = XML::Node.new('content')
|
237
|
+
nav_content['src'] = "#{x[:item].href}"
|
238
|
+
count = count + 1
|
239
|
+
|
240
|
+
nav_map << nav_point
|
241
|
+
nav_point << nav_label
|
242
|
+
nav_point << nav_content
|
243
|
+
}
|
244
|
+
result.to_s
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
data/lib/gepub/generator.rb
CHANGED
@@ -11,6 +11,7 @@ module GEPUB
|
|
11
11
|
attr_accessor :spine
|
12
12
|
|
13
13
|
def initialize(title)
|
14
|
+
warn('GEPUB::Generator is obsolete. use GEPUB::Book instead.')
|
14
15
|
@metadata = Hash.new
|
15
16
|
@manifest = Hash.new
|
16
17
|
@spine = Array.new
|
@@ -75,7 +76,7 @@ module GEPUB
|
|
75
76
|
def addManifest(id, href, mediatype)
|
76
77
|
@manifest[id] = { :href => href, :mediatype => mediatype }
|
77
78
|
end
|
78
|
-
|
79
|
+
|
79
80
|
def addNav(id, text, ref)
|
80
81
|
@toc.push({ :id => id, :text => text, :ref => ref})
|
81
82
|
end
|
@@ -93,6 +94,7 @@ module GEPUB
|
|
93
94
|
|
94
95
|
def create_epub(destdir, targetdir, epubname = @metadata[:title])
|
95
96
|
realtarget = File::expand_path(targetdir)
|
97
|
+
|
96
98
|
FileUtils.cd("#{destdir}") do
|
97
99
|
|dir|
|
98
100
|
epubname = "#{realtarget}/#{epubname}.epub"
|
@@ -101,7 +103,7 @@ module GEPUB
|
|
101
103
|
Zip::ZipOutputStream::open(epubname) {
|
102
104
|
|epub|
|
103
105
|
epub.put_next_entry('mimetype', '', '', Zip::ZipEntry::STORED)
|
104
|
-
epub <<
|
106
|
+
epub << 'application/epub+zip'
|
105
107
|
|
106
108
|
Dir["**/*"].each do
|
107
109
|
|f|
|
data/lib/gepub/item.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module GEPUB
|
2
|
+
class Item
|
3
|
+
attr_accessor :itemid, :href, :mediatype, :content
|
4
|
+
|
5
|
+
def initialize(itemid, href, mediatype = nil)
|
6
|
+
@itemid = itemid
|
7
|
+
@href = href
|
8
|
+
@mediatype = mediatype || guess_mediatype
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_content(io)
|
12
|
+
io.binmode
|
13
|
+
@content = io.read
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def guess_mediatype
|
18
|
+
case File.extname(@href)
|
19
|
+
when /.(html|xhtml)/i
|
20
|
+
'application/xhtml+xml'
|
21
|
+
when /.css/i
|
22
|
+
'text/css'
|
23
|
+
when /.(jpg|jpeg)/i
|
24
|
+
'image/jpeg'
|
25
|
+
when /.png/i
|
26
|
+
'image/png'
|
27
|
+
when /.gif/i
|
28
|
+
'image/gif'
|
29
|
+
when /.svg/i
|
30
|
+
'image/svg+xml'
|
31
|
+
when /.opf/i
|
32
|
+
'application/oebps-package+xml'
|
33
|
+
when /.ncx/i
|
34
|
+
'application/x-dtbncx+xml'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/gepub_spec.rb
CHANGED
@@ -1,20 +1,52 @@
|
|
1
|
-
|
1
|
+
# need to install 'epubcheck'.
|
2
2
|
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
3
4
|
require 'rubygems'
|
4
5
|
require 'xml/libxml'
|
5
6
|
|
6
|
-
|
7
|
+
|
8
|
+
describe GEPUB::Item do
|
9
|
+
it "should return atttributes" do
|
10
|
+
item = GEPUB::Item.new('theid', 'foo/bar.bar', 'application/xhtml+xml')
|
11
|
+
item.itemid.should == 'theid'
|
12
|
+
item.href.should == 'foo/bar.bar'
|
13
|
+
item.mediatype.should == 'application/xhtml+xml'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should handle html" do
|
17
|
+
item = GEPUB::Item.new('id', 'text/foo.html')
|
18
|
+
item.mediatype.should == 'application/xhtml+xml'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should handle xhtml" do
|
22
|
+
item = GEPUB::Item.new('id', 'text/foo.xhtml')
|
23
|
+
item.mediatype.should == 'application/xhtml+xml'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should handle JPG" do
|
27
|
+
item = GEPUB::Item.new('id', 'img/foo.JPG')
|
28
|
+
item.mediatype.should == 'image/jpeg'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe GEPUB::Book do
|
7
34
|
before do
|
8
|
-
@generator = GEPUB::
|
35
|
+
@generator = GEPUB::Book.new('thetitle')
|
9
36
|
@generator.author = "theauthor"
|
10
37
|
@generator.contributor = "contributors contributors!"
|
11
38
|
@generator.publisher = "thepublisher"
|
12
39
|
@generator.date = "2010-05-05"
|
13
40
|
@generator.identifier = "http://example.jp/foobar/"
|
41
|
+
item1 = @generator.add_ref_to_item('text/foobar.html','c1')
|
42
|
+
item1.add_content(StringIO.new('<html xmlns="http://www.w3.org/1999/xhtml"><head><title>c1</title></head><body><p>the first page</p></body></html>'))
|
43
|
+
|
44
|
+
item2 = @generator.add_ref_to_item('text/barbar.html','c2')
|
45
|
+
item2.add_content(StringIO.new('<html xmlns="http://www.w3.org/1999/xhtml"><head><title>c2</title></head><body><p>second page, whith is test chapter.</p></body></html>'))
|
14
46
|
|
15
|
-
@generator.
|
16
|
-
@generator.
|
17
|
-
@generator.
|
47
|
+
@generator.spine.push(item1)
|
48
|
+
@generator.spine.push(item2)
|
49
|
+
@generator.add_nav(item2, 'test chapter')
|
18
50
|
end
|
19
51
|
|
20
52
|
it "should have titile" do
|
@@ -35,7 +67,6 @@ describe GEPUB::Generator do
|
|
35
67
|
ncx.find_first('a:head').should_not be_nil
|
36
68
|
|
37
69
|
ncx.find_first("a:head/a:meta[@name='dtb:uid']")['content'].should == "http://example.jp/foobar/"
|
38
|
-
|
39
70
|
ncx.find_first("a:head/a:meta[@name='dtb:depth']").should_not be_nil
|
40
71
|
ncx.find_first("a:head/a:meta[@name='dtb:totalPageCount']").should_not be_nil
|
41
72
|
ncx.find_first("a:head/a:meta[@name='dtb:maxPageNumber']").should_not be_nil
|
@@ -60,7 +91,7 @@ describe GEPUB::Generator do
|
|
60
91
|
|
61
92
|
nav_point.find_first('a:navLabel/a:text').content.should == 'test chapter'
|
62
93
|
nav_point.find_first('a:content')['src'] == 'foobar2.html'
|
63
|
-
|
94
|
+
|
64
95
|
end
|
65
96
|
|
66
97
|
it "should create correct opf" do
|
@@ -89,25 +120,40 @@ describe GEPUB::Generator do
|
|
89
120
|
|
90
121
|
manifest = opf.find_first('a:manifest')
|
91
122
|
manifest.find_first('a:item')['id'].should == 'c1'
|
92
|
-
manifest.find_first('a:item')['href'].should == 'foobar.html'
|
93
|
-
manifest.find_first('a:item')['media-type'].should == '
|
123
|
+
manifest.find_first('a:item')['href'].should == 'text/foobar.html'
|
124
|
+
manifest.find_first('a:item')['media-type'].should == 'application/xhtml+xml'
|
94
125
|
|
95
126
|
spine = opf.find_first('a:spine')
|
96
127
|
spine['toc'].should == 'ncx'
|
97
128
|
spine.find_first('a:itemref')['idref'].should == 'c1'
|
98
129
|
end
|
99
130
|
|
131
|
+
it "should have correct metadata in opf" do
|
132
|
+
opf = LibXML::XML::Parser.string(@generator.opf_xml).parse
|
133
|
+
opf.root.namespaces.default_prefix='a'
|
134
|
+
|
135
|
+
metadata = opf.find_first('a:metadata')
|
136
|
+
metadata.find_first('dc:language').content.should == 'ja'
|
137
|
+
# TODO checking metadatas...
|
138
|
+
end
|
139
|
+
|
100
140
|
it "should have correct cover image id" do
|
141
|
+
item = @generator.add_ref_to_item("img/img.jpg")
|
142
|
+
@generator.specify_cover_image(item)
|
101
143
|
|
102
|
-
@generator.specifyCoverImage("theId")
|
103
144
|
opf = LibXML::XML::Parser.string(@generator.opf_xml).parse
|
104
145
|
opf.root.namespaces.default_prefix='a'
|
105
146
|
|
106
147
|
metadata = opf.find_first('a:metadata')
|
107
148
|
metacover = metadata.find_first('a:meta')
|
108
149
|
metacover['name'].should == 'cover'
|
109
|
-
metacover['content'].should ==
|
150
|
+
metacover['content'].should == item.itemid
|
151
|
+
end
|
110
152
|
|
153
|
+
it "should generate correct epub" do
|
154
|
+
epubname = File.join(File.dirname(__FILE__), 'testepub.epub')
|
155
|
+
@generator.generate_epub(epubname)
|
156
|
+
%x( epubcheck #{epubname} )
|
111
157
|
end
|
112
158
|
|
113
159
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gepub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- KOJIMA Satoshi
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-06
|
18
|
+
date: 2010-07-06 00:00:00 +09:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 2
|
@@ -32,33 +35,53 @@ dependencies:
|
|
32
35
|
type: :development
|
33
36
|
version_requirements: *id001
|
34
37
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
38
|
+
name: epubcheck
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 1
|
49
|
+
- 0
|
50
|
+
version: 0.1.0
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: libxml-ruby
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 27
|
41
62
|
segments:
|
42
63
|
- 1
|
43
64
|
- 1
|
44
65
|
- 4
|
45
66
|
version: 1.1.4
|
46
67
|
type: :runtime
|
47
|
-
version_requirements: *
|
68
|
+
version_requirements: *id003
|
48
69
|
- !ruby/object:Gem::Dependency
|
49
70
|
name: rubyzip
|
50
71
|
prerelease: false
|
51
|
-
requirement: &
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
52
74
|
requirements:
|
53
75
|
- - ">="
|
54
76
|
- !ruby/object:Gem::Version
|
77
|
+
hash: 51
|
55
78
|
segments:
|
56
79
|
- 0
|
57
80
|
- 9
|
58
81
|
- 4
|
59
82
|
version: 0.9.4
|
60
83
|
type: :runtime
|
61
|
-
version_requirements: *
|
84
|
+
version_requirements: *id004
|
62
85
|
description: an easy-to-use (and easy-to-implement) EPUB generator.
|
63
86
|
email: skoji@skoji.jp
|
64
87
|
executables: []
|
@@ -68,13 +91,17 @@ extensions: []
|
|
68
91
|
extra_rdoc_files:
|
69
92
|
- README.rdoc
|
70
93
|
files:
|
94
|
+
- .document
|
71
95
|
- .gitignore
|
72
96
|
- README.rdoc
|
73
97
|
- Rakefile
|
74
98
|
- VERSION
|
75
99
|
- examples/example.rb
|
100
|
+
- gepub.gemspec
|
76
101
|
- lib/gepub.rb
|
102
|
+
- lib/gepub/book.rb
|
77
103
|
- lib/gepub/generator.rb
|
104
|
+
- lib/gepub/item.rb
|
78
105
|
- spec/gepub_spec.rb
|
79
106
|
- spec/spec.opts
|
80
107
|
- spec/spec_helper.rb
|
@@ -88,23 +115,27 @@ rdoc_options:
|
|
88
115
|
require_paths:
|
89
116
|
- lib
|
90
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
91
119
|
requirements:
|
92
120
|
- - ">="
|
93
121
|
- !ruby/object:Gem::Version
|
122
|
+
hash: 3
|
94
123
|
segments:
|
95
124
|
- 0
|
96
125
|
version: "0"
|
97
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
98
128
|
requirements:
|
99
129
|
- - ">="
|
100
130
|
- !ruby/object:Gem::Version
|
131
|
+
hash: 3
|
101
132
|
segments:
|
102
133
|
- 0
|
103
134
|
version: "0"
|
104
135
|
requirements: []
|
105
136
|
|
106
137
|
rubyforge_project:
|
107
|
-
rubygems_version: 1.3.
|
138
|
+
rubygems_version: 1.3.7
|
108
139
|
signing_key:
|
109
140
|
specification_version: 3
|
110
141
|
summary: a good-enough EPUB generator.
|