thepub 0.0.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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.markdown +18 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/lib/thepub/epub/container_item.rb +49 -0
- data/lib/thepub/epub/ncx.rb +137 -0
- data/lib/thepub/epub/ocf.rb +62 -0
- data/lib/thepub/epub/opf.rb +137 -0
- data/lib/thepub/epub.rb +4 -0
- data/lib/thepub.rb +2 -0
- data/test/test_helper.rb +10 -0
- data/test/test_ncx.rb +40 -0
- data/test/test_ocf.rb +25 -0
- data/test/test_opf.rb +63 -0
- data/thepub.gemspec +66 -0
- metadata +95 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009, 2010 Dmitri Goutnik, Invisible Llama
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= thepub
|
2
|
+
|
3
|
+
Nothing more than a direct extraction of [Repub's](http://github.com/invisiblellama/repub) epub module and associated tests.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2010 Dmitri Goutnik, Invisible Llama. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "thepub"
|
8
|
+
gem.summary = %Q{Extraction of Repub's epub module and associated tests}
|
9
|
+
gem.description = %Q{Extraction of Repub's epub module and associated tests}
|
10
|
+
gem.email = "hi@williammelody.com"
|
11
|
+
gem.homepage = "http://github.com/autodata/thepub"
|
12
|
+
gem.authors = ["Dmitri Goutnik, Invisible Llama", "William Melody"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
gem.add_dependency "nokogiri"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
if File.exist?('VERSION')
|
48
|
+
version = File.read('VERSION')
|
49
|
+
else
|
50
|
+
version = ""
|
51
|
+
end
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "thepub #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Thepub
|
4
|
+
module Epub
|
5
|
+
|
6
|
+
# Mixin for stuff that can be added to the ePub package
|
7
|
+
#
|
8
|
+
module ContainerItem
|
9
|
+
attr_accessor :file_path
|
10
|
+
attr_accessor :media_type
|
11
|
+
|
12
|
+
def document?
|
13
|
+
['application/xhtml+xml', 'application/x-dtbook+xml'].include? self.media_type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Wrapper class for ePub items that do not have specialized classes
|
18
|
+
# e.g. HTML files, CSSs etc.
|
19
|
+
#
|
20
|
+
class Item
|
21
|
+
include ContainerItem
|
22
|
+
|
23
|
+
def initialize(file_path, media_type = nil)
|
24
|
+
@file_path = file_path.strip
|
25
|
+
@media_type = media_type || case @file_path.downcase
|
26
|
+
when /.*\.html?$/
|
27
|
+
'application/xhtml+xml'
|
28
|
+
when /.*\.css$/
|
29
|
+
'text/css'
|
30
|
+
when /.*\.(jpeg|jpg)$/
|
31
|
+
'image/jpeg'
|
32
|
+
when /.*\.png$/
|
33
|
+
'image/png'
|
34
|
+
when /.*\.gif$/
|
35
|
+
'image/gif'
|
36
|
+
when /.*\.svg$/
|
37
|
+
'image/svg+xml'
|
38
|
+
when /.*\.ncx$/
|
39
|
+
'application/x-dtbncx+xml'
|
40
|
+
when /.*\.opf$/
|
41
|
+
'application/oebps-package+xml'
|
42
|
+
else
|
43
|
+
raise 'Unknown media type'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
module Thepub
|
5
|
+
module Epub
|
6
|
+
|
7
|
+
class NCX
|
8
|
+
include ContainerItem
|
9
|
+
|
10
|
+
def initialize(uid, file_path = 'toc.ncx')
|
11
|
+
@file_path = file_path
|
12
|
+
@media_type = 'application/x-dtbncx+xml'
|
13
|
+
@head = Head.new(uid)
|
14
|
+
@doc_title = DocTitle.new('Untitled')
|
15
|
+
@nav_map = NavMap.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def title
|
19
|
+
@doc_title.text
|
20
|
+
end
|
21
|
+
|
22
|
+
def title=(text)
|
23
|
+
@doc_title = DocTitle.new(text)
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :nav_map
|
27
|
+
|
28
|
+
def to_xml
|
29
|
+
out = ''
|
30
|
+
builder = Builder::XmlMarkup.new(:target => out)
|
31
|
+
builder.instruct!
|
32
|
+
builder.declare! :DOCTYPE, :ncx, :PUBLIC, "-//NISO//DTD ncx 2005-1//EN", "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd"
|
33
|
+
builder.ncx :xmlns => "http://www.daisy.org/z3986/2005/ncx/", :version => "2005-1" do
|
34
|
+
@nav_map.calc_depth_and_play_order
|
35
|
+
@head.depth = @nav_map.depth
|
36
|
+
@head.to_xml(builder)
|
37
|
+
@doc_title.to_xml(builder)
|
38
|
+
@nav_map.to_xml(builder)
|
39
|
+
end
|
40
|
+
out
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
File.open(@file_path, 'w') do |f|
|
45
|
+
f << to_xml
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Head < Struct.new(
|
50
|
+
:uid
|
51
|
+
)
|
52
|
+
|
53
|
+
attr_accessor :depth
|
54
|
+
|
55
|
+
def to_xml(builder)
|
56
|
+
builder.head do
|
57
|
+
builder.meta :name => "dtb:uid", :content => self.uid
|
58
|
+
builder.meta :name => "dtb:depth", :content => @depth
|
59
|
+
builder.meta :name => "dtb:totalPageCount", :content => 0
|
60
|
+
builder.meta :name => "dtb:maxPageNumber", :content => 0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class DocTitle < Struct.new(
|
66
|
+
:text
|
67
|
+
)
|
68
|
+
|
69
|
+
def to_xml(builder)
|
70
|
+
builder.docTitle do
|
71
|
+
builder.text self.text
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class NavPoint < Struct.new(
|
77
|
+
:title,
|
78
|
+
:src
|
79
|
+
)
|
80
|
+
|
81
|
+
def initialize(title, src, points = nil)
|
82
|
+
super(title, src)
|
83
|
+
@play_order = 0
|
84
|
+
@points = points || []
|
85
|
+
end
|
86
|
+
|
87
|
+
attr_accessor :play_order
|
88
|
+
attr_accessor :points
|
89
|
+
|
90
|
+
def to_xml(builder)
|
91
|
+
builder.navPoint :id => point_id(@play_order), :playOrder => @play_order do
|
92
|
+
builder.navLabel do
|
93
|
+
builder.text self.title
|
94
|
+
end
|
95
|
+
builder.content :src => self.src
|
96
|
+
@points.each { |point| point.to_xml(builder) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def point_id(play_order)
|
103
|
+
"navPoint-#{play_order}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class NavMap < NavPoint
|
108
|
+
|
109
|
+
def initialize
|
110
|
+
super(nil, nil)
|
111
|
+
@depth = 1
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :depth
|
115
|
+
|
116
|
+
def calc_depth_and_play_order
|
117
|
+
play_order = 0
|
118
|
+
l = lambda do |points, depth|
|
119
|
+
@depth = depth if depth > @depth
|
120
|
+
points.each do |pt|
|
121
|
+
pt.play_order = (play_order += 1)
|
122
|
+
l.call(pt.points, depth + 1) unless pt.points.empty?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
l.call(@points, @depth = 1)
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_xml(builder)
|
129
|
+
builder.navMap do
|
130
|
+
@points.each { |point| point.to_xml(builder) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'builder'
|
4
|
+
|
5
|
+
module Thepub
|
6
|
+
module Epub
|
7
|
+
|
8
|
+
# OEBPS Container Format (OCF) 1.0 wrapper
|
9
|
+
# (see http://www.idpf.org/ocf/ocf1.0/download/ocf10.htm)
|
10
|
+
#
|
11
|
+
class OCF
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@items = []
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :items
|
18
|
+
|
19
|
+
def <<(item)
|
20
|
+
if item.kind_of? ContainerItem
|
21
|
+
@items << item
|
22
|
+
elsif item.is_a? String
|
23
|
+
@items << Item.new(item)
|
24
|
+
else
|
25
|
+
raise "Unsupported item class: #{item.class}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_xml
|
30
|
+
out = ''
|
31
|
+
builder = Builder::XmlMarkup.new(:target => out)
|
32
|
+
builder.instruct!
|
33
|
+
builder.container :xmlns => "urn:oasis:names:tc:opendocument:xmlns:container", :version => "1.0" do
|
34
|
+
builder.rootfiles do
|
35
|
+
@items.each do |item|
|
36
|
+
builder.rootfile 'full-path' => item.file_path, 'media-type' => item.media_type
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
out
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
meta_inf = 'META-INF'
|
45
|
+
FileUtils.mkdir_p(meta_inf)
|
46
|
+
File.open(File.join(meta_inf, 'container.xml'), 'w') do |f|
|
47
|
+
f << to_xml
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def zip(output_path)
|
52
|
+
File.open('mimetype', 'w') do |f|
|
53
|
+
f << 'application/epub+zip'
|
54
|
+
end
|
55
|
+
# mimetype has to be first in the archive
|
56
|
+
%x(zip -X9 \"#{output_path}\" mimetype)
|
57
|
+
%x(zip -Xr9D \"#{output_path}\" * -xi mimetype)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
module Thepub
|
5
|
+
module Epub
|
6
|
+
|
7
|
+
# Open Packaging Format (OPF) 2.0 wrapper
|
8
|
+
# (see http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html)
|
9
|
+
#
|
10
|
+
class OPF
|
11
|
+
include ContainerItem
|
12
|
+
|
13
|
+
def initialize(uid, file_path = 'package.opf')
|
14
|
+
@file_path = file_path
|
15
|
+
@media_type = 'application/oebps-package+xml'
|
16
|
+
@metadata = Metadata.new('Untitled', 'en', uid, Date.today.to_s)
|
17
|
+
@items = []
|
18
|
+
@ncx = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
class Metadata < Struct.new(
|
22
|
+
:title,
|
23
|
+
:language,
|
24
|
+
:identifier,
|
25
|
+
:date,
|
26
|
+
:subject,
|
27
|
+
:description,
|
28
|
+
:relation,
|
29
|
+
:creator,
|
30
|
+
:publisher,
|
31
|
+
:rights
|
32
|
+
)
|
33
|
+
|
34
|
+
def to_xml(builder)
|
35
|
+
builder.metadata 'xmlns:dc' => "http://purl.org/dc/elements/1.1/",
|
36
|
+
'xmlns:dcterms' => "http://purl.org/dc/terms/",
|
37
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
38
|
+
'xmlns:opf' => "http://www.idpf.org/2007/opf" do
|
39
|
+
# Required elements
|
40
|
+
builder.dc :title do
|
41
|
+
builder << self.title
|
42
|
+
end
|
43
|
+
builder.dc :language, 'xsi:type' => "dcterms:RFC3066" do
|
44
|
+
builder << self.language
|
45
|
+
end
|
46
|
+
builder.dc :identifier, :id => 'dcidid', 'opf:scheme' => 'URI' do
|
47
|
+
builder << self.identifier
|
48
|
+
end
|
49
|
+
# Optional elements
|
50
|
+
builder.dc :subject do
|
51
|
+
builder << self.subject
|
52
|
+
end if self.subject
|
53
|
+
builder.dc :description do
|
54
|
+
builder << self.description
|
55
|
+
end if self.description
|
56
|
+
builder.dc :relation do
|
57
|
+
builder << self.relation
|
58
|
+
end if self.relation
|
59
|
+
builder.dc :creator do # TODO: roles
|
60
|
+
builder << self.creator
|
61
|
+
end if self.creator
|
62
|
+
builder.dc :publisher do
|
63
|
+
builder << self.publisher
|
64
|
+
end if self.publisher
|
65
|
+
builder.dc :date do
|
66
|
+
builder << self.date.to_s
|
67
|
+
end if self.date
|
68
|
+
builder.dc :rights do
|
69
|
+
builder << self.rights
|
70
|
+
end if self.rights
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :metadata
|
76
|
+
attr_reader :items
|
77
|
+
|
78
|
+
def <<(item)
|
79
|
+
if item.kind_of? NCX
|
80
|
+
@ncx = item
|
81
|
+
elsif item.kind_of? ContainerItem
|
82
|
+
@items << item
|
83
|
+
elsif item.is_a? String
|
84
|
+
@items << Item.new(item)
|
85
|
+
else
|
86
|
+
raise "Unsupported item class: #{item.class}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_xml
|
91
|
+
out = ''
|
92
|
+
builder = Builder::XmlMarkup.new(:target => out)
|
93
|
+
builder.instruct!
|
94
|
+
builder.package :xmlns => "http://www.idpf.org/2007/opf",
|
95
|
+
'unique-identifier' => "dcidid",
|
96
|
+
'version' => "2.0" do
|
97
|
+
@metadata.to_xml(builder)
|
98
|
+
manifest_to_xml(builder)
|
99
|
+
spine_to_xml(builder)
|
100
|
+
end
|
101
|
+
out
|
102
|
+
end
|
103
|
+
|
104
|
+
def save
|
105
|
+
File.open(@file_path, 'w') do |f|
|
106
|
+
f << to_xml
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def item_id(index)
|
113
|
+
"item-#{index + 1}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def manifest_to_xml(builder)
|
117
|
+
builder.manifest do
|
118
|
+
# NCX has fixed id
|
119
|
+
builder.item :id => 'ncx', :href => @ncx.file_path, 'media-type' => @ncx.media_type if @ncx
|
120
|
+
@items.each_with_index do |item, index|
|
121
|
+
builder.item :id => item_id(index), :href => item.file_path, 'media-type' => item.media_type
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def spine_to_xml(builder)
|
127
|
+
# toc attribute points to the NCX item in manifest
|
128
|
+
builder.spine :toc => 'ncx' do
|
129
|
+
@items.each_with_index do |item, index|
|
130
|
+
builder.itemref :idref => item_id(index) if item.document?
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
data/lib/thepub/epub.rb
ADDED
data/lib/thepub.rb
ADDED
data/test/test_helper.rb
ADDED
data/test/test_ncx.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestToc < Test::Unit::TestCase
|
4
|
+
def test_toc_create
|
5
|
+
ncx = Thepub::Epub::NCX.new('some-ncx')
|
6
|
+
s = ncx.to_xml
|
7
|
+
#p s
|
8
|
+
doc = Nokogiri::XML.parse(s)
|
9
|
+
assert_equal('some-ncx', doc.at("//xmlns:meta[@name='dtb:uid']")['content'])
|
10
|
+
assert_equal('1', doc.at("//xmlns:meta[@name='dtb:depth']")['content'])
|
11
|
+
assert_equal('0', doc.at("//xmlns:meta[@name='dtb:totalPageCount']")['content'])
|
12
|
+
assert_equal('0', doc.at("//xmlns:meta[@name='dtb:maxPageNumber']")['content'])
|
13
|
+
assert_equal('Untitled', doc.at("//xmlns:docTitle/xmlns:text").inner_text)
|
14
|
+
assert_not_nil(doc.at('//xmlns:navMap'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_nav_map
|
18
|
+
ncx = Thepub::Epub::NCX.new('some-ncx')
|
19
|
+
ncx.nav_map.points << Thepub::Epub::NCX::NavPoint.new('Intro', 'intro.html')
|
20
|
+
ncx.nav_map.points << Thepub::Epub::NCX::NavPoint.new('Chapter 1', 'chapter-1.html')
|
21
|
+
ncx.nav_map.points << Thepub::Epub::NCX::NavPoint.new('Chapter 2', 'chapter-2.html')
|
22
|
+
ncx.nav_map.points[2].points << Thepub::Epub::NCX::NavPoint.new('Chapter 2-1', 'chapter-2-1.html')
|
23
|
+
ncx.nav_map.points << Thepub::Epub::NCX::NavPoint.new('Glossary', 'glossary.html')
|
24
|
+
ncx.nav_map.points[1].points << Thepub::Epub::NCX::NavPoint.new('Chapter 1-1', 'chapter-1-1.html')
|
25
|
+
ncx.nav_map.points[1].points << Thepub::Epub::NCX::NavPoint.new('Chapter 1-2', 'chapter-1-2.html')
|
26
|
+
s = ncx.to_xml
|
27
|
+
#p s
|
28
|
+
doc = Nokogiri::XML.parse(s)
|
29
|
+
assert_equal(4, doc.xpath('//xmlns:navMap/xmlns:navPoint').size)
|
30
|
+
assert_equal('2', doc.at("//xmlns:meta[@name='dtb:depth']")['content'])
|
31
|
+
assert_equal('1', doc.at('//xmlns:navMap/xmlns:navPoint[position()=1]')['playOrder'])
|
32
|
+
assert_equal('2', doc.at('//xmlns:navMap/xmlns:navPoint[position()=2]')['playOrder'])
|
33
|
+
assert_equal('3', doc.at('//xmlns:navMap/xmlns:navPoint[position()=2]/xmlns:navPoint[position()=1]')['playOrder'])
|
34
|
+
assert_equal('5', doc.at('//xmlns:navMap/xmlns:navPoint[position()=3]')['playOrder'])
|
35
|
+
assert_equal('navPoint-2', doc.at('//xmlns:navMap/xmlns:navPoint[position()=2]')['id'])
|
36
|
+
assert_equal('Chapter 1', doc.at('//xmlns:navMap/xmlns:navPoint[position()=2]/xmlns:navLabel/xmlns:text').inner_text)
|
37
|
+
assert_equal('chapter-1.html', doc.at('//xmlns:navMap/xmlns:navPoint[position()=2]/xmlns:content')['src'])
|
38
|
+
assert_equal(7, doc.xpath('//xmlns:navMap//xmlns:navPoint').size)
|
39
|
+
end
|
40
|
+
end
|
data/test/test_ocf.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestContainer < Test::Unit::TestCase
|
4
|
+
def test_container_create
|
5
|
+
container = Thepub::Epub::OCF.new
|
6
|
+
container << 'test.html'
|
7
|
+
container << Thepub::Epub::OPF.new('12345')
|
8
|
+
s = container.to_xml
|
9
|
+
#p s
|
10
|
+
doc = Nokogiri::XML.parse(s)
|
11
|
+
assert_not_nil(doc.at('rootfile'))
|
12
|
+
assert_equal('test.html', doc.at('rootfile[1]')['full-path'])
|
13
|
+
assert_equal('application/xhtml+xml', doc.at('rootfile[1]')['media-type'])
|
14
|
+
assert_equal('package.opf', doc.at('rootfile[2]')['full-path'])
|
15
|
+
assert_equal('application/oebps-package+xml', doc.at('rootfile[2]')['media-type'])
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_container_create_fail
|
19
|
+
assert_raise(RuntimeError) do
|
20
|
+
# unknown mime type
|
21
|
+
container = Thepub::Epub::OCF.new
|
22
|
+
container << 'blah.blah'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/test/test_opf.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestContent < Test::Unit::TestCase
|
4
|
+
def test_create
|
5
|
+
opf = Thepub::Epub::OPF.new('some-opf')
|
6
|
+
s = opf.to_xml
|
7
|
+
doc = Nokogiri::XML.parse(s)
|
8
|
+
#p doc
|
9
|
+
|
10
|
+
metadata = doc.at('metadata')
|
11
|
+
assert_not_nil(metadata)
|
12
|
+
assert_equal('some-opf', metadata.xpath('dc:identifier', 'xmlns:dc' => "http://purl.org/dc/elements/1.1/").inner_text)
|
13
|
+
assert_equal('Untitled', metadata.xpath('dc:title', 'xmlns:dc' => "http://purl.org/dc/elements/1.1/").inner_text)
|
14
|
+
assert_equal('en', metadata.xpath('dc:language', 'xmlns:dc' => "http://purl.org/dc/elements/1.1/").inner_text)
|
15
|
+
assert_equal(Date.today.to_s, metadata.xpath('dc:date', 'xmlns:dc' => "http://purl.org/dc/elements/1.1/").inner_text)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_manifest_create
|
19
|
+
opf = Thepub::Epub::OPF.new('some-opf')
|
20
|
+
opf << Thepub::Epub::NCX.new('some-ncx')
|
21
|
+
s = opf.to_xml
|
22
|
+
doc = Nokogiri::XML.parse(s)
|
23
|
+
#p doc
|
24
|
+
|
25
|
+
manifest = doc.at('manifest')
|
26
|
+
assert_not_nil(manifest)
|
27
|
+
assert_equal(1, manifest.children.size)
|
28
|
+
assert_equal('ncx', manifest.at('item[@href="toc.ncx"]')['id'])
|
29
|
+
assert_not_nil(doc.at('spine'))
|
30
|
+
assert_equal(0, doc.xpath('spine/item').size)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_manifest_and_spine_items
|
34
|
+
opf = Thepub::Epub::OPF.new('some-opf')
|
35
|
+
opf << 'style.css'
|
36
|
+
opf << 'more-style.css'
|
37
|
+
opf << ' logo.jpg '
|
38
|
+
opf << 'intro.html'
|
39
|
+
opf << ' image.png'
|
40
|
+
opf << 'picture.jpeg '
|
41
|
+
opf << Thepub::Epub::NCX.new('some-ncx')
|
42
|
+
opf << 'chapter-1.html'
|
43
|
+
opf << 'glossary.html'
|
44
|
+
s = opf.to_xml
|
45
|
+
doc = Nokogiri::HTML(s)
|
46
|
+
#p doc
|
47
|
+
|
48
|
+
manifest = doc.at('manifest')
|
49
|
+
assert_not_nil(manifest)
|
50
|
+
assert_equal(2, manifest.xpath('item[@media-type="text/css"]').size)
|
51
|
+
assert_equal(2, manifest.search('item[@media-type="image/jpeg"]').size)
|
52
|
+
assert_equal(1, manifest.search('item[@media-type="image/png"]').size)
|
53
|
+
# NCX is first and always has id = 'ncx'
|
54
|
+
assert_equal('ncx', manifest.at('./item[position()=1]')['id'])
|
55
|
+
|
56
|
+
spine = doc.at('spine')
|
57
|
+
# attribute toc has and id of NCX manifest item
|
58
|
+
assert_equal('ncx', spine['toc'])
|
59
|
+
assert_equal(3, spine.search('itemref').size)
|
60
|
+
assert_equal('item-4', spine.at('./itemref[position()=1]')['idref'])
|
61
|
+
assert_equal('item-8', spine.at('./itemref[position()=3]')['idref'])
|
62
|
+
end
|
63
|
+
end
|
data/thepub.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
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{thepub}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Dmitri Goutnik, Invisible Llama", "William Melody"]
|
12
|
+
s.date = %q{2010-02-01}
|
13
|
+
s.description = %q{Extraction of Repub's epub module and associated tests}
|
14
|
+
s.email = %q{hi@williammelody.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/thepub.rb",
|
27
|
+
"lib/thepub/epub.rb",
|
28
|
+
"lib/thepub/epub/container_item.rb",
|
29
|
+
"lib/thepub/epub/ncx.rb",
|
30
|
+
"lib/thepub/epub/ocf.rb",
|
31
|
+
"lib/thepub/epub/opf.rb",
|
32
|
+
"test/test_helper.rb",
|
33
|
+
"test/test_ncx.rb",
|
34
|
+
"test/test_ocf.rb",
|
35
|
+
"test/test_opf.rb",
|
36
|
+
"thepub.gemspec"
|
37
|
+
]
|
38
|
+
s.homepage = %q{http://github.com/autodata/thepub}
|
39
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.5}
|
42
|
+
s.summary = %q{Extraction of Repub's epub module and associated tests}
|
43
|
+
s.test_files = [
|
44
|
+
"test/test_helper.rb",
|
45
|
+
"test/test_ncx.rb",
|
46
|
+
"test/test_ocf.rb",
|
47
|
+
"test/test_opf.rb"
|
48
|
+
]
|
49
|
+
|
50
|
+
if s.respond_to? :specification_version then
|
51
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
52
|
+
s.specification_version = 3
|
53
|
+
|
54
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
55
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
56
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
59
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
60
|
+
end
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
63
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thepub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dmitri Goutnik, Invisible Llama
|
8
|
+
- William Melody
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-02-01 00:00:00 -06:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: thoughtbot-shoulda
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: nokogiri
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
36
|
+
description: Extraction of Repub's epub module and associated tests
|
37
|
+
email: hi@williammelody.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- LICENSE
|
44
|
+
- README.markdown
|
45
|
+
files:
|
46
|
+
- .document
|
47
|
+
- .gitignore
|
48
|
+
- LICENSE
|
49
|
+
- README.markdown
|
50
|
+
- Rakefile
|
51
|
+
- VERSION
|
52
|
+
- lib/thepub.rb
|
53
|
+
- lib/thepub/epub.rb
|
54
|
+
- lib/thepub/epub/container_item.rb
|
55
|
+
- lib/thepub/epub/ncx.rb
|
56
|
+
- lib/thepub/epub/ocf.rb
|
57
|
+
- lib/thepub/epub/opf.rb
|
58
|
+
- test/test_helper.rb
|
59
|
+
- test/test_ncx.rb
|
60
|
+
- test/test_ocf.rb
|
61
|
+
- test/test_opf.rb
|
62
|
+
- thepub.gemspec
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/autodata/thepub
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --charset=UTF-8
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.5
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Extraction of Repub's epub module and associated tests
|
91
|
+
test_files:
|
92
|
+
- test/test_helper.rb
|
93
|
+
- test/test_ncx.rb
|
94
|
+
- test/test_ocf.rb
|
95
|
+
- test/test_opf.rb
|