bindery 2.0.0 → 2.1.0
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/lib/bindery/content_methods.rb +8 -4
- data/lib/bindery/division.rb +5 -5
- data/lib/bindery/formats/epub.rb +41 -39
- data/lib/bindery/version.rb +1 -1
- metadata +3 -3
@@ -19,18 +19,22 @@ module Bindery
|
|
19
19
|
def chapter(title, filename, options={}, &block)
|
20
20
|
div('chapter', title, filename, options, &block)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def section(title, filename, options={}, &block)
|
24
24
|
div('section', title, filename, options, &block)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def part(title, filename, options={}, &block)
|
28
28
|
div('part', title, filename, options, &block)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def appendix(title, filename, options={}, &block)
|
32
32
|
div('appendix', title, filename, options, &block)
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
|
+
def index(title, filename, options={}, &block)
|
36
|
+
div('index', title, filename, options, &block)
|
37
|
+
end
|
38
|
+
|
35
39
|
end
|
36
40
|
end
|
data/lib/bindery/division.rb
CHANGED
@@ -6,14 +6,14 @@ module Bindery
|
|
6
6
|
attr_accessor :options
|
7
7
|
|
8
8
|
include ContentMethods
|
9
|
-
|
9
|
+
|
10
10
|
def initialize(div_type, title, file, options)
|
11
11
|
self.div_type = div_type
|
12
12
|
self.title = title
|
13
13
|
self.file = file
|
14
14
|
self.options = options
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def valid?
|
18
18
|
true
|
19
19
|
# ??? title specified? Is this required by the spec? Think about
|
@@ -25,17 +25,17 @@ module Bindery
|
|
25
25
|
# chapters that would break up the text flow?
|
26
26
|
# file exists, readable
|
27
27
|
# file content properly formed? Does that matter? Can we
|
28
|
-
# verify it?
|
28
|
+
# verify it?
|
29
29
|
end
|
30
30
|
|
31
31
|
def divisions
|
32
32
|
@divisions ||= []
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def body_only?
|
36
36
|
options.fetch(:body_only, true)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def include_images?
|
40
40
|
options.fetch(:include_images, true)
|
41
41
|
end
|
data/lib/bindery/formats/epub.rb
CHANGED
@@ -2,10 +2,11 @@ require 'builder'
|
|
2
2
|
require 'zip'
|
3
3
|
require 'bindery/extensions/zip_file'
|
4
4
|
require 'nokogiri'
|
5
|
+
require 'uri'
|
5
6
|
|
6
7
|
module Bindery
|
7
8
|
module Formats
|
8
|
-
|
9
|
+
|
9
10
|
# Builds an EPUB book file from the book description.
|
10
11
|
#
|
11
12
|
# The {EPUB Wikipedia entry}[http://en.wikipedia.org/wiki/EPUB] provides a nice, concise overview of the EPUB format.
|
@@ -20,25 +21,25 @@ module Bindery
|
|
20
21
|
# * Details of the format of other files allowed in EPUB documents are found in
|
21
22
|
# {Open Publication Structure (OPS) 2.0.1 - Recommended Specification}[http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm].
|
22
23
|
class Epub
|
23
|
-
|
24
|
+
|
24
25
|
MimeTypes = {
|
25
26
|
'.jpg' => 'image/jpeg',
|
26
27
|
'.png' => 'image/png',
|
27
28
|
'.gif' => 'image/gif',
|
28
29
|
}
|
29
|
-
|
30
|
+
|
30
31
|
class ManifestEntry < Struct.new(:file_name, :xml_id, :mime_type)
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
attr_accessor :book, :manifest_entries
|
34
|
-
|
35
|
+
|
35
36
|
def initialize(book)
|
36
37
|
self.book = book
|
37
38
|
book.extend BookMethods
|
38
39
|
book.divisions.each{|division| division.extend DivisionMethods}
|
39
40
|
self.manifest_entries = []
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
def generate
|
43
44
|
File.delete(book.epub_output_file) if File.exist?(book.epub_output_file)
|
44
45
|
Zip::ZipFile.open(book.epub_output_file, Zip::ZipFile::CREATE) do |zipfile|
|
@@ -46,12 +47,12 @@ module Bindery
|
|
46
47
|
zipfile.write_uncompressed_file 'mimetype', mimetype
|
47
48
|
zipfile.mkdir 'META-INF'
|
48
49
|
zipfile.write_file 'META-INF/container.xml', container
|
49
|
-
|
50
|
+
|
50
51
|
# also frontmatter, backmatter
|
51
52
|
book.divisions.each do |division|
|
52
53
|
write_division(division, zipfile)
|
53
54
|
end
|
54
|
-
|
55
|
+
|
55
56
|
zipfile.mkdir 'css'
|
56
57
|
zipfile.write_file 'css/book.css', stylesheet
|
57
58
|
|
@@ -59,13 +60,13 @@ module Bindery
|
|
59
60
|
zipfile.write_file 'book.ncx', ncx
|
60
61
|
end
|
61
62
|
end
|
62
|
-
|
63
|
+
|
63
64
|
def mimetype
|
64
65
|
# the mimetype file must be the first file in the archive
|
65
66
|
# it must be ASCII, uncompressed, and unencrypted
|
66
67
|
'application/epub+zip'
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
def container
|
70
71
|
%q{|<?xml version="1.0" encoding="UTF-8" ?>
|
71
72
|
|<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
@@ -75,23 +76,23 @@ module Bindery
|
|
75
76
|
|</container>
|
76
77
|
|}.strip_margin
|
77
78
|
end
|
78
|
-
|
79
|
+
|
79
80
|
def opf
|
80
81
|
xm = Builder::XmlMarkup.new(:indent => 2)
|
81
82
|
xm.instruct!
|
82
83
|
xm.package('version'=>'2.0', 'xmlns'=>'http://www.idpf.org/2007/opf', 'unique-identifier'=>'BookId') {
|
83
|
-
|
84
|
+
|
84
85
|
xm.metadata('xmlns:dc'=>'http://purl.org/dc/elements/1.1/', 'xmlns:opf'=>'http://www.idpf.org/2007/opf') {
|
85
86
|
# required elements
|
86
87
|
xm.dc :title, book.full_title
|
87
88
|
xm.dc :language, book.language
|
88
89
|
xm.dc :identifier, book.url, ident_options('opf:scheme'=>'URL') if book.url
|
89
|
-
xm.dc :identifier, book.isbn, ident_options('opf:scheme'=>'ISBN') if book.isbn
|
90
|
-
|
90
|
+
xm.dc :identifier, book.isbn, ident_options('opf:scheme'=>'ISBN') if book.isbn
|
91
|
+
|
91
92
|
# optional elements
|
92
93
|
xm.dc :creator, book.author, 'opf:role'=>'aut' if book.author
|
93
94
|
}
|
94
|
-
|
95
|
+
|
95
96
|
xm.manifest {
|
96
97
|
book.divisions.each{|division| division.write_item(xm)}
|
97
98
|
# also frontmatter, backmatter
|
@@ -102,17 +103,17 @@ module Bindery
|
|
102
103
|
# xm.item 'id'=>'myfont', 'href'=>'css/myfont.otf', 'media-type'=>'application/x-font-opentype'
|
103
104
|
xm.item 'id'=>'ncx', 'href'=>'book.ncx', 'media-type'=>'application/x-dtbncx+xml'
|
104
105
|
}
|
105
|
-
|
106
|
+
|
106
107
|
xm.spine('toc'=>'ncx') {
|
107
108
|
book.divisions.each{|division| division.write_itemref(xm)}
|
108
109
|
}
|
109
|
-
|
110
|
+
|
110
111
|
# xm.guide {
|
111
112
|
# xm.reference 'type'='loi', 'title'=>'List of Illustrations', 'href'=>'appendix.html#figures'
|
112
113
|
# }
|
113
114
|
}
|
114
115
|
end
|
115
|
-
|
116
|
+
|
116
117
|
def ncx
|
117
118
|
xm = Builder::XmlMarkup.new(:indent => 2)
|
118
119
|
xm.instruct!
|
@@ -124,18 +125,18 @@ module Bindery
|
|
124
125
|
xm.meta 'name'=>'dtb:totalPageCount', 'content'=>0
|
125
126
|
xm.meta 'name'=>'dtb:maxPageNumber', 'content'=>0
|
126
127
|
}
|
127
|
-
|
128
|
+
|
128
129
|
xm.docTitle {
|
129
130
|
xm.text book.full_title
|
130
131
|
}
|
131
|
-
|
132
|
+
|
132
133
|
xm.docAuthor {
|
133
134
|
xm.text book.author
|
134
135
|
}
|
135
|
-
|
136
|
+
|
136
137
|
xm.navMap {
|
137
138
|
play_order = 0
|
138
|
-
|
139
|
+
|
139
140
|
# also frontmatter, backmatter
|
140
141
|
book.divisions.each do |division|
|
141
142
|
play_order += 1
|
@@ -174,7 +175,7 @@ module Bindery
|
|
174
175
|
write_division(div, zipfile)
|
175
176
|
end
|
176
177
|
end
|
177
|
-
|
178
|
+
|
178
179
|
def include_images(doc, zipfile)
|
179
180
|
# TODO: where else can images appear? Style sheets?
|
180
181
|
zipfile.mkdir('images') unless zip_dir_exists?(zipfile, 'images')
|
@@ -195,12 +196,12 @@ module Bindery
|
|
195
196
|
end
|
196
197
|
end
|
197
198
|
end
|
198
|
-
|
199
|
+
|
199
200
|
def add_manifest_entry(file_name)
|
200
201
|
xml_id, ext = File.base_parts(file_name.gsub('/', '-'))
|
201
202
|
manifest_entries << ManifestEntry.new(file_name, xml_id, MimeTypes[ext])
|
202
203
|
end
|
203
|
-
|
204
|
+
|
204
205
|
def cover
|
205
206
|
xm = Builder::XmlMarkup.new(:indent => 2)
|
206
207
|
xm.instruct!
|
@@ -223,7 +224,7 @@ module Bindery
|
|
223
224
|
}
|
224
225
|
}
|
225
226
|
end
|
226
|
-
|
227
|
+
|
227
228
|
def stylesheet
|
228
229
|
# This is a start, but needs work.
|
229
230
|
%q{|@page {
|
@@ -257,7 +258,7 @@ module Bindery
|
|
257
258
|
|h3.section_title {text-align: center;}
|
258
259
|
|}.strip_margin
|
259
260
|
end
|
260
|
-
|
261
|
+
|
261
262
|
def ident_options(opts)
|
262
263
|
if book.isbn
|
263
264
|
return opts.merge('id'=>'BookId') if opts['opf:scheme'] == 'ISBN'
|
@@ -266,18 +267,19 @@ module Bindery
|
|
266
267
|
end
|
267
268
|
opts
|
268
269
|
end
|
269
|
-
|
270
|
+
|
270
271
|
def zip_dir_exists?(zipfile, dirname)
|
271
272
|
dirname = "#{dirname}/" unless dirname =~ %r{/$}
|
272
273
|
zipfile.entries.any?{|e| e.directory? && e.name == dirname}
|
273
274
|
end
|
274
|
-
|
275
|
+
|
275
276
|
def zip_file_exists?(zipfile, filename)
|
276
277
|
zipfile.entries.any?{|e| e.name == filename}
|
277
278
|
end
|
278
|
-
|
279
|
+
|
279
280
|
def make_image_file_name(zipfile, url)
|
280
|
-
|
281
|
+
uri = URI(url)
|
282
|
+
stem, ext = File.base_parts(uri.path)
|
281
283
|
filename = "images/#{stem}#{ext}"
|
282
284
|
n = 0
|
283
285
|
while zip_file_exists?(zipfile, filename)
|
@@ -286,31 +288,31 @@ module Bindery
|
|
286
288
|
end
|
287
289
|
filename
|
288
290
|
end
|
289
|
-
|
291
|
+
|
290
292
|
module BookMethods
|
291
293
|
def epub_output_file
|
292
294
|
@epub_output_file ||= "#{output}.epub"
|
293
295
|
end
|
294
|
-
|
296
|
+
|
295
297
|
def depth
|
296
298
|
(divisions.map(&:depth) + [0]).max
|
297
299
|
end
|
298
|
-
|
300
|
+
|
299
301
|
def ident
|
300
302
|
isbn || url
|
301
303
|
end
|
302
304
|
end
|
303
|
-
|
305
|
+
|
304
306
|
module DivisionMethods
|
305
307
|
|
306
308
|
def self.extended(obj)
|
307
309
|
obj.divisions.each{|division| division.extend DivisionMethods}
|
308
310
|
end
|
309
|
-
|
311
|
+
|
310
312
|
def epub_id
|
311
313
|
@epub_id ||= File.stemname(file)
|
312
314
|
end
|
313
|
-
|
315
|
+
|
314
316
|
def epub_output_file
|
315
317
|
@epub_output_file ||= "#{epub_id}.xhtml"
|
316
318
|
end
|
@@ -346,14 +348,14 @@ module Bindery
|
|
346
348
|
end
|
347
349
|
|
348
350
|
end
|
349
|
-
|
351
|
+
|
350
352
|
module MetadataMethods
|
351
353
|
def to_xml(builder)
|
352
354
|
builder.meta(options.merge(:name => name, :content => value))
|
353
355
|
%{<dc:#{name}>#{value}</dc:#{name}>}
|
354
356
|
end
|
355
357
|
end
|
356
|
-
|
358
|
+
|
357
359
|
module DublinMetadataMethods
|
358
360
|
def to_xml(builder)
|
359
361
|
builder.dc name, value, options
|
data/lib/bindery/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bindery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-06-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: builder
|
@@ -173,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
173
|
version: '0'
|
174
174
|
segments:
|
175
175
|
- 0
|
176
|
-
hash:
|
176
|
+
hash: 4117656268896811284
|
177
177
|
requirements: []
|
178
178
|
rubyforge_project: bindery
|
179
179
|
rubygems_version: 1.8.23
|