kitabu 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +4 -0
  3. data/.github/FUNDING.yml +4 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  5. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
  8. data/.github/dependabot.yml +15 -0
  9. data/.github/workflows/ruby-tests.yml +61 -0
  10. data/.gitignore +1 -0
  11. data/.rubocop.yml +17 -0
  12. data/CHANGELOG.md +34 -1
  13. data/CODE_OF_CONDUCT.md +74 -0
  14. data/CONTRIBUTING.md +79 -0
  15. data/Gemfile +2 -0
  16. data/LICENSE.md +20 -0
  17. data/README.md +121 -85
  18. data/Rakefile +7 -0
  19. data/bin/kitabu +4 -0
  20. data/kitabu.gemspec +20 -14
  21. data/lib/kitabu/cli.rb +54 -39
  22. data/lib/kitabu/dependency.rb +11 -5
  23. data/lib/kitabu/errors.rb +2 -0
  24. data/lib/kitabu/exporter/base.rb +13 -11
  25. data/lib/kitabu/exporter/css.rb +6 -14
  26. data/lib/kitabu/exporter/epub.rb +24 -18
  27. data/lib/kitabu/exporter/html.rb +33 -20
  28. data/lib/kitabu/exporter/mobi.rb +7 -1
  29. data/lib/kitabu/exporter/pdf.rb +9 -3
  30. data/lib/kitabu/exporter.rb +15 -16
  31. data/lib/kitabu/extensions/rouge.rb +7 -1
  32. data/lib/kitabu/extensions/string.rb +5 -3
  33. data/lib/kitabu/footnotes/base.rb +2 -0
  34. data/lib/kitabu/footnotes/html.rb +19 -12
  35. data/lib/kitabu/footnotes/pdf.rb +17 -11
  36. data/lib/kitabu/generator.rb +16 -8
  37. data/lib/kitabu/helpers.rb +12 -9
  38. data/lib/kitabu/markdown.rb +12 -10
  39. data/lib/kitabu/source_list.rb +15 -12
  40. data/lib/kitabu/stats.rb +3 -1
  41. data/lib/kitabu/syntax/highlight.rb +4 -11
  42. data/lib/kitabu/toc/epub.rb +5 -2
  43. data/lib/kitabu/toc/html/stream.rb +33 -0
  44. data/lib/kitabu/toc/html.rb +19 -9
  45. data/lib/kitabu/version.rb +4 -2
  46. data/lib/kitabu.rb +11 -12
  47. data/spec/kitabu/cli/export_spec.rb +6 -4
  48. data/spec/kitabu/cli/new_spec.rb +6 -4
  49. data/spec/kitabu/cli/permalinks_spec.rb +4 -2
  50. data/spec/kitabu/cli/stats_spec.rb +19 -15
  51. data/spec/kitabu/cli/version_spec.rb +3 -1
  52. data/spec/kitabu/exporter/css_spec.rb +3 -1
  53. data/spec/kitabu/exporter/epub_spec.rb +2 -0
  54. data/spec/kitabu/exporter/html_spec.rb +17 -4
  55. data/spec/kitabu/exporter/mobi_spec.rb +5 -5
  56. data/spec/kitabu/exporter/pdf_spec.rb +8 -4
  57. data/spec/kitabu/extensions/string_spec.rb +14 -9
  58. data/spec/kitabu/footnotes/html_spec.rb +38 -28
  59. data/spec/kitabu/generator_spec.rb +3 -1
  60. data/spec/kitabu/markdown_spec.rb +15 -3
  61. data/spec/kitabu/source_list_spec.rb +8 -2
  62. data/spec/kitabu/stats_spec.rb +10 -6
  63. data/spec/kitabu/toc/html_spec.rb +55 -35
  64. data/spec/spec_helper.rb +23 -8
  65. data/spec/support/exit_with_code.rb +7 -5
  66. data/spec/support/have_tag.rb +44 -32
  67. data/spec/support/helper.rb +5 -3
  68. data/spec/support/mybook/code/code.rb +2 -0
  69. data/spec/support/mybook/config/helper.rb +2 -0
  70. data/spec/support/mybook/fonts/OpenSans-CondBold.ttf +0 -0
  71. data/spec/support/shared.rb +12 -6
  72. data/templates/Gemfile +5 -3
  73. data/templates/Guardfile +3 -1
  74. data/templates/helper.rb +8 -6
  75. data/templates/templates/styles/epub.css +1 -0
  76. data/templates/templates/styles/files/normalize.css +351 -0
  77. data/templates/templates/styles/{html.scss → html.css} +28 -26
  78. data/templates/templates/styles/{pdf.scss → pdf.css} +49 -47
  79. data/templates/templates/styles/print.css +2 -0
  80. data/templates/text/01_Getting_Started.md +27 -9
  81. data/templates/text/02_Creating_Chapters.md +9 -3
  82. data/templates/text/{03_Syntax_Highlighting.erb → 03_Syntax_Highlighting.md.erb} +12 -7
  83. data/templates/text/04_Dynamic_Content.md.erb +48 -0
  84. data/templates/text/05_Exporting_Files.md +17 -8
  85. metadata +42 -50
  86. data/.gitmodules +0 -3
  87. data/.travis.yml +0 -18
  88. data/Gemfile.lock +0 -108
  89. data/lib/kitabu/exporter/txt.rb +0 -18
  90. data/lib/kitabu/stream.rb +0 -27
  91. data/lib/kitabu/toc.rb +0 -6
  92. data/spec/kitabu/exporter/txt_spec.rb +0 -14
  93. data/templates/ebook.png +0 -0
  94. data/templates/templates/styles/epub.scss +0 -1
  95. data/templates/templates/styles/files/_normalize.scss +0 -427
  96. data/templates/templates/styles/print.scss +0 -2
  97. data/templates/text/04_Dynamic_Content.erb +0 -64
