rpub 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: