rpub 0.2.0 → 0.2.1

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/.gitignore CHANGED
@@ -6,3 +6,5 @@ bin/*
6
6
  .DS_Store
7
7
  *~
8
8
  pkg
9
+ coverage
10
+ _site
data/.yardopts CHANGED
@@ -1,5 +1,5 @@
1
1
  --no-private
2
- --title "rPub, a simple ePub generator library in Ruby"
2
+ --title "Rpub, a simple ePub generator library in Ruby"
3
3
  --readme README.md
4
4
  -
5
5
  HISTORY.md
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rpub (0.2.0)
4
+ rpub (0.2.1)
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
+ multi_json (1.3.2)
23
24
  nokogiri (1.5.2)
24
25
  rake (0.9.2.2)
25
26
  rb-fsevent (0.9.1)
@@ -33,6 +34,10 @@ GEM
33
34
  rspec-mocks (2.9.0)
34
35
  rubypants (0.2.0)
35
36
  rubyzip (0.9.7)
37
+ simplecov (0.6.2)
38
+ multi_json (~> 1.3)
39
+ simplecov-html (~> 0.5.3)
40
+ simplecov-html (0.5.3)
36
41
  thor (0.14.6)
37
42
  typogruby (1.0.15)
38
43
  rubypants
@@ -50,4 +55,5 @@ DEPENDENCIES
50
55
  rb-fsevent
51
56
  rpub!
52
57
  rspec
58
+ simplecov
53
59
  yard
data/HISTORY.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # History
2
2
 
3
+ ## 0.2.1
4
+
5
+ * Bugfix: allow multiple headings per chapters in outline
6
+ * Bugfix: use correct id method, renamed to xml_id
7
+ * Various documentation improvements
8
+ * Added MIT license
9
+ * Added code coverage reports (Ruby 1.9 only)
10
+ * Improved test suite
11
+
3
12
  ## 0.2.0
4
13
 
5
14
  * Prefixed book query methods with `has_?`
data/LICENSE CHANGED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2012 Arjan van der Gaag
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md CHANGED
@@ -1,21 +1,19 @@
1
- # rPub -- an ePub generator in Ruby [![Build Status](https://secure.travis-ci.org/avdgaag/rpub.png?branch=master)](http://travis-ci.org/avdgaag/rpub)
2
-
3
- **Note** this project is still in development and not yet ready for general use.
1
+ # Rpub -- an ePub generator in Ruby [![Build Status](https://secure.travis-ci.org/avdgaag/rpub.png?branch=master)](http://travis-ci.org/avdgaag/rpub)
4
2
 
5
3
  ## Introduction
6
4
 
7
- rPub is a command-line tool that generates a collection of plain text input
5
+ Rpub is a command-line tool that generates a collection of plain text input
8
6
  files into an eBook in ePub format. It provides several related functions to
9
7
  make working with ePub files a little easier:
10
8
 
11
9
  * Generation of table of contents
12
- * Tracking of references to tables or figures
13
- * Validation of output file
14
10
  * Packaging your eBook in an archive with additional README file
11
+ * Embedding fonts
12
+ * Easy previewing as you write
15
13
 
16
14
  ## Installation
17
15
 
18
- rPub is distributed as a Ruby gem, which should be installed on most Macs and
16
+ Rpub is distributed as a Ruby gem, which should be installed on most Macs and
19
17
  Linux systems. Once you have ensured you have a working installation of Ruby
20
18
  and Ruby gems, install the gem as follows from the command line:
21
19
 
@@ -33,7 +31,7 @@ along the lines of `rpub 1.0.0`.
33
31
  ### Basics
34
32
 
35
33
  ePubs are basically collections of HTML files, combined in a single archive
36
- according to a set of predefined rules. rPub generates these files for you from
34
+ according to a set of predefined rules. Rpub generates these files for you from
37
35
  simple text files written in [Markdown][], a very readable markup language created
38
36
  by [John Gruber][]. This very README file is an example of a Markdown document.
39
37
 
@@ -58,7 +56,7 @@ in a special configuration file called `config.yml`:
58
56
  This file is written in [YAML](http://yaml.org) and sets basic properties of your book project.
59
57
 
60
58
  Since regenerating your ePub file and opening it in a suitable reader
61
- application is cumbersome, rPub can generate a simple preview document for you:
59
+ application is cumbersome, Rpub can generate a simple preview document for you:
62
60
 
63
61
  $ rpub preview
64
62
 
@@ -149,6 +147,10 @@ those files into your project using the `generate` subcommand:
149
147
 
150
148
  See the [examples directory](https://github.com/avdgaag/rpub/example) for two example projects.
151
149
 
150
+ ### Documentation
151
+
152
+ See the inline [API docs](http://rubydoc.info/github/avdgaag/rpub/master/frames) for more information.
153
+
152
154
  ## Other
153
155
 
154
156
  ### Note on Patches/Pull Requests
@@ -44,6 +44,7 @@ module Rpub
44
44
  end
45
45
  end
46
46
 
47
+ # @return [String] full path to a file that was relative to the gem support directory
47
48
  def self.support_file(path)
48
49
  File.join(GEM_ROOT, 'support', path)
49
50
  end
@@ -1,4 +1,13 @@
1
1
  module Rpub
2
+ # The +Commander+ module is responsible for invoking `Command` objects. This is
3
+ # the internal part of the library that is used by the CLI.
4
+ #
5
+ # The +Commander+ takes a list of arguments, which would typically come from the CLI,
6
+ # and tries to look up a +Command+ class. If it cannot find anything, it will invoke
7
+ # the {Rpub::Commands::Main} command.
8
+ #
9
+ # @see Rpub::Commands::Base
10
+ # @see Rpub::Commands
2
11
  module Commander
3
12
  def invoke(args = [])
4
13
  subcommand, *options = args
@@ -29,7 +29,7 @@ module Rpub
29
29
  def write_file(file)
30
30
  output_file = File.basename(file)
31
31
  if File.exist?(output_file)
32
- warn "Not overriding #{output_file}"
32
+ puts "Not overriding #{output_file}"
33
33
  return
34
34
  end
35
35
  File.open(output_file, 'w') do |f|
@@ -1,23 +1,42 @@
1
1
  module Rpub
2
+ # Provide a set of helper methods that are used across various commands to
3
+ # simplify the compilation process. These methods mostly deal with loading files
4
+ # from the current project directory.
2
5
  module CompilationHelpers
6
+
7
+ # Factory method for {Rpub::Book} objects, loading every markdown file as a
8
+ # chapter.
9
+ #
10
+ # @see #markdown_files
11
+ # @return [Rpub::Book]
3
12
  def create_book
4
13
  book = Book.new(layout, config)
5
14
  markdown_files.each(&book.method(:<<))
6
15
  book
7
16
  end
8
17
 
18
+ # All chapter input files loaded into strings. This does not include any of
19
+ # the files listed in the +ignore+ configuration key.
20
+ #
21
+ # @return [Array<String>]
9
22
  def markdown_files
10
23
  @markdown_files ||= filter_exceptions(Dir['*.md']).sort.map(&File.method(:read))
11
24
  end
12
25
 
26
+ # @return [String] path to the current layout file (defaulting to built-in)
13
27
  def layout
14
28
  @layout ||= own_or_support_file('layout.html')
15
29
  end
16
30
 
31
+ # @return [String] path to the current stylesheet file (defaulting to built-in)
17
32
  def styles
18
33
  @styles ||= own_or_support_file('styles.css')
19
34
  end
20
35
 
36
+ # Load the contents of +config.yml+ into a +Hash+ object.
37
+ #
38
+ # @raise [NoConfiguration] when the config file cannot be found.
39
+ # @return [Hash] parsed configuration
21
40
  def config
22
41
  @config_file ||= begin
23
42
  raise NoConfiguration unless File.exist?('config.yml')
@@ -1,5 +1,5 @@
1
1
  module Rpub
2
- # Wrapper around a `ZipOutputStream` object provided by the `rubyzip` gem.
2
+ # Wrapper around a +ZipOutputStream+ object provided by the +rubyzip+ gem.
3
3
  # This writes string contents straight into a zip file, without first saving
4
4
  # them to disk.
5
5
  class Compressor
@@ -19,8 +19,10 @@ module Rpub
19
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)
22
+ if book.has_fonts?
23
+ book.fonts.each do |font|
24
+ target.compress_file File.join('OEBPS', font), File.read(font)
25
+ end
24
26
  end
25
27
  book.each do |chapter|
26
28
  target.compress_file File.join('OEBPS', chapter.filename), chapter.to_html
@@ -58,7 +58,7 @@ module Rpub
58
58
  end
59
59
 
60
60
  book.chapters.each do |chapter|
61
- xml.item 'id' => chapter.id, 'href' => chapter.filename, 'media-type' => 'application/xhtml+xml'
61
+ xml.item 'id' => chapter.xml_id, 'href' => chapter.filename, 'media-type' => 'application/xhtml+xml'
62
62
  end
63
63
  end
64
64
 
@@ -67,7 +67,7 @@ module Rpub
67
67
  xml.itemref 'idref' => 'cover', 'linear' => 'no'
68
68
  end
69
69
  book.chapters.each do |chapter|
70
- xml.itemref 'idref' => chapter.id
70
+ xml.itemref 'idref' => chapter.xml_id
71
71
  end
72
72
  end
73
73
 
@@ -12,9 +12,11 @@ module Rpub
12
12
  xml.div :id => 'toc' do
13
13
  xml.h1 'Table of Contents'
14
14
  xml.div :class => 'toc' do
15
- book.outline.each do |(filename, heading)|
16
- xml.div :class => "level-#{heading.level}" do
17
- xml.a heading.text, :href => [filename, heading.html_id].join('#')
15
+ book.outline.each do |(filename, headings)|
16
+ headings.each do |heading|
17
+ xml.div :class => "level-#{heading.level}" do
18
+ xml.a heading.text, :href => [filename, heading.html_id].join('#')
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -21,7 +21,7 @@ module Rpub
21
21
  xml.docTitle { xml.text book.title }
22
22
  xml.navMap do
23
23
  book.chapters.each_with_index do |chapter, n|
24
- xml.navPoint :id => chapter.id, :playOrder => n do
24
+ xml.navPoint :id => chapter.xml_id, :playOrder => n do
25
25
  xml.navLabel { xml.text chapter.title }
26
26
  xml.content :src => chapter.filename
27
27
  end
@@ -2,7 +2,7 @@ module Rpub
2
2
  # Add tracking of subclasses to an existing class by extending it with
3
3
  # SubclassTracker.
4
4
  #
5
- # This allows you to set an identifier in a subclass using the `identifier`
5
+ # This allows you to set an identifier in a subclass using the +identifier+
6
6
  # macro, and find subclasses based on that value.
7
7
  #
8
8
  # Example:
@@ -19,7 +19,7 @@ module Rpub
19
19
  # ParentClass.matching('bar') # => raises SubclassTracker::NoSuchSubclass
20
20
  #
21
21
  # Note that you don't HAVE to set an identifier. If you don't, your child
22
- # class will never be found by `#matching`.
22
+ # class will never be found by +#matching+.
23
23
  module SubclassTracker
24
24
  class NoSuchSubclass < StandardError
25
25
  def initialize(subcommand)
@@ -1,3 +1,3 @@
1
1
  module Rpub
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
@@ -1,11 +1,13 @@
1
1
  module Rpub
2
2
  class XmlFile
3
+ # @return [Builder::XmlMarkup]
3
4
  attr_reader :xml
4
5
 
5
6
  def initialize
6
7
  @xml = Builder::XmlMarkup.new :indent => 2
7
8
  end
8
9
 
10
+ # @return [String] render this file and output as string
9
11
  def to_s
10
12
  render
11
13
  xml.target!
@@ -48,5 +48,6 @@ EOS
48
48
  s.add_development_dependency 'guard-rspec'
49
49
  s.add_development_dependency 'rb-fsevent'
50
50
  s.add_development_dependency 'growl'
51
+ s.add_development_dependency 'simplecov'
51
52
  end
52
53
 
File without changes
@@ -0,0 +1 @@
1
+ test
@@ -0,0 +1,15 @@
1
+
2
+ ---
3
+ title: 'Untitled book'
4
+ description: 'No description'
5
+ creator: 'Anonymous'
6
+ publisher: 'Untitled publisher'
7
+ subject: 'General'
8
+ language: 'en'
9
+ rights: 'public comain'
10
+ version: '0.0.0'
11
+ ignore:
12
+ - README.md
13
+ package_file: package.zip
14
+ package:
15
+ - README.md
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Commands::Generate do
4
+ let(:buffer) { StringIO.new }
5
+ before do
6
+ Dir.chdir File.join(FIXTURES_DIRECTORY, 'generate')
7
+ end
8
+
9
+ after do
10
+ File.unlink 'styles.css' if File.exist?('styles.css')
11
+ File.unlink 'layout.html' if File.exist?('layout.html')
12
+ File.unlink 'config.yml' if File.exist?('config.yml')
13
+ end
14
+
15
+ context 'given a specific option' do
16
+ let(:subject) { described_class.new(['--config'], buffer) }
17
+
18
+ it 'should generate one file' do
19
+ expect(&subject.method(:invoke)).to create_file('config.yml')
20
+ end
21
+
22
+ it 'should not generate stylesheet' do
23
+ expect(&subject.method(:invoke)).to_not create_file('layout.html', 'styles.css')
24
+ end
25
+ end
26
+
27
+ context 'given a no option' do
28
+ let(:subject) { described_class.new(['--no-styles'], buffer) }
29
+
30
+ it 'should generate two files' do
31
+ expect(&subject.method(:invoke)).to create_file('layout.html', 'config.yml')
32
+ end
33
+
34
+ it 'should not generate stylesheet' do
35
+ expect(&subject.method(:invoke)).to_not create_file('styles.css')
36
+ end
37
+ end
38
+
39
+ context 'given no options' do
40
+ let(:subject) { described_class.new([], buffer) }
41
+
42
+ it 'should generate three files' do
43
+ expect(&subject.method(:invoke)).to create_file('styles.css', 'layout.html', 'config.yml')
44
+ end
45
+
46
+ it 'should not generate existing files' do
47
+ File.open('styles.css', 'w') { |f| f.write 'foo' }
48
+ expect(&subject.method(:invoke)).to_not change { File.read('styles.css') }
49
+ buffer.string.should include('Not overriding styles.css')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rpub::Commands::Package do
4
+ before do
5
+ Dir.chdir File.join(FIXTURES_DIRECTORY, 'package')
6
+ end
7
+
8
+ after do
9
+ File.unlink('package.zip') if File.exist?('package.zip')
10
+ File.unlink('untitled-book-0.0.0.epub') if File.exist?('untitled-book-0.0.0.epub')
11
+ end
12
+
13
+ it 'should generate an archive' do
14
+ expect(&subject.method(:invoke)).to create_file('package.zip')
15
+ end
16
+
17
+ context 'archive file' do
18
+ before { described_class.new.invoke }
19
+
20
+ let(:subject) do
21
+ [].tap do |files|
22
+ Zip::ZipInputStream.open('package.zip') do |io|
23
+ while entry = io.get_next_entry
24
+ files << entry.name
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ it { should include('README.md') }
31
+ it { should include('untitled-book-0.0.0.epub') }
32
+ end
33
+ end
@@ -67,7 +67,7 @@ describe Rpub::Epub::Content do
67
67
  end
68
68
 
69
69
  context 'when the book has chapters' do
70
- let(:chapter) { double('chapter', :filename => 'chapter.html', :id => 'chapter1') }
70
+ let(:chapter) { double('chapter', :filename => 'chapter.html', :xml_id => 'chapter1') }
71
71
  before { book.stub! :chapters => [chapter] }
72
72
  it { should have_xpath('/xmlns:package/xmlns:manifest/xmlns:item[@id="chapter1"][@href="chapter.html"][@media-type="application/xhtml+xml"]') }
73
73
  it { should have_xpath('/xmlns:package/xmlns:spine[@toc="ncx"]/xmlns:itemref[@idref="chapter1"]') }
@@ -13,7 +13,7 @@ describe Rpub::Epub::HtmlToc do
13
13
  end
14
14
 
15
15
  context 'with heading in the outline' do
16
- let(:outline) { [['foo.html', double('heading', :text => 'link', :html_id => 'bar', :level => 1)]] }
16
+ let(:outline) { [['foo.html', [double('heading', :text => 'link', :html_id => 'bar', :level => 1)]]] }
17
17
  it { should have_xpath('/div/div/div[@class="level-1"]/a[@href="foo.html#bar"][text()="link"]') }
18
18
  end
19
19
  end
@@ -17,7 +17,7 @@ describe Rpub::Epub::Toc do
17
17
  end
18
18
 
19
19
  context 'with chapters' do
20
- let(:chapters) { [double('chapter', :title => 'chapter title', :filename => 'filename', :id => 'id')] }
20
+ let(:chapters) { [double('chapter', :title => 'chapter title', :filename => 'filename', :xml_id => 'id')] }
21
21
  it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint[@id="id"]') }
22
22
  it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint/xmlns:navLabel/xmlns:text[text()="chapter title"]') }
23
23
  it { should have_xpath('/xmlns:ncx/xmlns:navMap/xmlns:navPoint/xmlns:content[@src="filename"]') }
@@ -1,3 +1,8 @@
1
+ if RUBY_VERSION >= '1.9'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
5
+
1
6
  require 'rpub'
2
7
  require 'nokogiri'
3
8
 
@@ -12,11 +17,11 @@ RSpec::Matchers.define :remove_file do |filename|
12
17
  end
13
18
  end
14
19
 
15
- RSpec::Matchers.define :create_file do |filename|
20
+ RSpec::Matchers.define :create_file do |*filenames|
16
21
  match do |block|
17
- before = File.exist?(filename)
22
+ before = filenames.all?(&File.method(:exist?))
18
23
  block.call
19
- after = File.exist?(filename)
24
+ after = filenames.all?(&File.method(:exist?))
20
25
  !before && after
21
26
  end
22
27
  end
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.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -203,6 +203,22 @@ dependencies:
203
203
  - - ! '>='
204
204
  - !ruby/object:Gem::Version
205
205
  version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: simplecov
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
206
222
  description: an ePub generation library in Ruby
207
223
  email: arjan@arjanvandergaag.nl
208
224
  executables:
@@ -261,14 +277,19 @@ files:
261
277
  - spec/fixtures/clean/config.yml
262
278
  - spec/fixtures/clean/example.epub
263
279
  - spec/fixtures/clean/preview.html
280
+ - spec/fixtures/generate/.gitkeep
264
281
  - spec/fixtures/no_files/config.yml
282
+ - spec/fixtures/package/README.md
283
+ - spec/fixtures/package/config.yml
265
284
  - spec/fixtures/preview/a.md
266
285
  - spec/fixtures/preview/b.md
267
286
  - spec/fixtures/preview/config.yml
268
287
  - spec/rpub/book_spec.rb
269
288
  - spec/rpub/chapter_spec.rb
270
289
  - spec/rpub/commands/clean_spec.rb
290
+ - spec/rpub/commands/generate_spec.rb
271
291
  - spec/rpub/commands/main_spec.rb
292
+ - spec/rpub/commands/package_spec.rb
272
293
  - spec/rpub/commands/preview_spec.rb
273
294
  - spec/rpub/epub/container_spec.rb
274
295
  - spec/rpub/epub/content_spec.rb
@@ -295,7 +316,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
295
316
  version: '0'
296
317
  segments:
297
318
  - 0
298
- hash: 976501169507100538
319
+ hash: -3544660265101418
299
320
  required_rubygems_version: !ruby/object:Gem::Requirement
300
321
  none: false
301
322
  requirements:
@@ -304,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
304
325
  version: '0'
305
326
  segments:
306
327
  - 0
307
- hash: 976501169507100538
328
+ hash: -3544660265101418
308
329
  requirements: []
309
330
  rubyforge_project:
310
331
  rubygems_version: 1.8.22
@@ -319,14 +340,19 @@ test_files:
319
340
  - spec/fixtures/clean/config.yml
320
341
  - spec/fixtures/clean/example.epub
321
342
  - spec/fixtures/clean/preview.html
343
+ - spec/fixtures/generate/.gitkeep
322
344
  - spec/fixtures/no_files/config.yml
345
+ - spec/fixtures/package/README.md
346
+ - spec/fixtures/package/config.yml
323
347
  - spec/fixtures/preview/a.md
324
348
  - spec/fixtures/preview/b.md
325
349
  - spec/fixtures/preview/config.yml
326
350
  - spec/rpub/book_spec.rb
327
351
  - spec/rpub/chapter_spec.rb
328
352
  - spec/rpub/commands/clean_spec.rb
353
+ - spec/rpub/commands/generate_spec.rb
329
354
  - spec/rpub/commands/main_spec.rb
355
+ - spec/rpub/commands/package_spec.rb
330
356
  - spec/rpub/commands/preview_spec.rb
331
357
  - spec/rpub/epub/container_spec.rb
332
358
  - spec/rpub/epub/content_spec.rb