@@ -1,7 +1,9 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  describe Kitabu::Footnotes::HTML do
4
- let(:footnotes) {
6
+ let(:footnotes) do
5
7
  Kitabu::Markdown.render <<-MARKDOWN.strip_heredoc
6
8
  ohai[^1] and kthxbai[^2]
7
9
 
@@ -10,9 +12,9 @@ describe Kitabu::Footnotes::HTML do
10
12
  [^1]: Hello
11
13
  [^2]: OK, thanks. Bye!
12
14
  MARKDOWN
13
- }
15
+ end
14
16
 
15
- let(:content) {
17
+ let(:content) do
16
18
  <<-HTML.strip_heredoc
17
19
  <div class="chapter">
18
20
  #{footnotes}
@@ -22,46 +24,54 @@ describe Kitabu::Footnotes::HTML do
22
24
  #{footnotes}
23
25
  </div>
24
26
  HTML
25
- }
27
+ end
26
28
 
27
- let(:html) {
29
+ let(:html) do
28
30
  Kitabu::Footnotes::HTML.process(content).html
29
- }
31
+ end
30
32
 
31
- let(:chapter1) { html.css('.chapter:first-of-type').first }
32
- let(:chapter2) { html.css('.chapter:last-of-type').first }
33
+ let(:chapter1) { html.css(".chapter:first-of-type").first }
34
+ let(:chapter2) { html.css(".chapter:last-of-type").first }
33
35
 
34
- it 'sets starting index' do
36
+ it "sets starting index" do
35
37
  expect(chapter1).to have_tag('.footnotes ol[start="1"]')
36
38
  expect(chapter2).to have_tag('.footnotes ol[start="3"]')
37
39
  end
38
40
 
39
- it 'sets footnotes id' do
40
- html.css('.footnotes li').to_enum(:each).with_index(1) do |footnote, index|
41
- expect(footnote.get_attribute('id')).to eq("fn#{index}")
41
+ it "sets footnotes id" do
42
+ html.css(".footnotes li").to_enum(:each).with_index(1) do |footnote, index|
43
+ expect(footnote.get_attribute("id")).to eq("fn#{index}")
42
44
  end
43
45
  end
44
46
 
