rpub 0.1.0 → 0.2.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.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rpub (0.1.0)
4
+ rpub (0.2.0)
5
5
  builder
6
6
  kramdown
7
7
  rubyzip
@@ -20,6 +20,7 @@ GEM
20
20
  guard-rspec (0.7.0)
21
21
  guard (>= 0.10.0)
22
22
  kramdown (0.13.5)
23
+ nokogiri (1.5.2)
23
24
  rake (0.9.2.2)
24
25
  rb-fsevent (0.9.1)
25
26
  rspec (2.9.0)
@@ -44,6 +45,7 @@ DEPENDENCIES
44
45
  growl
45
46
  guard
46
47
  guard-rspec
48
+ nokogiri
47
49
  rake
48
50
  rb-fsevent
49
51
  rpub!
data/HISTORY.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # History
2
2
 
3
+ ## 0.2.0
4
+
5
+ * Prefixed book query methods with `has_?`
6
+ * Added generate command
7
+ * Use inline styles for preview file
8
+ * Allow font embedding
9
+ * Improved tests
10
+ * Remove mention of validate command
11
+
3
12
  ## 0.1.0
4
13
 
5
14
  * Initial gem release
data/README.md CHANGED
@@ -57,14 +57,6 @@ in a special configuration file called `config.yml`:
57
57
 
