rpub 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -1
- data/.rspec +0 -1
- data/.travis.yml +3 -4
- data/.yardopts +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +70 -46
- data/Guardfile +6 -0
- data/HISTORY.md +10 -0
- data/README.md +1 -1
- data/Rakefile +7 -2
- data/bin/rpub +64 -1
- data/doc/.gitignore +8 -0
- data/doc/api/Rpub.html +339 -0
- data/doc/api/Rpub/Book.html +983 -0
- data/doc/api/Rpub/Chapter.html +737 -0
- data/doc/api/Rpub/Command.html +356 -0
- data/doc/api/Rpub/Commands.html +117 -0
- data/doc/api/Rpub/Commands/Clean.html +216 -0
- data/doc/api/Rpub/Commands/Compile.html +218 -0
- data/doc/api/Rpub/Commands/Generate.html +242 -0
- data/doc/api/Rpub/Commands/Package.html +230 -0
- data/doc/api/Rpub/Commands/Preview.html +216 -0
- data/doc/api/Rpub/Commands/Stats.html +226 -0
- data/doc/api/Rpub/Compressor.html +687 -0
- data/doc/api/Rpub/Context.html +553 -0
- data/doc/api/Rpub/Document.html +647 -0
- data/doc/api/Rpub/Document/OutlineElement.html +388 -0
- data/doc/api/Rpub/Epub.html +465 -0
- data/doc/api/Rpub/Epub/Container.html +224 -0
- data/doc/api/Rpub/Epub/Content.html +344 -0
- data/doc/api/Rpub/Epub/Cover.html +236 -0
- data/doc/api/Rpub/Epub/HtmlToc.html +240 -0
- data/doc/api/Rpub/Epub/Toc.html +244 -0
- data/doc/api/Rpub/FilesystemSource.html +544 -0
- data/doc/api/Rpub/HashDelegation.html +281 -0
- data/doc/api/Rpub/HashDelegation/ClassMethods.html +175 -0
- data/doc/api/Rpub/MediaType.html +192 -0
- data/doc/api/Rpub/Preview.html +464 -0
- data/doc/api/Rpub/XmlFile.html +457 -0
- data/doc/api/_index.html +405 -0
- data/doc/api/class_list.html +54 -0
- data/doc/api/css/common.css +1 -0
- data/doc/api/css/full_list.css +57 -0
- data/doc/api/css/style.css +339 -0
- data/doc/api/file.HISTORY.html +131 -0
- data/doc/api/file.LICENSE.html +92 -0
- data/doc/api/file.README.html +337 -0
- data/doc/api/file_list.html +62 -0
- data/doc/api/frames.html +26 -0
- data/doc/api/index.html +337 -0
- data/doc/api/js/app.js +219 -0
- data/doc/api/js/full_list.js +178 -0
- data/doc/api/js/jquery.js +4 -0
- data/doc/api/method_list.html +533 -0
- data/doc/api/top-level-namespace.html +112 -0
- data/doc/index.html +312 -0
- data/doc/javascripts/scale.fix.js +17 -0
- data/doc/params.json +1 -0
- data/doc/stylesheets/pygment_trac.css +69 -0
- data/doc/stylesheets/styles.css +255 -0
- data/features/clean.feature +31 -0
- data/features/compile.feature +49 -0
- data/features/embedded_assets.feature +51 -0
- data/features/generate.feature +63 -0
- data/features/layout.feature +41 -0
- data/features/package.feature +30 -0
- data/features/previews.feature +66 -0
- data/features/stats.feature +18 -0
- data/features/step_definitions/general_steps.rb +60 -0
- data/features/styles.feature +33 -0
- data/features/support/env.rb +7 -0
- data/features/table_of_contents.feature +35 -0
- data/lib/rpub.rb +28 -31
- data/lib/rpub/book.rb +9 -16
- data/lib/rpub/chapter.rb +4 -54
- data/lib/rpub/command.rb +32 -0
- data/lib/rpub/commands/clean.rb +4 -49
- data/lib/rpub/commands/compile.rb +4 -49
- data/lib/rpub/commands/generate.rb +10 -67
- data/lib/rpub/commands/package.rb +9 -37
- data/lib/rpub/commands/preview.rb +4 -54
- data/lib/rpub/commands/stats.rb +6 -10
- data/lib/rpub/compressor.rb +3 -3
- data/lib/rpub/context.rb +48 -0
- data/lib/rpub/document.rb +68 -0
- data/lib/rpub/epub.rb +8 -7
- data/lib/rpub/epub/content.rb +9 -30
- data/lib/rpub/epub/cover.rb +1 -8
- data/lib/rpub/epub/html_toc.rb +4 -9
- data/lib/rpub/epub/toc.rb +16 -13
- data/lib/rpub/filesystem_source.rb +47 -0
- data/lib/rpub/media_type.rb +16 -0
- data/lib/rpub/preview.rb +29 -0
- data/lib/rpub/version.rb +1 -1
- data/lib/rpub/xml_file.rb +4 -1
- data/rpub.gemspec +6 -7
- data/spec/rpub/book_spec.rb +45 -45
- data/spec/rpub/chapter_spec.rb +87 -22
- data/spec/rpub/epub/container_spec.rb +3 -5
- data/spec/rpub/epub/content_spec.rb +62 -41
- data/spec/rpub/epub/cover_spec.rb +3 -5
- data/spec/rpub/epub/html_toc_spec.rb +8 -8
- data/spec/rpub/epub/toc_spec.rb +20 -22
- data/spec/rpub_spec.rb +1 -3
- data/spec/spec_helper.rb +28 -0
- data/support/config.yml +1 -0
- data/support/styles.css +3 -3
- metadata +131 -120
- data/lib/rpub/commander.rb +0 -23
- data/lib/rpub/commands/base.rb +0 -33
- data/lib/rpub/commands/help.rb +0 -37
- data/lib/rpub/commands/main.rb +0 -45
- data/lib/rpub/compilation_helpers.rb +0 -73
- data/lib/rpub/subclass_tracker.rb +0 -53
- data/spec/rpub/commands/clean_spec.rb +0 -46
- data/spec/rpub/commands/generate_spec.rb +0 -52
- data/spec/rpub/commands/main_spec.rb +0 -26
- data/spec/rpub/commands/package_spec.rb +0 -33
- data/spec/rpub/commands/preview_spec.rb +0 -43
@@ -0,0 +1,68 @@
|
|
1
|
+
module Rpub
|
2
|
+
class Document
|
3
|
+
KRAMDOWN_OPTIONS = {
|
4
|
+
:coderay_line_numbers => nil
|
5
|
+
}
|
6
|
+
|
7
|
+
OutlineElement = Struct.new(:level, :text, :html_id)
|
8
|
+
|
9
|
+
def initialize(content, layout)
|
10
|
+
@document = Kramdown::Document.new(content, KRAMDOWN_OPTIONS.merge(:template => layout))
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Kramdown::Element] Toc elements hierarchy
|
14
|
+
def toc
|
15
|
+
Kramdown::Converter::Toc.convert(document.root).first
|
16
|
+
end
|
17
|
+
|
18
|
+
# Ordered headers for this chapter, each header as an object responding
|
19
|
+
# to #level and #text.
|
20
|
+
#
|
21
|
+
# @return [Array<#text,#level,#html_id>] list of headers for this chapter
|
22
|
+
def outline
|
23
|
+
@outline ||= elements(:header).map do |element|
|
24
|
+
OutlineElement.new(
|
25
|
+
element.options[:level],
|
26
|
+
element_text(element),
|
27
|
+
Kramdown::Converter::Html.send(:new, document, { :auto_id_prefix => '' }).generate_id(element.options[:raw_text])
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] content parsed to HTML by the markdown engine.
|
33
|
+
def to_html
|
34
|
+
@to_html ||= Typogruby.improve(@document.to_html)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String] Text of the first heading in this chapter
|
38
|
+
def title
|
39
|
+
@title ||= begin
|
40
|
+
(heading = outline.first) ? heading.text : 'untitled'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Array<String>] list of all image references
|
45
|
+
def images
|
46
|
+
@images ||= elements(:img).map { |e| e.attr['src'] }
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :document
|
52
|
+
|
53
|
+
def element_text(element)
|
54
|
+
elements(:text, element).map { |e| e.value }.join
|
55
|
+
end
|
56
|
+
|
57
|
+
def elements(type, root = @document.root)
|
58
|
+
collector = lambda do |element|
|
59
|
+
element.children.select { |e|
|
60
|
+
e.type == type
|
61
|
+
} + element.children.map { |e|
|
62
|
+
collector.call(e)
|
63
|
+
}.flatten
|
64
|
+
end
|
65
|
+
collector.call(root)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/rpub/epub.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Rpub
|
2
2
|
class Epub
|
3
|
+
include Rpub.source
|
3
4
|
attr_reader :book, :styles
|
4
5
|
|
5
6
|
def initialize(book, styles)
|
@@ -9,26 +10,26 @@ module Rpub
|
|
9
10
|
def manifest_in(target)
|
10
11
|
target.store_file 'mimetype', 'application/epub+zip'
|
11
12
|
target.compress_file 'META-INF/container.xml', Container.new
|
12
|
-
target.compress_file 'OEBPS/content.opf',
|
13
|
-
target.compress_file 'OEBPS/toc.ncx',
|
14
|
-
target.compress_file 'OEBPS/styles.css',
|
13
|
+
target.compress_file 'OEBPS/content.opf', Content.new(book)
|
14
|
+
target.compress_file 'OEBPS/toc.ncx', Toc.new(book)
|
15
|
+
target.compress_file 'OEBPS/styles.css', styles
|
15
16
|
if book.has_cover?
|
16
17
|
target.compress_file 'OEBPS/cover.html', Cover.new(book)
|
17
|
-
target.compress_file File.join('OEBPS', book.cover_image),
|
18
|
+
target.compress_file File.join('OEBPS', book.config.cover_image), read(book.config.cover_image)
|
18
19
|
end
|
19
20
|
if book.has_toc?
|
20
21
|
target.compress_file 'OEBPS/toc.html', toc { HtmlToc.new(book).render }
|
21
22
|
end
|
22
23
|
if book.has_fonts?
|
23
24
|
book.fonts.each do |font|
|
24
|
-
target.compress_file File.join('OEBPS', font),
|
25
|
+
target.compress_file File.join('OEBPS', font), read(font)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
book.each do |chapter|
|
28
29
|
target.compress_file File.join('OEBPS', chapter.filename), chapter.to_html
|
29
30
|
end
|
30
31
|
book.images.each do |image|
|
31
|
-
target.compress_file File.join('OEBPS', image),
|
32
|
+
target.compress_file File.join('OEBPS', image), read(image)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
@@ -36,7 +37,7 @@ module Rpub
|
|
36
37
|
|
37
38
|
def toc
|
38
39
|
@body = yield
|
39
|
-
ERB.new(
|
40
|
+
ERB.new(read(book.layout)).result(binding)
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
data/lib/rpub/epub/content.rb
CHANGED
@@ -1,33 +1,19 @@
|
|
1
1
|
module Rpub
|
2
2
|
class Epub
|
3
3
|
class Content < XmlFile
|
4
|
-
attr_reader :book
|
5
|
-
|
6
|
-
MEDIA_TYPES = {
|
7
|
-
'png' => 'image/png',
|
8
|
-
'gif' => 'image/gif',
|
9
|
-
'jpg' => 'image/jpeg',
|
10
|
-
'svg' => 'image/svg+xml'
|
11
|
-
}
|
12
|
-
|
13
|
-
def initialize(book)
|
14
|
-
@book = book
|
15
|
-
super()
|
16
|
-
end
|
17
|
-
|
18
4
|
def render
|
19
5
|
xml.instruct!
|
20
6
|
xml.declare! :DOCTYPE, :package, :PUBLIC, '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
|
21
7
|
xml.package 'xmlns' => 'http://www.idpf.org/2007/opf', 'unique-identifier' => 'BookId', 'version' => '2.0' do
|
22
8
|
xml.metadata 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/', 'xmlns:opf' => 'http://www.idpf.org/2007/opf' do
|
23
|
-
xml.dc :language, book.language
|
24
|
-
xml.dc :title, book.title
|
25
|
-
xml.dc :creator, book.creator, 'opf:role' => 'aut'
|
26
|
-
xml.dc :publisher, book.publisher
|
27
|
-
xml.dc :subject, book.subject
|
9
|
+
xml.dc :language, book.config.language
|
10
|
+
xml.dc :title, book.config.title
|
11
|
+
xml.dc :creator, book.config.creator, 'opf:role' => 'aut'
|
12
|
+
xml.dc :publisher, book.config.publisher
|
13
|
+
xml.dc :subject, book.config.subject
|
28
14
|
xml.dc :identifier, book.uid, :id => 'BookId'
|
29
|
-
xml.dc :rights, book.rights
|
30
|
-
xml.dc :description, book.description
|
15
|
+
xml.dc :rights, book.config.rights
|
16
|
+
xml.dc :description, book.config.description
|
31
17
|
|
32
18
|
if book.has_cover?
|
33
19
|
xml.meta :name => 'cover', :content => 'cover-image'
|
@@ -46,11 +32,11 @@ module Rpub
|
|
46
32
|
|
47
33
|
if book.has_cover?
|
48
34
|
xml.item 'id' => 'cover', 'href' => 'cover.html', 'media-type' => 'application/xhtml+xml'
|
49
|
-
xml.item 'id' => 'cover-image', 'href' => book.cover_image, 'media-type' => guess_media_type(book.cover_image)
|
35
|
+
xml.item 'id' => 'cover-image', 'href' => book.config.cover_image, 'media-type' => MediaType.guess_media_type(book.config.cover_image)
|
50
36
|
end
|
51
37
|
|
52
38
|
book.images.each do |image|
|
53
|
-
xml.item 'id' => File.basename(image), 'href' => image, 'media-type' => guess_media_type(image)
|
39
|
+
xml.item 'id' => File.basename(image), 'href' => image, 'media-type' => MediaType.guess_media_type(image)
|
54
40
|
end
|
55
41
|
|
56
42
|
if book.has_toc?
|
@@ -83,13 +69,6 @@ module Rpub
|
|
83
69
|
end
|
84
70
|
end
|
85
71
|
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
# TODO refactor into separate guesser object
|
90
|
-
def guess_media_type(filename)
|
91
|
-
MEDIA_TYPES.fetch(filename[/\.(gif|png|jpe?g|svg)$/, 1]) { 'image/png' }
|
92
|
-
end
|
93
72
|
end
|
94
73
|
end
|
95
74
|
end
|
data/lib/rpub/epub/cover.rb
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
module Rpub
|
2
2
|
class Epub
|
3
3
|
class Cover < XmlFile
|
4
|
-
attr_reader :book
|
5
|
-
|
6
|
-
def initialize(book)
|
7
|
-
@book = book
|
8
|
-
super()
|
9
|
-
end
|
10
|
-
|
11
4
|
def render
|
12
5
|
xml.declare! :DOCTYPE, :html, :PUBLIC, '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
|
13
6
|
xml.html :xmlns => 'http://www.w3.org/1999/xhtml' do
|
@@ -17,7 +10,7 @@ module Rpub
|
|
17
10
|
end
|
18
11
|
xml.body do
|
19
12
|
xml.div :id => 'cover-image' do
|
20
|
-
xml.img :src => book.cover_image, :alt => book.title
|
13
|
+
xml.img :src => book.config.cover_image, :alt => book.config.title
|
21
14
|
end
|
22
15
|
end
|
23
16
|
end
|
data/lib/rpub/epub/html_toc.rb
CHANGED
@@ -1,21 +1,16 @@
|
|
1
1
|
module Rpub
|
2
2
|
class Epub
|
3
3
|
class HtmlToc < XmlFile
|
4
|
-
attr_reader :book
|
5
|
-
|
6
|
-
def initialize(book)
|
7
|
-
@book = book
|
8
|
-
super()
|
9
|
-
end
|
10
|
-
|
11
4
|
def render
|
12
5
|
xml.div :id => 'toc' do
|
13
6
|
xml.h1 'Table of Contents'
|
14
7
|
xml.div :class => 'toc' do
|
15
8
|
book.outline.each do |(filename, headings)|
|
16
9
|
headings.each do |heading|
|
17
|
-
|
18
|
-
xml.
|
10
|
+
if heading.level <= (book.config.max_level || 2)
|
11
|
+
xml.div :class => "level-#{heading.level}" do
|
12
|
+
xml.a heading.text, :href => [filename, heading.html_id].join('#')
|
13
|
+
end
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
data/lib/rpub/epub/toc.rb
CHANGED
@@ -1,26 +1,17 @@
|
|
1
1
|
module Rpub
|
2
2
|
class Epub
|
3
3
|
class Toc < XmlFile
|
4
|
-
attr_reader :book
|
5
|
-
|
6
|
-
def initialize(book)
|
7
|
-
@book = book
|
8
|
-
@play_order = -1
|
9
|
-
@max_level = book.config.fetch(:max_level) { 2 }
|
10
|
-
super()
|
11
|
-
end
|
12
|
-
|
13
4
|
def render
|
14
5
|
xml.instruct!
|
15
6
|
xml.declare! :DOCTYPE, :ncx, :PUBLIC, "-//W3C//DTD XHTML 1.1//EN", 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
|
16
7
|
xml.ncx :xmlns => 'http://www.daisy.org/z3986/2005/ncx/', :version => '2005-1' do
|
17
8
|
xml.head do
|
18
9
|
xml.meta :name => 'dtb:uid', :content => book.uid
|
19
|
-
xml.meta :name => 'dtb:depth', :content =>
|
10
|
+
xml.meta :name => 'dtb:depth', :content => max_level
|
20
11
|
xml.meta :name => 'dtb:totalPageCount', :content => '0'
|
21
12
|
xml.meta :name => 'dtb:maxPageNumber', :content => '0'
|
22
13
|
end
|
23
|
-
xml.docTitle { xml.text book.title }
|
14
|
+
xml.docTitle { xml.text book.config.title }
|
24
15
|
xml.navMap do
|
25
16
|
book.chapters.each do |chapter|
|
26
17
|
nav_points_nested_by_level chapter.toc, chapter.filename
|
@@ -31,15 +22,27 @@ module Rpub
|
|
31
22
|
|
32
23
|
private
|
33
24
|
|
25
|
+
def max_level
|
26
|
+
book.config.max_level || 2
|
27
|
+
end
|
28
|
+
|
29
|
+
def play_order
|
30
|
+
@play_order ||= 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def play_order=(v)
|
34
|
+
@play_order = v
|
35
|
+
end
|
36
|
+
|
34
37
|
def next_play_order
|
35
|
-
|
38
|
+
self.play_order = play_order + 1
|
36
39
|
end
|
37
40
|
|
38
41
|
def nav_points_nested_by_level(heading, filename, level = 1)
|
39
42
|
heading.children.each do |heading|
|
40
43
|
html_id = heading.attr[:id]
|
41
44
|
source = filename+'#'+html_id
|
42
|
-
if heading.value.options[:level] <=
|
45
|
+
if heading.value.options[:level] <= max_level
|
43
46
|
nav_point html_id, next_play_order, heading.value.options[:raw_text], source do
|
44
47
|
nav_points_nested_by_level heading, filename, level + 1
|
45
48
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Rpub
|
2
|
+
module FilesystemSource
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def read(filename)
|
6
|
+
File.read(filename)
|
7
|
+
end
|
8
|
+
|
9
|
+
def exists?(filename)
|
10
|
+
File.exists?(filename)
|
11
|
+
end
|
12
|
+
|
13
|
+
def source_files
|
14
|
+
Dir['*{.md,.markdown,.mdown,.markd}']
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(filename, content, force = false)
|
18
|
+
return if content.nil?
|
19
|
+
if !force && File.exist?(filename)
|
20
|
+
warn "Not overriding #{filename}"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
File.open(filename, 'w') do |f|
|
24
|
+
f.write content
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def force_write(filename, content)
|
29
|
+
write filename, content, true
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove(filename, dry_run = false)
|
33
|
+
if File.exist?(filename)
|
34
|
+
if dry_run
|
35
|
+
puts filename
|
36
|
+
else
|
37
|
+
File.unlink(filename)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def own_or_support_file(filename)
|
43
|
+
return filename if exists?(filename)
|
44
|
+
Rpub.support_file(filename)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rpub
|
2
|
+
module MediaType
|
3
|
+
MEDIA_TYPES = {
|
4
|
+
'png' => 'image/png',
|
5
|
+
'gif' => 'image/gif',
|
6
|
+
'jpg' => 'image/jpeg',
|
7
|
+
'svg' => 'image/svg+xml'
|
8
|
+
}
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def guess_media_type(filename)
|
13
|
+
MEDIA_TYPES.fetch(filename[/\.(gif|png|jpe?g|svg)$/, 1]) { 'image/png' }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/rpub/preview.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rpub
|
2
|
+
class Preview
|
3
|
+
attr_reader :context, :source
|
4
|
+
|
5
|
+
def initialize(context, source)
|
6
|
+
@context, @source = context, source
|
7
|
+
end
|
8
|
+
|
9
|
+
def formatted
|
10
|
+
return unless context.chapter_files.any?
|
11
|
+
move_styles_inline(plain)
|
12
|
+
end
|
13
|
+
|
14
|
+
def text
|
15
|
+
Nokogiri::HTML(plain).xpath('//text()').to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def plain
|
21
|
+
Rpub.document_factory.call(context.chapter_files.join("\n"), context.layout).to_html
|
22
|
+
end
|
23
|
+
|
24
|
+
def move_styles_inline(html)
|
25
|
+
style_block = %Q{<style>\n#{source.read(context.styles)}\n</style>}
|
26
|
+
html.gsub %r{</head>}, style_block + "\n</head>"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rpub/version.rb
CHANGED
data/lib/rpub/xml_file.rb
CHANGED
@@ -3,8 +3,11 @@ module Rpub
|
|
3
3
|
# @return [Builder::XmlMarkup]
|
4
4
|
attr_reader :xml
|
5
5
|
|
6
|
-
|
6
|
+
attr_reader :book
|
7
|
+
|
8
|
+
def initialize(book = nil)
|
7
9
|
@xml = Builder::XmlMarkup.new :indent => 2
|
10
|
+
@book = book
|
8
11
|
end
|
9
12
|
|
10
13
|
# @return [String] render this file and output as string
|
data/rpub.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require '
|
2
|
+
require File.expand_path('../lib/rpub/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
# Metadata
|
@@ -42,14 +42,13 @@ EOS
|
|
42
42
|
s.add_runtime_dependency 'builder'
|
43
43
|
s.add_runtime_dependency 'nokogiri'
|
44
44
|
s.add_runtime_dependency 'textstats'
|
45
|
-
s.add_runtime_dependency '
|
45
|
+
s.add_runtime_dependency 'commander'
|
46
46
|
s.add_development_dependency 'yard'
|
47
|
-
s.add_development_dependency 'rspec'
|
47
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
48
48
|
s.add_development_dependency 'rake'
|
49
|
-
s.add_development_dependency 'guard'
|
50
|
-
s.add_development_dependency 'guard-rspec'
|
51
|
-
s.add_development_dependency 'rb-fsevent'
|
52
|
-
s.add_development_dependency 'growl'
|
53
49
|
s.add_development_dependency 'simplecov'
|
50
|
+
s.add_development_dependency 'cucumber'
|
51
|
+
s.add_development_dependency 'aruba'
|
52
|
+
s.add_development_dependency 'coveralls'
|
54
53
|
end
|
55
54
|
|
data/spec/rpub/book_spec.rb
CHANGED
@@ -1,115 +1,115 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe Rpub::Book do
|
4
|
-
let(:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
it { should respond_to(:title) }
|
11
|
-
its(:title) { should == 'My "Awesome" Title!' }
|
12
|
-
its(:filename) { should == 'my-awesome-title-1.0.3.epub' }
|
2
|
+
let(:context) { Rpub::Context.new }
|
3
|
+
let(:subject) { described_class.new(context) }
|
4
|
+
before { allow(context).to receive(:chapter_files).and_return(['foo']) }
|
5
|
+
it { is_expected.to respond_to(:config) }
|
13
6
|
|
14
7
|
describe 'chapters' do
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
it 'has 1 chapter' do
|
9
|
+
expect(subject.chapters.size).to eq(1)
|
10
|
+
end
|
18
11
|
|
19
|
-
it {
|
12
|
+
it { is_expected.to be_kind_of(Enumerable) }
|
20
13
|
|
21
|
-
it 'should start with
|
22
|
-
|
14
|
+
it 'should start with context chapters' do
|
15
|
+
expect(subject.chapters.size).to eq(1)
|
23
16
|
end
|
24
17
|
|
25
18
|
it 'should allow chaining multiple calls' do
|
26
19
|
subject << 'foo' << 'bar'
|
27
|
-
subject.
|
20
|
+
expect(subject.chapters.size).to eq(3)
|
28
21
|
end
|
29
22
|
|
30
23
|
it 'should yield chapters' do
|
31
24
|
yielded = false
|
32
25
|
subject.each { |c| yielded = true }
|
33
|
-
yielded.
|
26
|
+
expect(yielded).to be_truthy
|
34
27
|
end
|
35
28
|
end
|
36
29
|
|
37
30
|
describe '#has_fonts?' do
|
38
31
|
it 'should not have a font by default' do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
it 'should not have a font with an empty array' do
|
43
|
-
described_class.new(nil, nil, []).should_not have_fonts
|
32
|
+
expect(context).to receive(:fonts).and_return([])
|
33
|
+
is_expected.not_to have_fonts
|
44
34
|
end
|
45
35
|
|
46
36
|
it 'should have a font with a non-empty array' do
|
47
|
-
|
37
|
+
expect(context).to receive(:fonts).and_return(['foo'])
|
38
|
+
is_expected.to have_fonts
|
48
39
|
end
|
49
40
|
end
|
50
41
|
|
51
42
|
describe '#uid' do
|
52
43
|
it 'should change when chapters change' do
|
53
|
-
|
44
|
+
expect(described_class.new(context).add_chapter('foo')).to_not eql(subject.uid)
|
54
45
|
end
|
55
46
|
|
56
47
|
it 'should change when config changes' do
|
57
|
-
|
48
|
+
expect(described_class.new(context)).to_not eql(subject.uid)
|
58
49
|
end
|
59
50
|
end
|
60
51
|
|
61
52
|
describe '#outline' do
|
53
|
+
before { expect(context).to receive(:chapter_files).and_return([]) }
|
54
|
+
|
62
55
|
it 'should return empty array when there are no chapters' do
|
63
|
-
subject.outline.
|
56
|
+
expect(subject.outline).to be_empty
|
64
57
|
end
|
65
58
|
|
66
59
|
it 'should return combination of all chapter outlines with filename' do
|
67
60
|
subject << '# foo' << '# bar'
|
68
|
-
subject.outline.
|
61
|
+
expect(subject.outline.size).to eq(2)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should combine chapter outlines' do
|
65
|
+
subject << '# foo' << '# bar'
|
66
|
+
expect(subject.outline.first[0]).to eql('chapter-0-foo.html')
|
67
|
+
expect(subject.outline.first[1][0].text).to eql('foo')
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
72
71
|
describe '#has_cover?' do
|
73
72
|
it 'should not have a cover without a config key' do
|
74
|
-
|
73
|
+
is_expected.not_to have_cover
|
75
74
|
end
|
76
75
|
|
77
76
|
it 'should not have a cover with a config key that is false' do
|
78
|
-
|
77
|
+
expect(context).to receive(:config).and_return(OpenStruct.new({ 'cover_image' => false }))
|
78
|
+
is_expected.not_to have_cover
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should have a cover with a config key' do
|
82
|
-
|
82
|
+
expect(context).to receive(:config).and_return(OpenStruct.new({ 'cover_image' => true }))
|
83
|
+
is_expected.to have_cover
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
86
87
|
describe '#has_toc?' do
|
87
88
|
it 'should not have a toc without a config key' do
|
88
|
-
|
89
|
+
expect(context).to receive(:config).and_return(OpenStruct.new)
|
90
|
+
is_expected.not_to have_toc
|
89
91
|
end
|
90
92
|
|
91
93
|
it 'should not have a toc with a config key that is false' do
|
92
|
-
|
94
|
+
expect(context).to receive(:config).and_return(OpenStruct.new({ 'toc' => false }))
|
95
|
+
is_expected.not_to have_toc
|
93
96
|
end
|
94
97
|
|
95
98
|
it 'should have a toc with a config key' do
|
96
|
-
|
99
|
+
expect(context).to receive(:config).and_return(OpenStruct.new({ 'toc' => true }))
|
100
|
+
is_expected.to have_toc
|
97
101
|
end
|
98
102
|
end
|
99
103
|
|
100
104
|
describe '#images' do
|
101
105
|
before { subject << '![foo](bar)' << '![baz](qux)' << '![bla](qux)' }
|
102
|
-
it { should have(2).images }
|
103
|
-
its(:images) { should include('bar') }
|
104
|
-
its(:images) { should include('qux') }
|
105
|
-
end
|
106
106
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
subject.
|
107
|
+
it 'has 2 images' do
|
108
|
+
expect(subject.images.size).to eq(2)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'has includes each unique image' do
|
112
|
+
expect(subject.images).to include('bar', 'qux')
|
113
113
|
end
|
114
114
|
end
|
115
115
|
end
|