45
- it 'removes id from existing <sup>' do
46
- expect(chapter1).to have_tag('sup:not([id])', count: 1)
47
- expect(chapter2).to have_tag('sup:not([id])', count: 1)
47
+ it "removes id from existing <sup>" do
48
+ expect(chapter1).to have_tag("sup:not([id])", count: 1)
49
+ expect(chapter2).to have_tag("sup:not([id])", count: 1)
50
+ end
51
+
52
+ it "sets <sup> id" do
53
+ expect(chapter1).to have_tag("sup", count: 3)
54
+ expect(chapter1).to have_tag("sup[id=fnref1]", count: 1)
55
+ expect(chapter1).to have_tag("sup[id=fnref2]", count: 1)
56
+
57
+ expect(chapter2).to have_tag("sup", count: 3)
58
+ expect(chapter2).to have_tag("sup[id=fnref3]", count: 1)
59
+ expect(chapter2).to have_tag("sup[id=fnref4]", count: 1)
48
60
  end
49
61
 
50
- it 'sets <sup> id' do
51
- expect(chapter1).to have_tag('sup', count: 3)
52
- expect(chapter1).to have_tag('sup[id=fnref1]', count: 1)
53
- expect(chapter1).to have_tag('sup[id=fnref2]', count: 1)
62
+ it "updates link to footnote" do
63
+ expect(chapter1).to have_tag("sup:nth-child(1) > a", text: "1", count: 2)
64
+ expect(chapter1).to have_tag("sup:nth-child(2) > a", text: "2", count: 1)
54
65
 
55
- expect(chapter2).to have_tag('sup', count: 3)
56
- expect(chapter2).to have_tag('sup[id=fnref3]', count: 1)
57
- expect(chapter2).to have_tag('sup[id=fnref4]', count: 1)
66
+ expect(chapter2).to have_tag("sup:nth-child(1) > a", text: "3", count: 2)
67
+ expect(chapter2).to have_tag("sup:nth-child(2) > a", text: "4", count: 1)
58
68
  end
59
69
 
60
- it 'sets footnote link-back' do
61
- expect(chapter1).to have_tag('.footnotes li:nth-child(1) a[rev=footnote][href="#fnref1"]')
62
- expect(chapter1).to have_tag('.footnotes li:nth-child(2) a[rev=footnote][href="#fnref2"]')
70
+ it "sets footnote link-back" do
71
+ expect(chapter1).to have_tag('.footnotes li:nth-child(1) a[href="#fnref1"]')
72
+ expect(chapter1).to have_tag('.footnotes li:nth-child(2) a[href="#fnref2"]')
63
73
 
64
- expect(chapter2).to have_tag('.footnotes li:nth-child(1) a[rev=footnote][href="#fnref3"]')
65
- expect(chapter2).to have_tag('.footnotes li:nth-child(2) a[rev=footnote][href="#fnref4"]')
74
+ expect(chapter2).to have_tag('.footnotes li:nth-child(1) a[href="#fnref3"]')
75
+ expect(chapter2).to have_tag('.footnotes li:nth-child(2) a[href="#fnref4"]')
66
76
  end
67
77
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Kitabu::Generator do
4
6
  before do
5
7
  subject.destination_root = tmpdir.join("mybook")
6
- capture(:stdout){ subject.invoke_all }
8
+ capture(:stdout) { subject.invoke_all }
7
9
  end
8
10
 
9
11
  it_behaves_like "e-book"
@@ -1,7 +1,9 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  describe Kitabu::Markdown do
4
- it 'enables fenced code blocks' do
6
+ it "enables fenced code blocks" do
5
7
  html = Kitabu::Markdown.render <<-TEXT.strip_heredoc
6
8
  ```ruby
7
9
  class User
@@ -12,7 +14,7 @@ describe Kitabu::Markdown do
12
14
  expect(html).to include('<pre class="highlight ruby">')
13
15
  end
14
16
 
15
- it 'enables options' do
17
+ it "enables options" do
16
18
  html = Kitabu::Markdown.render <<-TEXT.strip_heredoc
17
19
  ```php?start_inline=true
18
20
  echo 'Hello';
@@ -21,4 +23,14 @@ describe Kitabu::Markdown do
21
23
 