58
58
  This file is written in [YAML](http://yaml.org) and sets basic properties of your book project.
59
59
 
60
- To make sure the book you generated is _valid_ -- meaning it is likely that most
61
- readers out there will be able to read it -- you can use the special `validate`
62
- command:
63
-
64
- $ rpub validate
65
-
66
- rPub will report any errors it finds. No output means everything is alright.
67
-
68
60
  Since regenerating your ePub file and opening it in a suitable reader
69
61
  application is cumbersome, rPub can generate a simple preview document for you:
70
62
 
@@ -139,11 +131,17 @@ or `preview` commands, using the `-l` or `-s` options:
139
131
 
140
132
  $ rpub compile -l /tmp/my-layout.html
141
133
 
134
+ If you like the default layout or styles, but want to adapt them, you can copy
135
+ those files into your project using the `generate` subcommand:
136
+
137
+ $ rpub generate
138
+
142
139
  ### Command reference
143
140
 
144
141
  * `rpub compile` -- generate .epub file
145
142
  * `rpub package` -- create zip file with compiled book and other listed files
146
143
  * `rpub preview` -- generate preview HTML file
144
+ * `rpub generate` -- copy default layout.html, styles.css and config.yml
147
145
  * `rpub help` -- get help on subcommands
148
146
  * `rpub clean` -- remove generated files
149
147
 
@@ -20,6 +20,7 @@ require 'rpub/commands/clean'
20
20
  require 'rpub/commands/preview'
21
21
  require 'rpub/commands/package'
22
22
  require 'rpub/commands/help'
23
+ require 'rpub/commands/generate'
23
24
  require 'rpub/hash_delegation'
24
25
  require 'rpub/book'
25
26
  require 'rpub/chapter'
@@ -25,11 +25,16 @@ module Rpub
25
25
  chapters.each(&block)
26
26
  end
27
27
 
28
- def toc?
28
+ def has_fonts?
29
+ fonts = config.fetch('fonts') { [] }
30
+ fonts.respond_to?(:any?) && fonts.any?
31
+ end
32
+
33
+ def has_toc?
29
34
  !!config.fetch('toc') { false }
30
35
  end
31
36
 
32
- def cover?
37
+ def has_cover?
33
38
  !!config.fetch('cover_image') { false }
34
39
  end
35
40
 
@@ -20,11 +20,11 @@ module Rpub
20
20
 
21
21
  # @return [String] Unique identifier for this chapter.
22
22
  def uid
23
- @uid ||= Digest::SHA1.hexdigest([content, id.to_s, layout].join)
23
+ @uid ||= Digest::SHA1.hexdigest([content, xml_id.to_s, layout].join)
24
24
  end
25
25
 
26
26
  # @return [String] XML-friendly slug for this chapter based on its number.
27
- def id
27
+ def xml_id
28
28
  @id ||= "chapter-#{number}"
29
29
  end
30
30
 
@@ -35,7 +35,7 @@ module Rpub
35
35
 
36
36
  # @return [String] name for the file in the zip to use, based on the title
37
37
  def filename
38
- @filename ||= id.to_s + '-' + title.gsub(/[^\w\.]/i, '-').squeeze('-').downcase.chomp('-') + '.html'
38
+ @filename ||= xml_id.to_s + '-' + title.gsub(/[^\w\.]/i, '-').squeeze('-').downcase.chomp('-') + '.html'
39
39
  end
40
40
 
41
41
  # Ordered headers for this chapter, each header as an object responding
@@ -45,9 +45,9 @@ module Rpub
45
45
  def outline
46
46
  @outline ||= elements(:header).map do |element|
47
47
  OpenStruct.new({
48
- :level => element.options[:level],
49
- :text => element_text(element),
50
- :id => Kramdown::Converter::Html.send(:new, @document, { :auto_id_prefix => '' }).generate_id(element.options[:raw_text])
48
+ :level => element.options[:level],
49
+ :text => element_text(element),
50
+ :html_id => Kramdown::Converter::Html.send(:new, @document, { :auto_id_prefix => '' }).generate_id(element.options[:raw_text])
51
51
  })
52
52
  end
53
53
  end
@@ -0,0 +1,80 @@
1
+ module Rpub
2
+ module Commands
3
+ class Generate < Base
4
+ identifier 'generate'
5
+
6
+ def initialize(*args)
7
+ super
8
+ @all = true
9
+ end
10
+
11
+ def invoke
12
+ super
13
+
14
+ if (@styles.nil? && @all) || (!@styles.nil? && @styles)
15
+ write_file Rpub.support_file('styles.css')
16
+ end
17
+
18
+ if (@layout.nil? && @all) || (!@layout.nil? && @layout)
19
+ write_file Rpub.support_file('layout.html')
20
+ end
21
+
22
+ if (@config.nil? && @all) || (!@config.nil? && @config)
23
+ write_file Rpub.support_file('config.yml')
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def write_file(file)
30
+ output_file = File.basename(file)
31
+ if File.exist?(output_file)
32
+ warn "Not overriding #{output_file}"
33
+ return
34
+ end
35
+ File.open(output_file, 'w') do |f|
36
+ f.write File.read(file)
37
+ end
38
+ end
39
+
40
+ def parser
41
+ OptionParser.new do |opts|
42
+ opts.banner = <<-EOS
43
+ Usage: rpub generate [-slach]
44
+
45
+ Generate one or more standard files to get started with a new project. By
46
+ default an entire skeleton project is generated, but by passing the -s, -l, -c
47
+ options you can generate just a single file.
48
+
49
+ Options:
50
+ EOS
51
+ opts.separator ' '
52
+
53
+ opts.on '-s', '--[no-]styles', 'Generate default stylesheet' do |v|
54
+ @all = false if v
55
+ @styles = v
56
+ end
57
+
58
+ opts.on '-l', '--[no-]layout', 'Generate default HTML layout' do |v|
59
+ @all = false if v
60
+ @layout = v
61
+ end
62
+
63
+ opts.on '-c', '--[no-]config', 'Generate default configuration' do |v|
64
+ @all = false if v
65
+ @config = v
66
+ end
67
+
68
+ opts.separator ''
69
+ opts.separator 'Generic options:'
70
+ opts.separator ''
71
+
72
+ opts.on_tail '-h', '--help', 'Display this message' do
73
+ puts opts
74
+ exit
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -15,12 +15,17 @@ module Rpub
15
15
  return unless markdown_files.any?
16
16
  concatenation = markdown_files.join("\n")
17
17
  File.open(@filename, 'w') do |f|
18
- f.write Kramdown::Document.new(concatenation, KRAMDOWN_OPTIONS.merge(:template => layout)).to_html
18
+ f.write move_styles_inline(Kramdown::Document.new(concatenation, KRAMDOWN_OPTIONS.merge(:template => layout)).to_html)
19
19
  end
20
20
  end
21
21
 
22
22
  private
23
23
 
24
+ def move_styles_inline(html)
25
+ style_block = %Q{<style>\n#{File.read(styles)}\n</style>}
26
+ html.gsub %r{</head>}, style_block + "\n</head>"
27
+ end
28
+
24
29
  def parser
25
30
  OptionParser.new do |opts|
26
31
  opts.banner = <<-EOS
@@ -12,13 +12,16 @@ module Rpub
12
12
  target.compress_file 'OEBPS/content.opf', Content.new(book)
13
13
  target.compress_file 'OEBPS/toc.ncx', Toc.new(book)
14
14
  target.compress_file 'OEBPS/styles.css', styles
15
- if book.cover?
15
+ if book.has_cover?
16
16
  target.compress_file 'OEBPS/cover.html', Cover.new(book)
17
17
  target.compress_file File.join('OEBPS', book.cover_image), File.read(book.cover_image)
18
18
  end
19
- if book.toc?
19
+ if book.has_toc?
20
20
  target.compress_file 'OEBPS/toc.html', toc { HtmlToc.new(book).render }
21
21
  end
22
+ book.fonts.each do |font|
23
+ target.compress_file File.join('OEBPS', font), File.read(font)
24
+ end
22
25
  book.each do |chapter|
23
26
  target.compress_file File.join('OEBPS', chapter.filename), chapter.to_html
24
27
  end
@@ -29,7 +29,7 @@ module Rpub
29
29
  xml.dc :rights, book.rights
30
30
  xml.dc :description, book.description
31
31
 
32
- if book.cover?
32
+ if book.has_cover?
33
33
  xml.meta :name => 'cover', :content => 'cover-image'
34
34
  end
35
35
  end
@@ -38,7 +38,13 @@ module Rpub
38
38
  xml.item 'id' => 'ncx', 'href' => 'toc.ncx', 'media-type' => 'application/x-dtbncx+xml'
39
39
  xml.item 'id' => 'css', 'href' => 'styles.css', 'media-type' => 'text/css'
40
40
 
41
- if book.cover?
41
+ if book.has_fonts?
42
+ book.fonts.each do |font|
43
+ xml.item 'id' => File.basename(font), 'href' => font, 'media-type' => 'font/opentype'
44
+ end
45
+ end
46
+
47
+ if book.has_cover?
42
48
  xml.item 'id' => 'cover', 'href' => 'cover.html', 'media-type' => 'application/xhtml+xml'
43
49
  xml.item 'id' => 'cover-image', 'href' => book.cover_image, 'media-type' => guess_media_type(book.cover_image)
44
50
  end
@@ -46,14 +52,18 @@ module Rpub
46
52
  book.images.each do |image|
47
53
  xml.item 'id' => File.basename(image), 'href' => image, 'media-type' => guess_media_type(image)
48
54
  end
49
- xml.item 'id' => 'toc', 'href' => 'toc.html', 'media-type' => 'application/xhtml+xml'
55
+
56
+ if book.has_toc?
57
+ xml.item 'id' => 'toc', 'href' => 'toc.html', 'media-type' => 'application/xhtml+xml'
58
+ end
59
+
50
60
  book.chapters.each do |chapter|
51
61
  xml.item 'id' => chapter.id, 'href' => chapter.filename, 'media-type' => 'application/xhtml+xml'
52
62
  end
53
63
  end
54
64
 
55
65
  xml.spine 'toc' => 'ncx' do
56
- if book.cover?
66
+ if book.has_cover?
57
67
  xml.itemref 'idref' => 'cover', 'linear' => 'no'
58
68
  end
59
69
  book.chapters.each do |chapter|
@@ -61,7 +71,7 @@ module Rpub
61
71
  end
62
72
  end
63
73
 
64
- if book.cover?
74
+ if book.has_cover?
65
75
  xml.guide do
66
76
  xml.reference :type => 'cover', :title => 'Cover', :href => 'cover.html'
67
77
  end
@@ -71,6 +81,7 @@ module Rpub
71
81
 
72
82
  private
73
83
 
84
+ # TODO refactor into separate guesser object
74
85
  def guess_media_type(filename)
75
86
  MEDIA_TYPES.fetch(filename[/\.(gif|png|jpe?g|svg)$/, 1]) { 'image/png' }
76
87
  end
@@ -9,12 +9,12 @@ module Rpub
9
9
  end
10
10
 
11
11
  def render
12
- xml.h1 'Table of Contents'
13
- xml.div :class => 'toc' do
14
- book.outline.each do |(filename, headings)|
15
- headings.each do |heading|
12
+ xml.div :id => 'toc' do
13
+ xml.h1 'Table of Contents'
14
+ xml.div :class => 'toc' do
15
+ book.outline.each do |(filename, heading)|
16
16
  xml.div :class => "level-#{heading.level}" do
17
- xml.a heading.text, :href => [filename, heading.id].join('#')
17
+ xml.a heading.text, :href => [filename, heading.html_id].join('#')
18
18
  end
19
19
  end
20
20
  end
@@ -13,14 +13,14 @@ module Rpub
13
13
  xml.declare! :DOCTYPE, :ncx, :PUBLIC, "-//W3C//DTD XHTML 1.1//EN", 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
14
14
  xml.ncx :xmlns => 'http://www.daisy.org/z3986/2005/ncx/', :version => '2005-1' do
15
15
  xml.head do
16
- xml.meta :name => 'dtb:uid', :content => @book.uid
16
+ xml.meta :name => 'dtb:uid', :content => book.uid
17
17
  xml.meta :name => 'dtb:depth', :content => '1'
18
18
  xml.meta :name => 'dtb:totalPageCount', :content => '0'
19
19
  xml.meta :name => 'dtb:maxPageNumber', :content => '0'
20
20
  end
21
- xml.docTitle { xml.text @book.title }
21
+ xml.docTitle { xml.text book.title }
22
22
  xml.navMap do
23
- @book.chapters.each_with_index do |chapter, n|
23
+ book.chapters.each_with_index do |chapter, n|
24
24
  xml.navPoint :id => chapter.id, :playOrder => n do
25
25
  xml.navLabel { xml.text chapter.title }
26
26
  xml.content :src => chapter.filename
@@ -1,3 +1,3 @@
1
1
  module Rpub
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -16,10 +16,9 @@ files into an eBook in ePub format. It provides several related functions to
16
16
  make working with ePub files a little easier:
17
17
 
18
18
  * Generation of table of contents
19
- * Tracking of references to tables or figures
20
- * Validation of output file
21
19
  * Packaging your eBook in an archive with additional README file
22
- * Very simple version control
20
+ * Embedding fonts
21
+ * Easy previewing as you write
23
22
  EOS
24
23
 
25
24
  # Files
@@ -42,6 +41,7 @@ EOS
42
41
  s.add_runtime_dependency 'rubyzip'
43
42
  s.add_runtime_dependency 'builder'
44
43
  s.add_development_dependency 'yard'
44
+ s.add_development_dependency 'nokogiri'
45
45
  s.add_development_dependency 'rspec'
46
46
  s.add_development_dependency 'rake'
47
47
  s.add_development_dependency 'guard'
@@ -34,6 +34,24 @@ describe Rpub::Book do
34
34
  end
35
35
  end
36
36
 
37
+ describe '#has_fonts?' do
38
+ it 'should not have a font without a config key' do
39
+ described_class.new(nil, {}).should_not have_fonts
40
+ end
41
+
42
+ it 'should not have a font with a config key that is false' do
43
+ described_class.new(nil, { 'fonts' => false }).should_not have_fonts
44
+ end
45
+
46
+ it 'should not have a font with a config key that is empty' do
47
+ described_class.new(nil, { 'fonts' => [] }).should_not have_fonts
48
+ end
49
+
50
+ it 'should have a font with a non-empty config key' do
51
+ described_class.new(nil, { 'fonts' => ['foo']}).should have_fonts
52
+ end
53
+ end
54
+
37
55
  describe '#uid' do
38
56
  it 'should change when chapters change' do
39
57
  Rpub::Book.new('bar').add_chapter('foo').should_not == subject.uid
@@ -44,6 +62,45 @@ describe Rpub::Book do
44
62
  end
45
63
  end
46
64
 
65
+ describe '#outline' do
66
+ it 'should return empty array when there are no chapters' do
67
+ subject.outline.should be_empty
68
+ end
69
+
70
+ it 'should return combination of all chapter outlines with filename' do
71
+ subject << '# foo' << '# bar'
72
+ subject.outline.should have(2).elements
73
+ end
74
+ end
75
+
76
+ describe '#has_cover?' do
77
+ it 'should not have a cover without a config key' do
78
+ described_class.new(nil, {}).should_not have_cover
79
+ end
80
+
81
+ it 'should not have a cover with a config key that is false' do
82
+ described_class.new(nil, { 'cover_image' => false }).should_not have_cover
83
+ end
84
+
85
+ it 'should have a cover with a config key' do
86
+ described_class.new(nil, { 'cover_image' => true}).should have_cover
87
+ end
88
+ end
89
+
90
+ describe '#has_toc?' do
91
+ it 'should not have a toc without a config key' do
92
+ described_class.new(nil, {}).should_not have_toc
93
+ end
94
+
95
+ it 'should not have a toc with a config key that is false' do
96
+ described_class.new(nil, { 'toc' => false }).should_not have_toc
97
+ end
98
+
99
+ it 'should have a toc with a config key' do
100
+ described_class.new(nil, { 'toc' => true }).should have_toc
101
+ end
102
+ end
103
+
47
104
  describe '#images' do
48
105
  before { subject << '![foo](bar)' << '![baz](qux)' << '![bla](qux)' }
49
106
  it { should have(2).images }
@@ -21,14 +21,34 @@ describe Rpub::Chapter do
21
21
  end
22
22
  end
23
23
 
24
- describe '#id' do
25
- its(:id) { should == 'chapter-1' }
24
+ describe '#xml_id' do
25
+ its(:xml_id) { should == 'chapter-1' }
26
26
  end
27
27
 
28
28
  describe '#filename' do
29
29
  its(:filename) { should == 'chapter-1-untitled.html' }
30
30
  end
31
31
 
32
+ describe '#outline' do
33
+ context 'when there are no headings' do
34
+ let(:subject) { described_class.new('foo', 1, 'document') }
35
+ its(:outline) { should have(0).elements }
36
+ its(:outline) { should be_empty }
37
+ end
38
+
39
+ context 'when there are headings' do
40
+ let(:subject) { described_class.new('# foo', 1, 'document') }
41
+ its(:outline) { should have(1).elements }
42
+
43
+ context 'a single heading entry' do
44
+ let(:subject) { described_class.new('# foo', 1, 'document').outline.first }
45
+ its(:level) { should == 1 }
46
+ its(:text) { should == 'foo' }
47
+ its(:html_id) { should == 'foo' }
48
+ end
49
+ end
50
+ end
51
+
32
52
  describe '#title' do
33
53
  context 'without a suitable markdown title' do
34
54
  its(:title) { should == 'untitled' }
@@ -18,6 +18,7 @@ describe Rpub::Commands::Preview do
18
18
  it { should include('<p>bar</p>') }
19
19
  it { should match(/foo.*bar/m) }
20
20
  it { should match(/<head>/) }
21
+ it { should match(/<style>/) }
21
22
  end
22
23
 
23
24
  it 'should create new preview file' do
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Epub::Container do
4
+ let(:subject) { described_class.new.render }
5
+ it { should have_xpath('/xmlns:container') }
6
+ it { should have_xpath('/xmlns:container[@version="1.0"]') }
7
+ it { should have_xpath('/xmlns:container/xmlns:rootfiles/xmlns:rootfile[@media-type="application/oebps-package+xml"]') }
8
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Epub::Content do
4
+ let(:book) do
5
+ double('book', {
6
+ :creator => 'anonymous',
7
+ :title => 'title',
8
+ :language => 'en',
9
+ :publisher => 'none',
10
+ :description => 'foo bar',
11
+ :subject => 'baz qux',
12
+ :rights => 'copyright',
13
+ :uid => 'abcd',
14
+ :has_cover? => false,
15
+ :has_fonts? => false,
16
+ :has_toc? => false,
17
+ :images => [],
18
+ :chapters => []
19
+ })
20
+ end
21
+ let(:subject) { described_class.new(book).render }
22
+
23
+ def self.it_should_have_metadata(name, value, options = {})
24
+ attr = options.inject('') do |str, (k, v)|
25
+ str << "[@#{k}=\"#{v}\"]"
26
+ end
27
+ it { should have_xpath(%Q{/xmlns:package/xmlns:metadata/dc:#{name}[text()="#{value}"]#{attr}}, 'dc' => 'http://purl.org/dc/elements/1.1/', 'xmlns' => 'http://www.idpf.org/2007/opf') }
28
+ end
29
+
30
+ context 'with an empty book' do
31
+
32
+ it { should have_xpath('/xmlns:package[@unique-identifier="BookId"][@version="2.0"]') }
33
+ it { should have_xpath('/xmlns:package[@unique-identifier="BookId"][@version="2.0"]') }
34
+
35
+ it_should_have_metadata 'title', "title"
36
+ it_should_have_metadata 'creator', "anonymous", 'xmlns:role' => 'aut'
37
+ it_should_have_metadata 'publisher', "none"
38
+ it_should_have_metadata 'subject', "baz qux"
39
+ it_should_have_metadata 'identifier', "abcd", :id => 'BookId'
40
+ it_should_have_metadata 'rights', "copyright"
41
+ it_should_have_metadata 'description', "foo bar"
42
+ end
43
+
44
+ context 'when the book has a cover' do
45
+ before { book.stub! :has_cover? => true, :cover_image => 'foo.jpg' }
46
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="cover"][@href="cover.html"][@media-type="application/xhtml+xml"]') }
47
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="cover-image"][@href="foo.jpg"][@media-type="image/jpeg"]') }
48
+ it { should have_xpath('/xmlns:package/xmlns:metadata/xmlns:meta[@name="cover"][@content="cover-image"]') }
49
+ it { should have_xpath('/xmlns:package/xmlns:guide/xmlns:reference[@type="cover"][@title="Cover"][@href="cover.html"]') }
50
+ it { should have_xpath('/xmlns:package/xmlns:spine[@toc="ncx"]/xmlns:itemref[@idref="cover"][@linear="no"]') }
51
+ end
52
+
53
+ context 'when the book has embedded fonts' do
54
+ before { book.stub! :has_fonts? => true, :fonts => ['font.otf'] }
55
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="font.otf"][@href="font.otf"][@media-type="font/opentype"]') }
56
+ end
57
+
58
+ context 'when the book has a ToC' do
59
+ before { book.stub! :has_toc? => true }
60
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="toc"][@href="toc.html"][@media-type="application/xhtml+xml"]') }
61
+ end
62
+
63
+ context 'when the book has images' do
64
+ before { book.stub! :images => ['foo.png', 'bar.gif'] }
65
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="foo.png"][@href="foo.png"][@media-type="image/png"]') }
66
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="bar.gif"][@href="bar.gif"][@media-type="image/gif"]') }
67
+ end
68
+
69
+ context 'when the book has chapters' do
70
+ let(:chapter) { double('chapter', :filename => 'chapter.html', :id => 'chapter1') }
71
+ before { book.stub! :chapters => [chapter] }
72
+ it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="chapter1"][@href="chapter.html"][@media-type="application/xhtml+xml"]') }
73
+ it { should have_xpath('/xmlns:package/xmlns:spine[@toc="ncx"]/xmlns:itemref[@idref="chapter1"]') }
74
+ end
75
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Epub::Cover do
4
+ let(:book) { double('book', :cover_image => 'cover.jpg', :title => 'title') }
5
+ let(:subject) { described_class.new(book).render }
6
+
7
+ it { should have_xpath('/xmlns:html/xmlns:head/xmlns:title[text()="Cover"]') }
8
+ it { should have_xpath('/xmlns:html/xmlns:body/xmlns:div/xmlns:img[@src="cover.jpg"][@alt="title"]') }
9
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Epub::HtmlToc do
4
+ let(:outline) { [] }
5
+ let(:book) { double('book', :outline => outline) }
6
+ let(:subject) { described_class.new(book).render }
7
+
8
+ it { should have_xpath('/div/h1[text()="Table of Contents"]') }
9
+ it { should have_xpath('/div/div[@class="toc"]') }
10
+
11
+ context 'without headings in the outline' do
12
+ it { should_not have_xpath('//a') }
13
+ end
14
+
15
+ context 'with heading in the outline' do
16
+ let(:outline) { [['foo.html', double('heading', :text => 'link', :html_id => 'bar', :level => 1)]] }
17
+ it { should have_xpath('/div/div/div[@class="level-1"]/a[@href="foo.html#bar"][text()="link"]') }
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Epub::Toc do
4
+ let(:chapters) { [] }
5
+ let(:book) { double('book', :uid => 'foo', :title => 'title', :chapters => chapters) }
6
+ let(:subject) { described_class.new(book).render }
7
+
8
+ it { should have_xpath('/xmlns:ncx') }
9
+ it { should have_xpath('/xmlns:ncx/xmlns:head/xmlns:meta[@name="dtb:uid"][@content="foo"]') }
10
+ it { should have_xpath('/xmlns:ncx/xmlns:head/xmlns:meta[@name="dtb:depth"][@content="1"]') }
11
+ it { should have_xpath('/xmlns:ncx/xmlns:head/xmlns:meta[@name="dtb:totalPageCount"][@content="0"]') }
12
+ it { should have_xpath('/xmlns:ncx/xmlns:head/xmlns:meta[@name="dtb:maxPageNumber"][@content="0"]') }
13
+ it { should have_xpath('/xmlns:ncx/xmlns:docTitle/xmlns:text[text()="title"]') }
14
+
15
+ context 'without chapters' do
16
+ it { should_not have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint') }
17
+ end
18
+
19
+ context 'with chapters' do
20
+ let(:chapters) { [double('chapter', :title => 'chapter title', :filename => 'filename', :id => 'id')] }
21
+ it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint[@id="id"]') }
22
+ it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint/xmlns:navLabel/xmlns:text[text()="chapter title"]') }
23
+ it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint/xmlns:content[@src="filename"]') }
24
+ end
25
+ end
@@ -1,4 +1,5 @@
1
1
  require 'rpub'
2
+ require 'nokogiri'
2
3
 
3
4
  FIXTURES_DIRECTORY = File.expand_path('../fixtures', __FILE__)
4
5
 
@@ -19,3 +20,9 @@ RSpec::Matchers.define :create_file do |filename|
19
20
  !before && after
20
21
  end
21
22
  end
23
+
24
+ RSpec::Matchers.define :have_xpath do |xpath, *args|
25
+ match do |xml|
26
+ Nokogiri::XML(xml).xpath(xpath, *args).any?
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: 'Untitled book'
3
+ description: 'No description'
4
+ creator: 'Anonymous'
5
+ publisher: 'Untitled publisher'
6
+ subject: 'General'
7
+ language: 'en'
8
+ rights: 'public comain'
9
+ version: '0.0.0'
10
+ toc: true
11
+ ignore:
12
+ - README.md
13
+ package:
14
+ - README.md
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.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: 2012-04-19 00:00:00.000000000 Z
12
+ date: 2012-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: typogruby
@@ -91,6 +91,22 @@ dependencies:
91
91
  - - ! '>='
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: nokogiri
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
94
110
  - !ruby/object:Gem::Dependency
95
111
  name: rspec
96
112
  requirement: !ruby/object:Gem::Requirement
@@ -224,6 +240,7 @@ files:
224
240
  - lib/rpub/commands/base.rb
225
241
  - lib/rpub/commands/clean.rb
226
242
  - lib/rpub/commands/compile.rb
243
+ - lib/rpub/commands/generate.rb
227
244
  - lib/rpub/commands/help.rb
228
245
  - lib/rpub/commands/main.rb
229
246
  - lib/rpub/commands/package.rb
@@ -253,8 +270,14 @@ files:
253
270
  - spec/rpub/commands/clean_spec.rb
254
271
  - spec/rpub/commands/main_spec.rb
255
272
  - spec/rpub/commands/preview_spec.rb
273
+ - spec/rpub/epub/container_spec.rb
274
+ - spec/rpub/epub/content_spec.rb
275
+ - spec/rpub/epub/cover_spec.rb
276
+ - spec/rpub/epub/html_toc_spec.rb
277
+ - spec/rpub/epub/toc_spec.rb
256
278
  - spec/rpub_spec.rb
257
279
  - spec/spec_helper.rb
280
+ - support/config.yml
258
281
  - support/layout.html
259
282
  - support/styles.css
260
283
  homepage: http://avdgaag.github.com/rpub
@@ -272,7 +295,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
272
295
  version: '0'
273
296
  segments:
274
297
  - 0
275
- hash: 756011084715788975
298
+ hash: 976501169507100538
276
299
  required_rubygems_version: !ruby/object:Gem::Requirement
277
300
  none: false
278
301
  requirements:
@@ -281,7 +304,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
281
304
  version: '0'
282
305
  segments:
283
306
  - 0
284
- hash: 756011084715788975
307
+ hash: 976501169507100538
285
308
  requirements: []
286
309
  rubyforge_project:
287
310
  rubygems_version: 1.8.22
@@ -290,8 +313,8 @@ specification_version: 3
290
313
  summary: ! 'rPub is a command-line tool that generates a collection of plain text
291
314
  input files into an eBook in ePub format. It provides several related functions
292
315
  to make working with ePub files a little easier: * Generation of table of contents
293
- * Tracking of references to tables or figures * Validation of output file * Packaging
294
- your eBook in an archive with additional README file * Very simple version control'
316
+ * Packaging your eBook in an archive with additional README file * Embedding fonts
317
+ * Easy previewing as you write'
295
318
  test_files:
296
319
  - spec/fixtures/clean/config.yml
297
320
  - spec/fixtures/clean/example.epub
@@ -305,6 +328,11 @@ test_files:
305
328
  - spec/rpub/commands/clean_spec.rb
306
329
  - spec/rpub/commands/main_spec.rb
307
330
  - spec/rpub/commands/preview_spec.rb
331
+ - spec/rpub/epub/container_spec.rb
332
+ - spec/rpub/epub/content_spec.rb
333
+ - spec/rpub/epub/cover_spec.rb
334
+ - spec/rpub/epub/html_toc_spec.rb
335
+ - spec/rpub/epub/toc_spec.rb
308
336
  - spec/rpub_spec.rb
309
337
  - spec/spec_helper.rb
310
338
  has_rdoc: