kitabu 2.1.0 → 3.0.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.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +61 -0
- data/.rubocop.yml +17 -0
- data/CHANGELOG.md +13 -2
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +2 -0
- data/LICENSE.md +20 -0
- data/README.md +103 -88
- data/Rakefile +7 -0
- data/bin/kitabu +4 -0
- data/kitabu.gemspec +21 -15
- data/lib/kitabu/cli.rb +54 -39
- data/lib/kitabu/dependency.rb +11 -5
- data/lib/kitabu/errors.rb +2 -0
- data/lib/kitabu/exporter/base.rb +11 -11
- data/lib/kitabu/exporter/css.rb +6 -15
- data/lib/kitabu/exporter/epub.rb +23 -17
- data/lib/kitabu/exporter/html.rb +27 -21
- data/lib/kitabu/exporter/mobi.rb +7 -1
- data/lib/kitabu/exporter/pdf.rb +9 -3
- data/lib/kitabu/exporter.rb +15 -16
- data/lib/kitabu/extensions/rouge.rb +6 -1
- data/lib/kitabu/extensions/string.rb +5 -3
- data/lib/kitabu/footnotes/base.rb +2 -0
- data/lib/kitabu/footnotes/html.rb +18 -13
- data/lib/kitabu/footnotes/pdf.rb +17 -11
- data/lib/kitabu/generator.rb +13 -8
- data/lib/kitabu/helpers.rb +12 -9
- data/lib/kitabu/markdown.rb +12 -10
- data/lib/kitabu/source_list.rb +15 -12
- data/lib/kitabu/stats.rb +3 -1
- data/lib/kitabu/syntax/highlight.rb +4 -11
- data/lib/kitabu/toc/epub.rb +5 -2
- data/lib/kitabu/toc/html/stream.rb +3 -1
- data/lib/kitabu/toc/html.rb +12 -8
- data/lib/kitabu/version.rb +4 -2
- data/lib/kitabu.rb +8 -10
- data/spec/kitabu/cli/export_spec.rb +6 -4
- data/spec/kitabu/cli/new_spec.rb +6 -4
- data/spec/kitabu/cli/permalinks_spec.rb +4 -2
- data/spec/kitabu/cli/stats_spec.rb +19 -15
- data/spec/kitabu/cli/version_spec.rb +3 -1
- data/spec/kitabu/exporter/css_spec.rb +3 -1
- data/spec/kitabu/exporter/epub_spec.rb +2 -0
- data/spec/kitabu/exporter/html_spec.rb +11 -9
- data/spec/kitabu/exporter/mobi_spec.rb +5 -5
- data/spec/kitabu/exporter/pdf_spec.rb +8 -4
- data/spec/kitabu/extensions/string_spec.rb +14 -9
- data/spec/kitabu/footnotes/html_spec.rb +35 -33
- data/spec/kitabu/generator_spec.rb +3 -1
- data/spec/kitabu/markdown_spec.rb +8 -6
- data/spec/kitabu/source_list_spec.rb +8 -2
- data/spec/kitabu/stats_spec.rb +10 -6
- data/spec/kitabu/toc/html_spec.rb +37 -21
- data/spec/spec_helper.rb +23 -8
- data/spec/support/exit_with_code.rb +7 -5
- data/spec/support/have_tag.rb +44 -32
- data/spec/support/helper.rb +5 -3
- data/spec/support/mybook/code/code.rb +2 -0
- data/spec/support/mybook/config/helper.rb +2 -0
- data/spec/support/shared.rb +8 -6
- data/templates/Gemfile +5 -3
- data/templates/Guardfile +3 -1
- data/templates/helper.rb +8 -6
- data/templates/templates/styles/epub.css +1 -0
- data/templates/templates/styles/files/normalize.css +351 -0
- data/templates/templates/styles/{html.scss → html.css} +28 -26
- data/templates/templates/styles/{pdf.scss → pdf.css} +49 -47
- data/templates/templates/styles/print.css +2 -0
- data/templates/text/01_Getting_Started.md +27 -9
- data/templates/text/02_Creating_Chapters.md +9 -3
- data/templates/text/{03_Syntax_Highlighting.erb → 03_Syntax_Highlighting.md.erb} +12 -7
- data/templates/text/04_Dynamic_Content.md.erb +48 -0
- data/templates/text/05_Exporting_Files.md +17 -8
- metadata +40 -48
- data/.gitmodules +0 -3
- data/.travis.yml +0 -18
- data/lib/kitabu/exporter/txt.rb +0 -18
- data/spec/kitabu/exporter/txt_spec.rb +0 -14
- data/templates/ebook.png +0 -0
- data/templates/templates/styles/epub.scss +0 -1
- data/templates/templates/styles/files/_normalize.scss +0 -427
- data/templates/templates/styles/print.scss +0 -2
- data/templates/text/04_Dynamic_Content.erb +0 -64
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
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,54 +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(
|
|
32
|
-
let(:chapter2) { html.css(
|
|
33
|
+
let(:chapter1) { html.css(".chapter:first-of-type").first }
|
|
34
|
+
let(:chapter2) { html.css(".chapter:last-of-type").first }
|
|
33
35
|
|
|
34
|
-
it
|
|
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
|
|
40
|
-
html.css(
|
|
41
|
-
expect(footnote.get_attribute(
|
|
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
|
|
46
|
-
expect(chapter1).to have_tag(
|
|
47
|
-
expect(chapter2).to have_tag(
|
|
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)
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
it
|
|
51
|
-
expect(chapter1).to have_tag(
|
|
52
|
-
expect(chapter1).to have_tag(
|
|
53
|
-
expect(chapter1).to have_tag(
|
|
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)
|
|
54
56
|
|
|
55
|
-
expect(chapter2).to have_tag(
|
|
56
|
-
expect(chapter2).to have_tag(
|
|
57
|
-
expect(chapter2).to have_tag(
|
|
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)
|
|
58
60
|
end
|
|
59
61
|
|
|
60
|
-
it
|
|
61
|
-
expect(chapter1).to have_tag(
|
|
62
|
-
expect(chapter1).to have_tag(
|
|
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)
|
|
63
65
|
|
|
64
|
-
expect(chapter2).to have_tag(
|
|
65
|
-
expect(chapter2).to have_tag(
|
|
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)
|
|
66
68
|
end
|
|
67
69
|
|
|
68
|
-
it
|
|
69
|
-
expect(chapter1).to have_tag('.footnotes li:nth-child(1) a[
|
|
70
|
-
expect(chapter1).to have_tag('.footnotes li:nth-child(2) a[
|
|
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"]')
|
|
71
73
|
|
|
72
|
-
expect(chapter2).to have_tag('.footnotes li:nth-child(1) a[
|
|
73
|
-
expect(chapter2).to have_tag('.footnotes li:nth-child(2) a[
|
|
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"]')
|
|
74
76
|
end
|
|
75
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
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
2
4
|
|
|
3
5
|
describe Kitabu::Markdown do
|
|
4
|
-
it
|
|
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
|
|
17
|
+
it "enables options" do
|
|
16
18
|
html = Kitabu::Markdown.render <<-TEXT.strip_heredoc
|
|
17
19
|
```php?start_inline=true
|
|
18
20
|
echo 'Hello';
|
|
@@ -22,13 +24,13 @@ describe Kitabu::Markdown do
|
|
|
22
24
|
expect(html).to include('<span class="k">echo</span>')
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
it
|
|
26
|
-
expect
|
|
27
|
+
it "does not raise with unknown lexers" do
|
|
28
|
+
expect do
|
|
27
29
|
Kitabu::Markdown.render <<-TEXT.strip_heredoc
|
|
28
30
|
```terminal
|
|
29
31
|
Text plain.
|
|
30
32
|
```
|
|
31
33
|
TEXT
|
|
32
|
-
|
|
34
|
+
end.not_to raise_error
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
|
|
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)
|
|
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
|
data/spec/kitabu/stats_spec.rb
CHANGED
|
@@ -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)
|
|
25
|
-
|
|
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,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require "spec_helper"
|
|
3
4
|
|
|
4
5
|
describe Kitabu::TOC::HTML do
|
|
@@ -6,25 +7,31 @@ describe Kitabu::TOC::HTML do
|
|
|
6
7
|
/#{Regexp.escape(text)}/
|
|
7
8
|
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<h2>Item 2.1</h2>
|
|
18
|
-
<h2>Item 2.1 again</h2>
|
|
19
|
-
<h2>Internacionalização</h2>
|
|
20
|
-
HTML
|
|
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>
|
|
21
18
|
|
|
22
|
-
|
|
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
|
|
23
26
|
|
|
24
|
-
let(:toc) { described_class.generate(
|
|
27
|
+
let(:toc) { described_class.generate(input) }
|
|
25
28
|
let(:html) { toc.to_html }
|
|
26
29
|
let(:content) { toc.content }
|
|
27
30
|
|
|
31
|
+
it "returns hash" do
|
|
32
|
+
expect(toc.to_hash.keys).to eq(%i[content html toc])
|
|
33
|
+
end
|
|
34
|
+
|
|
28
35
|
it "has no body tag" do
|
|
29
36
|
expect(content).not_to match(/<body>/)
|
|
30
37
|
end
|
|
@@ -34,13 +41,17 @@ describe Kitabu::TOC::HTML do
|
|
|
34
41
|
expect(html).to have_tag("div.level2.item-1-2", regexp("Item 1.2"))
|
|
35
42
|
expect(html).to have_tag("div.level3.item-1-1-3", regexp("Item 1.1.3"))
|
|
36
43
|
expect(html).to have_tag("div.level4.item-1-1-1-4", regexp("Item 1.1.1.4"))
|
|
37
|
-
expect(html).to have_tag("div.level5.item-1-1-1-1-5",
|
|
38
|
-
|
|
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"))
|
|
39
48
|
|
|
40
49
|
expect(html).to have_tag("div.level2.item-2-1", regexp("Item 2.1"))
|
|
41
|
-
expect(html).to have_tag("div.level2.item-2-1-again",
|
|
50
|
+
expect(html).to have_tag("div.level2.item-2-1-again",
|
|
51
|
+
regexp("Item 2.1 again"))
|
|
42
52
|
|
|
43
|
-
expect(html).to have_tag("div.level2.internacionalizacao",
|
|
53
|
+
expect(html).to have_tag("div.level2.internacionalizacao",
|
|
54
|
+
regexp("Internacionalização"))
|
|
44
55
|
end
|
|
45
56
|
|
|
46
57
|
it "adds id attribute to content" do
|
|
@@ -49,11 +60,16 @@ describe Kitabu::TOC::HTML do
|
|
|
49
60
|
expect(content).to have_tag("h3#item-1-1-3", regexp("Item 1.1.3"))
|
|
50
61
|
expect(content).to have_tag("h4#item-1-1-1-4", regexp("Item 1.1.1.4"))
|
|
51
62
|
expect(content).to have_tag("h5#item-1-1-1-1-5", regexp("Item 1.1.1.1.5"))
|
|
52
|
-
expect(content).to have_tag("h6#item-1-1-1-1-1-6",
|
|
63
|
+
expect(content).to have_tag("h6#item-1-1-1-1-1-6",
|
|
64
|
+
regexp("Item 1.1.1.1.1.6"))
|
|
53
65
|
|
|
54
66
|
expect(content).to have_tag("h2#item-2-1", regexp("Item 2.1"))
|
|
55
67
|
expect(content).to have_tag("h2#item-2-1-again", regexp("Item 2.1 again"))
|
|
56
68
|
|
|
57
|
-
expect(content).to have_tag("h2#internacionalizacao",
|
|
69
|
+
expect(content).to have_tag("h2#internacionalizacao",
|
|
70
|
+
regexp("Internacionalização"))
|
|
71
|
+
|
|
72
|
+
expect(content).to have_tag("h2#title", regexp("Title"))
|
|
73
|
+
expect(content).to have_tag("h2#title-2", regexp("Title"))
|
|
58
74
|
end
|
|
59
75
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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__)
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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(
|
|
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 =>
|
|
8
|
-
actual =
|
|
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 |
|
|
16
|
+
failure_message do |_block|
|
|
15
17
|
"expected block to call exit(#{code}) but exit" +
|
|
16
|
-
|
|
18
|
+
(actual ? "(#{actual}) was called" : " not called")
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
failure_message_when_negated do |
|
|
21
|
+
failure_message_when_negated do |_block|
|
|
20
22
|
"expected block not to call exit(#{code})"
|
|
21
23
|
end
|
|
22
24
|
|
data/spec/support/have_tag.rb
CHANGED
|
@@ -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 = {}
|
|
15
|
+
def initialize(type, selector, options = {})
|
|
14
16
|
@selector = selector
|
|
15
17
|
@type = type
|
|
16
18
|
|
|
17
|
-
case options
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
|
92
|
-
return false
|
|
93
|
-
return false
|
|
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
|
-
|
|
103
|
-
|
|
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 << (
|
|
122
|
+
phrase << (
|
|
123
|
+
options[:text] ? " with inner text #{options[:text].inspect}" : ""
|
|
124
|
+
)
|
|
113
125
|
end
|
|
114
126
|
end
|
|
115
127
|
end
|
data/spec/support/helper.rb
CHANGED
|
@@ -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
|
|
15
|
+
eval "$#{stream} = #{stream.upcase}" # rubocop:disable Security/Eval, Style/EvalWithLocation
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
result
|
data/spec/support/shared.rb
CHANGED
|
@@ -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
|
|
|
@@ -32,8 +34,8 @@ shared_examples_for "e-book" do
|
|
|
32
34
|
it "copies sample texts" do
|
|
33
35
|
expect(mybook.join("text/01_Getting_Started.md")).to be_file
|
|
34
36
|
expect(mybook.join("text/02_Creating_Chapters.md")).to be_file
|
|
35
|
-
expect(mybook.join("text/03_Syntax_Highlighting.erb")).to be_file
|
|
36
|
-
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
|
|
37
39
|
expect(mybook.join("text/05_Exporting_Files.md")).to be_file
|
|
38
40
|
end
|
|
39
41
|
|
|
@@ -43,10 +45,10 @@ shared_examples_for "e-book" do
|
|
|
43
45
|
|
|
44
46
|
it "copies stylesheets" do
|
|
45
47
|
expect(mybook.join("templates/styles")).to be_directory
|
|
46
|
-
expect(mybook.join("templates/styles/epub.
|
|
47
|
-
expect(mybook.join("templates/styles/print.
|
|
48
|
-
expect(mybook.join("templates/styles/pdf.
|
|
49
|
-
expect(mybook.join("templates/styles/html.
|
|
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
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
it "copies Gemfile" do
|
data/templates/Gemfile
CHANGED