rpub 0.4.0 → 0.5.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.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -1
  3. data/.rspec +0 -1
  4. data/.travis.yml +3 -4
  5. data/.yardopts +1 -0
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +70 -46
  8. data/Guardfile +6 -0
  9. data/HISTORY.md +10 -0
  10. data/README.md +1 -1
  11. data/Rakefile +7 -2
  12. data/bin/rpub +64 -1
  13. data/doc/.gitignore +8 -0
  14. data/doc/api/Rpub.html +339 -0
  15. data/doc/api/Rpub/Book.html +983 -0
  16. data/doc/api/Rpub/Chapter.html +737 -0
  17. data/doc/api/Rpub/Command.html +356 -0
  18. data/doc/api/Rpub/Commands.html +117 -0
  19. data/doc/api/Rpub/Commands/Clean.html +216 -0
  20. data/doc/api/Rpub/Commands/Compile.html +218 -0
  21. data/doc/api/Rpub/Commands/Generate.html +242 -0
  22. data/doc/api/Rpub/Commands/Package.html +230 -0
  23. data/doc/api/Rpub/Commands/Preview.html +216 -0
  24. data/doc/api/Rpub/Commands/Stats.html +226 -0
  25. data/doc/api/Rpub/Compressor.html +687 -0
  26. data/doc/api/Rpub/Context.html +553 -0
  27. data/doc/api/Rpub/Document.html +647 -0
  28. data/doc/api/Rpub/Document/OutlineElement.html +388 -0
  29. data/doc/api/Rpub/Epub.html +465 -0
  30. data/doc/api/Rpub/Epub/Container.html +224 -0
  31. data/doc/api/Rpub/Epub/Content.html +344 -0
  32. data/doc/api/Rpub/Epub/Cover.html +236 -0
  33. data/doc/api/Rpub/Epub/HtmlToc.html +240 -0
  34. data/doc/api/Rpub/Epub/Toc.html +244 -0
  35. data/doc/api/Rpub/FilesystemSource.html +544 -0
  36. data/doc/api/Rpub/HashDelegation.html +281 -0
  37. data/doc/api/Rpub/HashDelegation/ClassMethods.html +175 -0
  38. data/doc/api/Rpub/MediaType.html +192 -0
  39. data/doc/api/Rpub/Preview.html +464 -0
  40. data/doc/api/Rpub/XmlFile.html +457 -0
  41. data/doc/api/_index.html +405 -0
  42. data/doc/api/class_list.html +54 -0
  43. data/doc/api/css/common.css +1 -0
  44. data/doc/api/css/full_list.css +57 -0
  45. data/doc/api/css/style.css +339 -0
  46. data/doc/api/file.HISTORY.html +131 -0
  47. data/doc/api/file.LICENSE.html +92 -0
  48. data/doc/api/file.README.html +337 -0
  49. data/doc/api/file_list.html +62 -0
  50. data/doc/api/frames.html +26 -0
  51. data/doc/api/index.html +337 -0
  52. data/doc/api/js/app.js +219 -0
  53. data/doc/api/js/full_list.js +178 -0
  54. data/doc/api/js/jquery.js +4 -0
  55. data/doc/api/method_list.html +533 -0
  56. data/doc/api/top-level-namespace.html +112 -0
  57. data/doc/index.html +312 -0
  58. data/doc/javascripts/scale.fix.js +17 -0
  59. data/doc/params.json +1 -0
  60. data/doc/stylesheets/pygment_trac.css +69 -0
  61. data/doc/stylesheets/styles.css +255 -0
  62. data/features/clean.feature +31 -0
  63. data/features/compile.feature +49 -0
  64. data/features/embedded_assets.feature +51 -0
  65. data/features/generate.feature +63 -0
  66. data/features/layout.feature +41 -0
  67. data/features/package.feature +30 -0
  68. data/features/previews.feature +66 -0
  69. data/features/stats.feature +18 -0
  70. data/features/step_definitions/general_steps.rb +60 -0
  71. data/features/styles.feature +33 -0
  72. data/features/support/env.rb +7 -0
  73. data/features/table_of_contents.feature +35 -0
  74. data/lib/rpub.rb +28 -31
  75. data/lib/rpub/book.rb +9 -16
  76. data/lib/rpub/chapter.rb +4 -54
  77. data/lib/rpub/command.rb +32 -0
  78. data/lib/rpub/commands/clean.rb +4 -49
  79. data/lib/rpub/commands/compile.rb +4 -49
  80. data/lib/rpub/commands/generate.rb +10 -67
  81. data/lib/rpub/commands/package.rb +9 -37
  82. data/lib/rpub/commands/preview.rb +4 -54
  83. data/lib/rpub/commands/stats.rb +6 -10
  84. data/lib/rpub/compressor.rb +3 -3
  85. data/lib/rpub/context.rb +48 -0
  86. data/lib/rpub/document.rb +68 -0
  87. data/lib/rpub/epub.rb +8 -7
  88. data/lib/rpub/epub/content.rb +9 -30
  89. data/lib/rpub/epub/cover.rb +1 -8
  90. data/lib/rpub/epub/html_toc.rb +4 -9
  91. data/lib/rpub/epub/toc.rb +16 -13
  92. data/lib/rpub/filesystem_source.rb +47 -0
  93. data/lib/rpub/media_type.rb +16 -0
  94. data/lib/rpub/preview.rb +29 -0
  95. data/lib/rpub/version.rb +1 -1
  96. data/lib/rpub/xml_file.rb +4 -1
  97. data/rpub.gemspec +6 -7
  98. data/spec/rpub/book_spec.rb +45 -45
  99. data/spec/rpub/chapter_spec.rb +87 -22
  100. data/spec/rpub/epub/container_spec.rb +3 -5
  101. data/spec/rpub/epub/content_spec.rb +62 -41
  102. data/spec/rpub/epub/cover_spec.rb +3 -5
  103. data/spec/rpub/epub/html_toc_spec.rb +8 -8
  104. data/spec/rpub/epub/toc_spec.rb +20 -22
  105. data/spec/rpub_spec.rb +1 -3
  106. data/spec/spec_helper.rb +28 -0
  107. data/support/config.yml +1 -0
  108. data/support/styles.css +3 -3
  109. metadata +131 -120
  110. data/lib/rpub/commander.rb +0 -23
  111. data/lib/rpub/commands/base.rb +0 -33
  112. data/lib/rpub/commands/help.rb +0 -37
  113. data/lib/rpub/commands/main.rb +0 -45
  114. data/lib/rpub/compilation_helpers.rb +0 -73
  115. data/lib/rpub/subclass_tracker.rb +0 -53
  116. data/spec/rpub/commands/clean_spec.rb +0 -46
  117. data/spec/rpub/commands/generate_spec.rb +0 -52
  118. data/spec/rpub/commands/main_spec.rb +0 -26
  119. data/spec/rpub/commands/package_spec.rb +0 -33
  120. 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
