kitabu 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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