22
24
  expect(html).to include('<span class="k">echo</span>')
23
25
  end
26
+
27
+ it "does not raise with unknown lexers" do
28
+ expect do
29
+ Kitabu::Markdown.render <<-TEXT.strip_heredoc
30
+ ```terminal
31
+ Text plain.
32
+ ```
33
+ TEXT
34
+ end.not_to raise_error
35
+ end
24
36
  end
@@ -1,11 +1,17 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  describe Kitabu::SourceList do
4
6
  let(:root) { SPECDIR.join("support/mybook") }
5
7
  let(:format) { Kitabu::Exporter::HTML.new(root) }
6
8
  let(:entries) { source_list.entries }
7
9
  let(:source) { root.join("text") }
8
- let(:relative) { entries.collect {|e| e.to_s.gsub(/^#{Regexp.escape(source.to_s)}\//, "")} }
10
+ let(:relative) do
11
+ entries.collect do |e|
12
+ e.to_s.gsub(%r{^#{Regexp.escape(source.to_s)}/}, "")
13
+ end
14
+ end
9
15
  subject(:source_list) { Kitabu::SourceList.new(root) }
10
16
 
11
17
  context "when filtering entries" do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Kitabu::Stats do
@@ -6,9 +8,9 @@ describe Kitabu::Stats do
6
8
  let(:content) { "" }
7
9
  subject(:stats) { Kitabu::Stats.new(root_dir) }
8
10
 
9
- before {
11
+ before do
10
12
  allow(stats).to receive_message_chain(:content).and_return(content)
11
- }
13
+ end
12
14
 
13
15
  context "getting content" do
14
16
  it "generates content" do
@@ -21,8 +23,10 @@ describe Kitabu::Stats do
21
23
  end
22
24
 
23
25
  it "returns content" do
24
- allow(Kitabu::Exporter::HTML).to receive_message_chain(:new).and_return(format)
25
- allow(format).to receive_message_chain(:content).and_return("some content")
26
+ allow(Kitabu::Exporter::HTML).to receive_message_chain(:new)
27
+ .and_return(format)
28
+ allow(format).to receive_message_chain(:content)
29
+ .and_return("some content")
26
30
 
27
31
  expect(Kitabu::Stats.new(root_dir).content).to eql("some content")
28
32
  end
@@ -49,13 +53,13 @@ describe Kitabu::Stats do
49
53
  end
50
54
 
51
55
  context "external links counting" do
52
- let(:content) {
56
+ let(:content) do
53
57
  <<-HTML
54
58
  <a href="http://example.org">example.org</a>
55
59
  <a href="http://subdomain.example.org">subdomain.example.org</a>
56
60
  <a href="#some-anchor">anchor</a>
57
61
  HTML
58
- }
62
+ end
59
63
 
60
64
  it { expect(stats.links).to eql(2) }
61
65
  end
@@ -1,55 +1,75 @@
1
- # -*- encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Kitabu::TOC::HTML do
5
- HTML = <<-HTML
6
- <h1>Item 1</h1>
7
- <h2>Item 1.2</h2>
8
- <h3>Item 1.1.3</h3>
9
- <h4>Item 1.1.1.4</h4>
10
- <h5>Item 1.1.1.1.5</h5>
11
- <h6>Item 1.1.1.1.1.6</h6>
12
-
13
- <h2>Item 2.1</h2>
14
- <h2>Item 2.1 again</h2>
15
- <h2>Internacionalização</h2>
16
- HTML
17
-
18
- HTML.force_encoding("utf-8")
19
-
20
- let(:toc) { described_class.generate(HTML) }
6
+ def regexp(text)
7
+ /#{Regexp.escape(text)}/
8
+ end
9
+
10
+ def input
11
+ (+<<-HTML).force_encoding("utf-8")
12
+ <h1>Item 1</h1>
13
+ <h2>Item 1.2</h2>
14
+ <h3>Item 1.1.3</h3>
15
+ <h4>Item 1.1.1.4</h4>
16
+ <h5>Item 1.1.1.1.5</h5>
17
+ <h6>Item 1.1.1.1.1.6</h6>
18
+
19
+ <h2>Item 2.1</h2>
20
+ <h2>Item 2.1 again</h2>
21
+ <h2>Internacionalização</h2>
22
+ <h2>Title</h2>
23
+ <h2>Title</h2>
24
+ HTML
25
+ end
26
+
27
+ let(:toc) { described_class.generate(input) }
21
28
  let(:html) { toc.to_html }
22
29
  let(:content) { toc.content }
23
30
 
31
+ it "returns hash" do
32
+ expect(toc.to_hash.keys).to eq(%i[content html toc])
33
+ end
34
+
24
35
  it "has no body tag" do
25
36
  expect(content).not_to match(/<body>/)
26
37
  end
27
38
 
28
39
  it "generates toc" do
29
- expect(html).to have_tag("div.level1.item-1", "Item 1")
30
- expect(html).to have_tag("div.level2.item-1-2", "Item 1.2")
31
- expect(html).to have_tag("div.level3.item-1-1-3", "Item 1.1.3")
32
- expect(html).to have_tag("div.level4.item-1-1-1-4", "Item 1.1.1.4")
33
- expect(html).to have_tag("div.level5.item-1-1-1-1-5", "Item 1.1.1.1.5")
34
- expect(html).to have_tag("div.level6.item-1-1-1-1-1-6", "Item 1.1.1.1.1.6")
40
+ expect(html).to have_tag("div.level1.item-1", regexp("Item 1"))
41
+ expect(html).to have_tag("div.level2.item-1-2", regexp("Item 1.2"))
42
+ expect(html).to have_tag("div.level3.item-1-1-3", regexp("Item 1.1.3"))
43
+ expect(html).to have_tag("div.level4.item-1-1-1-4", regexp("Item 1.1.1.4"))
44
+ expect(html).to have_tag("div.level5.item-1-1-1-1-5",
45
+ regexp("Item 1.1.1.1.5"))
46
+ expect(html).to have_tag("div.level6.item-1-1-1-1-1-6",
47
+ regexp("Item 1.1.1.1.1.6"))
35
48
 
36
- expect(html).to have_tag("div.level2.item-2-1", "Item 2.1")
37
- expect(html).to have_tag("div.level2.item-2-1-again", "Item 2.1 again")
49
+ expect(html).to have_tag("div.level2.item-2-1", regexp("Item 2.1"))
50
+ expect(html).to have_tag("div.level2.item-2-1-again",
51
+ regexp("Item 2.1 again"))
38
52
 
39
- expect(html).to have_tag("div.level2.internacionalizacao", "Internacionalização")
53
+ expect(html).to have_tag("div.level2.internacionalizacao",
54
+ regexp("Internacionalização"))
40
55
  end
41
56
 
42
57
  it "adds id attribute to content" do
43
- expect(content).to have_tag("h1#item-1", "Item 1")
44
- expect(content).to have_tag("h2#item-1-2", "Item 1.2")
45
- expect(content).to have_tag("h3#item-1-1-3", "Item 1.1.3")
46
- expect(content).to have_tag("h4#item-1-1-1-4", "Item 1.1.1.4")
47
- expect(content).to have_tag("h5#item-1-1-1-1-5", "Item 1.1.1.1.5")
48
- expect(content).to have_tag("h6#item-1-1-1-1-1-6", "Item 1.1.1.1.1.6")
58
+ expect(content).to have_tag("h1#item-1", regexp("Item 1"))
59
+ expect(content).to have_tag("h2#item-1-2", regexp("Item 1.2"))
60
+ expect(content).to have_tag("h3#item-1-1-3", regexp("Item 1.1.3"))
61
+ expect(content).to have_tag("h4#item-1-1-1-4", regexp("Item 1.1.1.4"))
62
+ expect(content).to have_tag("h5#item-1-1-1-1-5", regexp("Item 1.1.1.1.5"))
63
+ expect(content).to have_tag("h6#item-1-1-1-1-1-6",
64
+ regexp("Item 1.1.1.1.1.6"))
65
+
66
+ expect(content).to have_tag("h2#item-2-1", regexp("Item 2.1"))
67
+ expect(content).to have_tag("h2#item-2-1-again", regexp("Item 2.1 again"))
49
68
 
50
- expect(content).to have_tag("h2#item-2-1", "Item 2.1")
51
- expect(content).to have_tag("h2#item-2-1-again", "Item 2.1 again")
69
+ expect(content).to have_tag("h2#internacionalizacao",
70
+ regexp("Internacionalização"))
52
71
 
53
- expect(content).to have_tag("h2#internacionalizacao", "Internacionalização")
72
+ expect(content).to have_tag("h2#title", regexp("Title"))
73
+ expect(content).to have_tag("h2#title-2", regexp("Title"))
54
74
  end
55
75
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,9 @@
1
- require "codeclimate-test-reporter"
2
- CodeClimate::TestReporter.start
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov"
4
+ SimpleCov.start do
5
+ add_filter "spec"
6
+ end
3
7
 
4
8
  require "bundler/setup"
5
9
 
@@ -9,12 +13,24 @@ require "pathname"
9
13
  SPECDIR = Pathname.new(File.dirname(__FILE__))
10
14
  TMPDIR = SPECDIR.join("tmp")
11
15
 
12
- Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|r| require r}
16
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each {|r| require r }
17
+
18
+ p [
19
+ :filter_env,
20
+ {
21
+ calibre: Kitabu::Dependency.calibre?,
22
+ prince: Kitabu::Dependency.prince?,
23
+ macos: Kitabu::Dependency.macos?,
24
+ linux: Kitabu::Dependency.linux?
25
+ }
26
+ ]
13
27
 
14
28
  # Disable the bundle install command.
15
29
  # TODO: Figure out the best way of doing it so.
16
- class Kitabu::Generator < Thor::Group
17
- def bundle_install
30
+ module Kitabu
31
+ class Generator < Thor::Group
32
+ def bundle_install
33
+ end
18
34
  end
19
35
  end
20
36
 
@@ -23,8 +39,7 @@ RSpec.configure do |config|
23
39
  config.include(Matchers)
24
40
 
25
41
  config.filter_run_excluding(
26
- html2text: false,
27
- kindlegen: false,
42
+ calibre: false,
28
43
  prince: false,
29
44
  osx: false,
30
45
  linux: false
@@ -35,7 +50,7 @@ RSpec.configure do |config|
35
50
  FileUtils.rm_rf(i) if File.exist?(i)
36
51
  end
37
52
 
38
- Dir.chdir File.expand_path('../..', __FILE__)
53
+ Dir.chdir File.expand_path("..", __dir__)
39
54
  end
40
55
 
41
56
  config.before(&cleaner)
@@ -1,22 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec::Matchers.define :exit_with_code do |code|
2
4
  actual = nil
3
5
 
4
6
  match do |block|
5
7
  begin
6
8
  block.call
7
- rescue SystemExit => e
8
- actual = e.status
9
+ rescue SystemExit => error
10
+ actual = error.status
9
11
  end
10
12
 
11
13
  actual && actual == code
12
14
  end
13
15
 
14
- failure_message do |block|
16
+ failure_message do |_block|
15
17
  "expected block to call exit(#{code}) but exit" +
16
- (actual ? "(#{actual}) was called" : " not called")
18
+ (actual ? "(#{actual}) was called" : " not called")
17
19
  end
18
20
 
19
- failure_message_when_negated do |block|
21
+ failure_message_when_negated do |_block|
20
22
  "expected block not to call exit(#{code})"
21
23
  end
22
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Matchers
2
4
  def have_tag(selector, options = {}, &block)
3
5
  HaveTag.new(:html, selector, options, &block)
@@ -10,18 +12,18 @@ module Matchers
10
12
  class HaveTag
11
13
  attr_reader :options, :selector, :actual, :actual_count, :doc, :type
12
14
 
13
- def initialize(type, selector, options = {}, &block)
15
+ def initialize(type, selector, options = {})
14
16
  @selector = selector
15
17
  @type = type
16
18
 
17
- case options
18
- when Hash
19
- @options = options
20
- when Numeric
21
- @options = {:count => options}
22
- else
23
- @options = {:text => options}
24
- end
19
+ @options = case options
20
+ when Hash
21
+ options
22
+ when Numeric
23
+ {count: options}
24
+ else
25
+ {text: options}
26
+ end
25
27
  end
26
28
 
27
29
  def doc_for(input)
@@ -29,7 +31,7 @@ module Matchers
29
31
 
30
32
  if input.respond_to?(:body)
31
33
  engine.parse(input.body.to_s)
32
- elsif Nokogiri::XML::Element === input
34
+ elsif Nokogiri::XML::Element == input
33
35
  input
34
36
  else
35
37
  engine.parse(input.to_s)
@@ -43,12 +45,13 @@ module Matchers
43
45
  matches = doc.css(selector)
44
46
 
45
47
  return options[:count] == 0 if matches.empty?
48
+
46
49
  matches = filter_on_inner_text(matches) if options[:text]
47
50
  matches = filter_on_nested_expectations(matches, block) if block
48
51
 
49
52
  @actual_count = matches.size
50
53
 
51
- return false if not acceptable_count?(actual_count)
54
+ return false unless acceptable_count?(actual_count)
52
55
 
53
56
  !matches.empty?
54
57
  end
@@ -59,57 +62,66 @@ module Matchers
59
62
 
60
63
  def failure_message
61
64
  explanation = actual_count ? "but found #{actual_count}" : "but did not"
62
- "expected\n#{doc.to_s}\nto have #{failure_count_phrase} #{failure_selector_phrase}, #{explanation}"
65
+
66
+ "expected\n#{doc}\nto have #{failure_count_phrase} " \
67
+ "#{failure_selector_phrase}, #{explanation}"
63
68
  end
64
69
 
65
70
  def failure_message_when_negated
66
71
  explanation = actual_count ? "but found #{actual_count}" : "but did"
67
- "expected\n#{doc.to_s}\nnot to have #{failure_count_phrase} #{failure_selector_phrase}, #{explanation}"
72
+
73
+ "expected\n#{doc}\nnot to have " \
74
+ "#{failure_count_phrase} #{failure_selector_phrase}, #{explanation}"
68
75
  end
69
76
 
70
- private
71
- def filter_on_inner_text(elements)
77
+ private def filter_on_inner_text(elements)
72
78
  elements.select do |el|
73
79
  next(el.inner_text =~ options[:text]) if options[:text].is_a?(Regexp)
80
+
74
81
  el.inner_text == options[:text]
75
82
  end
76
83
  end
77
84
 
78
- def filter_on_nested_expectations(elements, block)
85
+ private def filter_on_nested_expectations(elements, block)
79
86
  elements.select do |el|
80
- begin
81
- block[el]
82
- rescue RSpec::Expectations::ExpectationNotMetError
83
- false
84
- else
85
- true
86
- end
87
+ block[el]
88
+ rescue RSpec::Expectations::ExpectationNotMetError
89
+ false
90
+ else
91
+ true
87
92
  end
88
93
  end
89
94
 
90
- def acceptable_count?(count)
91
- return false unless options[:count] === count if options[:count]
92
- return false unless count >= options[:minimum] if options[:minimum]
93
- return false unless count <= options[:maximum] if options[:maximum]
95
+ private def acceptable_count?(count)
96
+ return false if options[:count] && options[:count] != count
97
+ return false if options[:minimum] && count < options[:minimum]
98
+ return false if options[:maximum] && count > options[:maximum]
99
+
94
100
  true
95
101
  end
96
102
 
97
- def failure_count_phrase
103
+ private def failure_count_phrase
98
104
  if options[:count]
99
105
  "#{options[:count]} elements matching"
100
106
  elsif options[:minimum] || options[:maximum]
101
107
  count_explanations = []
102
- count_explanations << "at least #{options[:minimum]}" if options[:minimum]
103
- count_explanations << "at most #{options[:maximum]}" if options[:maximum]
108
+ if options[:minimum]
109
+ count_explanations << "at least #{options[:minimum]}"
110
+ end
111
+ if options[:maximum]
112
+ count_explanations << "at most #{options[:maximum]}"
113
+ end
104
114
  "#{count_explanations.join(' and ')} elements matching"
105
115
  else
106
116
  "an element matching"
107
117
  end
108
118
  end
109
119
 
110
- def failure_selector_phrase
120
+ private def failure_selector_phrase
111
121
  phrase = selector.inspect
112
- phrase << (options[:text] ? " with inner text #{options[:text].inspect}" : "")
122
+ phrase << (
123
+ options[:text] ? " with inner text #{options[:text].inspect}" : ""
124
+ )
113
125
  end
114
126
  end
115
127
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SpecHelper
2
4
  def tmpdir
3
5
  TMPDIR
@@ -6,11 +8,11 @@ module SpecHelper
6
8
  def capture(stream)
7
9
  begin
8
10
  stream = stream.to_s
9
- eval "$#{stream} = StringIO.new"
11
+ eval "$#{stream} = StringIO.new" # rubocop:disable Security/Eval, Style/EvalWithLocation
10
12
  yield
11
- result = eval("$#{stream}").string
13
+ result = eval("$#{stream}").string # rubocop:disable Security/Eval, Style/EvalWithLocation
12
14
  ensure
13
- eval("$#{stream} = #{stream.upcase}")
15
+ eval "$#{stream} = #{stream.upcase}" # rubocop:disable Security/Eval, Style/EvalWithLocation
14
16
  end
15
17
 
16
18
  result
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class HelloWorld
2
4
  # @begin: method
3
5
  def self.say
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  module Helpers
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for "e-book" do
2
4
  let(:mybook) { tmpdir.join("mybook") }
3
5
 
@@ -13,6 +15,10 @@ shared_examples_for "e-book" do
13
15
  expect(mybook.join("text")).to be_directory
14
16
  end
15
17
 
18
+ it "creates fonts directory" do
19
+ expect(mybook.join("fonts")).to be_directory
20
+ end
21
+
16
22
  it "creates template directory" do
17
23
  expect(mybook.join("templates")).to be_directory
18
24
  end
@@ -28,8 +34,8 @@ shared_examples_for "e-book" do
28
34
  it "copies sample texts" do
29
35
  expect(mybook.join("text/01_Getting_Started.md")).to be_file
30
36
  expect(mybook.join("text/02_Creating_Chapters.md")).to be_file
31
- expect(mybook.join("text/03_Syntax_Highlighting.erb")).to be_file
32
- expect(mybook.join("text/04_Dynamic_Content.erb")).to be_file
37
+ expect(mybook.join("text/03_Syntax_Highlighting.md.erb")).to be_file
38
+ expect(mybook.join("text/04_Dynamic_Content.md.erb")).to be_file
33
39
  expect(mybook.join("text/05_Exporting_Files.md")).to be_file
34
40
  end
35
41
 
@@ -39,10 +45,10 @@ shared_examples_for "e-book" do
39
45
 
40
46
  it "copies stylesheets" do
41
47
  expect(mybook.join("templates/styles")).to be_directory
42
- expect(mybook.join("templates/styles/epub.scss")).to be_file
43
- expect(mybook.join("templates/styles/print.scss")).to be_file
44
- expect(mybook.join("templates/styles/pdf.scss")).to be_file
45
- expect(mybook.join("templates/styles/html.scss")).to be_file
48
+ expect(mybook.join("templates/styles/epub.css")).to be_file
49
+ expect(mybook.join("templates/styles/print.css")).to be_file
50
+ expect(mybook.join("templates/styles/pdf.css")).to be_file
51
+ expect(mybook.join("templates/styles/html.css")).to be_file
46
52
  end
47
53
 
48
54
  it "copies Gemfile" do
data/templates/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
- source 'https://rubygems.org'
2
- gem 'kitabu'
3
- gem 'guard-shell'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gem "guard-shell"
5
+ gem "kitabu"
data/templates/Guardfile CHANGED
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  notification :off
2
4
  interactor :off
3
5
 
4
6
  guard :shell do
5
- watch %r[^(?!output)] do |m|
7
+ watch(/^(?!output)/) do |_m|
6
8
  `kitabu export`
7
9
  end
8
10
  end