@@ -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', Content.new(book)
13
- target.compress_file 'OEBPS/toc.ncx', Toc.new(book)
14
- target.compress_file 'OEBPS/styles.css', styles
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), File.read(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), File.read(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), File.read(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(File.read(book.layout)).result(binding)
40
+ ERB.new(read(book.layout)).result(binding)
40
41
  end
41
42
  end
42
43
  end
@@ -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
@@ -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
@@ -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
- xml.div :class => "level-#{heading.level}" do
18
- xml.a heading.text, :href => [filename, heading.html_id].join('#')
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
@@ -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 => @max_level
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
- @play_order += 1
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] <= @max_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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Rpub
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -3,8 +3,11 @@ module Rpub
3
3
  # @return [Builder::XmlMarkup]
4
4
  attr_reader :xml
5
5
 
6
- def initialize
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
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require './lib/rpub/version'
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 'typogruby'
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
 
@@ -1,115 +1,115 @@
1
- require 'spec_helper'
2
-
3
1
  describe Rpub::Book do
4
- let(:subject) { described_class.new('some_file', 'title' => 'My "Awesome" Title!', 'version' => '1.0.3') }
5
-
6
- it 'should start with an empty configuration' do
7
- described_class.new('some_file').config.should == {}
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
- before { subject.add_chapter 'foo' }
16
-
17
- it { should have(1).chapters }
8
+ it 'has 1 chapter' do
9
+ expect(subject.chapters.size).to eq(1)
10
+ end
18
11
 
19
- it { should be_kind_of(Enumerable) }
12
+ it { is_expected.to be_kind_of(Enumerable) }
20
13
 
21
- it 'should start with no chapters' do
22
- described_class.new('foo').should have(0).chapters
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.should have(3).chapters
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.should be_true
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
- described_class.new(nil, {}).should_not have_fonts
40
- end
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
- described_class.new(nil, nil, ['foo']).should have_fonts
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
- Rpub::Book.new('bar').add_chapter('foo').should_not == subject.uid
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
- Rpub::Book.new('bar', 'baz' => 'qux').should_not == subject.uid
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.should be_empty
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.should have(2).elements
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
- described_class.new(nil, {}).should_not have_cover
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
- described_class.new(nil, { 'cover_image' => false }).should_not have_cover
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
- described_class.new(nil, { 'cover_image' => true}).should have_cover
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
- described_class.new(nil, {}).should_not have_toc
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
- described_class.new(nil, { 'toc' => false }).should_not have_toc
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
- described_class.new(nil, { 'toc' => true }).should have_toc
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
- describe '#outline' do
108
- before { subject << '# foo' << '## bar' }
109
- its(:outline) { should have(2).elements }
110
- it 'should combine chapter outlines' do
111
- subject.outline.first[0].should == 'chapter-0-foo.html'
112
- subject.outline.first[1][0].text.should == 'foo'
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