kitabu 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +7 -5
  5. data/lib/kitabu.rb +12 -1
  6. data/lib/kitabu/cli.rb +1 -1
  7. data/lib/kitabu/exporter.rb +5 -5
  8. data/lib/kitabu/{parser.rb → exporter/base.rb} +9 -11
  9. data/lib/kitabu/exporter/css.rb +24 -0
  10. data/lib/kitabu/{parser → exporter}/epub.rb +2 -2
  11. data/lib/kitabu/exporter/html.rb +109 -0
  12. data/lib/kitabu/{parser → exporter}/mobi.rb +2 -2
  13. data/lib/kitabu/exporter/pdf.rb +43 -0
  14. data/lib/kitabu/{parser → exporter}/txt.rb +2 -2
  15. data/lib/kitabu/footnotes/base.rb +33 -0
  16. data/lib/kitabu/footnotes/html.rb +52 -0
  17. data/lib/kitabu/footnotes/pdf.rb +47 -0
  18. data/lib/kitabu/source_list.rb +73 -0
  19. data/lib/kitabu/stats.rb +1 -1
  20. data/lib/kitabu/stream.rb +1 -1
  21. data/lib/kitabu/toc/html.rb +6 -6
  22. data/lib/kitabu/version.rb +1 -1
  23. data/spec/kitabu/exporter/css_spec.rb +16 -0
  24. data/spec/kitabu/{parser → exporter}/epub_spec.rb +3 -3
  25. data/spec/kitabu/exporter/html_spec.rb +36 -0
  26. data/spec/kitabu/{parser → exporter}/mobi_spec.rb +3 -3
  27. data/spec/kitabu/{parser → exporter}/pdf_spec.rb +3 -3
  28. data/spec/kitabu/{parser → exporter}/txt_spec.rb +3 -3
  29. data/spec/kitabu/footnotes/html_spec.rb +67 -0
  30. data/spec/kitabu/{parser/html_spec.rb → source_list_spec.rb} +5 -34
  31. data/spec/kitabu/stats_spec.rb +7 -7
  32. data/templates/templates/styles/pdf.scss +1 -47
  33. data/templates/text/04_Dynamic_Content.erb +1 -1
  34. metadata +29 -54
  35. data/examples/kitabu/output/epub/images/.gitkeep +0 -0
  36. data/examples/kitabu/output/epub/images/kitabu-icon.png +0 -0
  37. data/examples/kitabu/output/epub/images/kitabu-icon.svg +0 -19
  38. data/examples/kitabu/output/epub/images/kitabu-word.png +0 -0
  39. data/examples/kitabu/output/epub/images/kitabu-word.svg +0 -14
  40. data/examples/kitabu/output/epub/images/kitabu.png +0 -0
  41. data/examples/kitabu/output/epub/images/kitabu.svg +0 -20
  42. data/examples/kitabu/output/epub/section_0.html +0 -266
  43. data/examples/kitabu/output/epub/section_1.html +0 -246
  44. data/examples/kitabu/output/epub/section_2.html +0 -520
  45. data/examples/kitabu/output/epub/section_3.html +0 -282
  46. data/examples/kitabu/output/epub/section_4.html +0 -276
  47. data/examples/kitabu/output/epub/styles/epub.css +0 -437
  48. data/examples/kitabu/output/epub/styles/html.css +0 -712
  49. data/examples/kitabu/output/epub/styles/pdf.css +0 -840
  50. data/examples/kitabu/output/epub/styles/print.css +0 -1278
  51. data/examples/kitabu/output/epub/toc.html +0 -37
  52. data/examples/kitabu/output/images/.gitkeep +0 -0
  53. data/examples/kitabu/output/images/kitabu-icon.png +0 -0
  54. data/examples/kitabu/output/images/kitabu-icon.svg +0 -19
  55. data/examples/kitabu/output/images/kitabu-word.png +0 -0
  56. data/examples/kitabu/output/images/kitabu-word.svg +0 -14
  57. data/examples/kitabu/output/images/kitabu.png +0 -0
  58. data/examples/kitabu/output/images/kitabu.svg +0 -20
  59. data/examples/kitabu/output/kitabu.epub +0 -0
  60. data/examples/kitabu/output/kitabu.html +0 -513
  61. data/examples/kitabu/output/kitabu.mobi +0 -0
  62. data/examples/kitabu/output/kitabu.pdf +0 -0
  63. data/examples/kitabu/output/kitabu.pdf.html +0 -729
  64. data/examples/kitabu/output/kitabu.print.html +0 -729
  65. data/examples/kitabu/output/kitabu.print.pdf +0 -0
  66. data/examples/kitabu/output/kitabu.txt +0 -440
  67. data/examples/kitabu/output/styles/epub.css +0 -437
  68. data/examples/kitabu/output/styles/html.css +0 -712
  69. data/examples/kitabu/output/styles/pdf.css +0 -840
  70. data/examples/kitabu/output/styles/print.css +0 -1278
  71. data/lib/kitabu/parser/html.rb +0 -208
  72. data/lib/kitabu/parser/pdf.rb +0 -88
@@ -0,0 +1,47 @@
1
+ module Kitabu
2
+ module Footnotes
3
+ class PDF < Base
4
+ def process
5
+ remove_duplicated_attributes
6
+ html.css(".chapter").each(&method(:process_chapter))
7
+ end
8
+
9
+ def remove_duplicated_attributes
10
+ # https://github.com/sparklemotion/nokogiri/issues/339
11
+ html.css('html').first.tap do |element|
12
+ next unless element
13
+ element.delete('xmlns')
14
+ element.delete('xml:lang')
15
+ end
16
+ end
17
+
18
+ def process_chapter(chapter)
19
+ chapter.css('.footnotes li').each do |footnote|
20
+ process_footnote(chapter, footnote)
21
+ increment_footnote_index!
22
+ end
23
+
24
+ chapter.css('.footnotes').each(&:remove)
25
+ end
26
+
27
+ def process_footnote(chapter, footnote)
28
+ # Remove rev links
29
+ footnote.css('[rev=footnote]').map(&:remove)
30
+
31
+ # Create an element for storing the footnote description
32
+ description = Nokogiri::XML::Node.new('span', Nokogiri::HTML::DocumentFragment.parse(''))
33
+ description.set_attribute 'class', 'footnote'
34
+ description.inner_html = footnote.css('p').map(&:inner_html).join("\n")
35
+
36
+ # Find ref based on footnote's id
37
+ fn_id = footnote.get_attribute('id')
38
+
39
+ refs = chapter.css("a[href='##{fn_id}']").each do |ref|
40
+ sup = ref.parent
41
+ sup.after(description)
42
+ sup.remove
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,73 @@
1
+ module Kitabu
2
+ class SourceList
3
+ # List of directories that should be skipped.
4
+ #
5
+ IGNORE_DIR = %w[. .. .svn .git]
6
+
7
+ # Files that should be skipped.
8
+ #
9
+ IGNORE_FILES = /^(CHANGELOG|TOC)\..*?$/
10
+
11
+ # List of recognized extensions.
12
+ #
13
+ EXTENSIONS = %w[md erb]
14
+
15
+ attr_reader :root_dir
16
+ attr_reader :source
17
+
18
+ def initialize(root_dir)
19
+ @root_dir = root_dir
20
+ @source = root_dir.join('text')
21
+ end
22
+
23
+ #
24
+ #
25
+ def each_chapter(&block)
26
+ files_grouped_by_chapter.each(&block)
27
+ end
28
+
29
+ def files_grouped_by_chapter
30
+ entries.each_with_object([]) do |entry, buffer|
31
+ files = chapter_files(entry)
32
+ buffer << files unless files.empty?
33
+ end
34
+ end
35
+
36
+ def chapter_files(entry)
37
+ # Chapters can be files outside a directory.
38
+ if File.file?(entry)
39
+ [entry]
40
+ else
41
+ Dir["#{entry}/**/*.{#{EXTENSIONS.join(",")}}"].sort
42
+ end
43
+ end
44
+
45
+ # Return a list of all recognized files.
46
+ #
47
+ def entries
48
+ Dir.entries(source).sort.each_with_object([]) do |entry, buffer|
49
+ buffer << source.join(entry) if valid_entry?(entry)
50
+ end
51
+ end
52
+
53
+ # Check if path is a valid entry.
54
+ # Files/directories that start with a dot or underscore will be skipped.
55
+ #
56
+ def valid_entry?(entry)
57
+ entry !~ /^(\.|_)/ && (valid_directory?(entry) || valid_file?(entry))
58
+ end
59
+
60
+ # Check if path is a valid directory.
61
+ #
62
+ def valid_directory?(entry)
63
+ File.directory?(source.join(entry)) && !IGNORE_DIR.include?(File.basename(entry))
64
+ end
65
+
66
+ # Check if path is a valid file.
67
+ #
68
+ def valid_file?(entry)
69
+ ext = File.extname(entry).gsub(/\./, "").downcase
70
+ File.file?(source.join(entry)) && EXTENSIONS.include?(ext) && entry !~ IGNORE_FILES
71
+ end
72
+ end
73
+ end
@@ -39,7 +39,7 @@ module Kitabu
39
39
  end
40
40
 
41
41
  def content
42
- @content ||= Parser::HTML.new(root_dir).content
42
+ @content ||= Exporter::HTML.new(root_dir).content
43
43
  end
44
44
  end
45
45
  end
@@ -21,7 +21,7 @@ module Kitabu
21
21
  end
22
22
 
23
23
  def emit(node)
24
- listener.send(:tag, node) if node.name =~ /h[1-6]/
24
+ listener.tag(node) if node.name =~ /h[1-6]/
25
25
  end
26
26
  end
27
27
  end
@@ -48,9 +48,9 @@ module Kitabu
48
48
 
49
49
  def tag(node) # :nodoc:
50
50
  toc << {
51
- :level => node.name.gsub(/[^\d]/, "").to_i,
52
- :text => node.text,
53
- :permalink => node["id"]
51
+ level: node.name.gsub(/[^\d]/, "").to_i,
52
+ text: node.text,
53
+ permalink: node["id"]
54
54
  }
55
55
  end
56
56
 
@@ -58,9 +58,9 @@ module Kitabu
58
58
  #
59
59
  def to_hash
60
60
  {
61
- :content => content,
62
- :html => to_html,
63
- :toc => toc
61
+ content: content,
62
+ html: to_html,
63
+ toc: toc
64
64
  }
65
65
  end
66
66
 
@@ -2,7 +2,7 @@ module Kitabu
2
2
  module Version
3
3
  MAJOR = 2
4
4
  MINOR = 0
5
- PATCH = 0
5
+ PATCH = 1
6
6
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
  end
8
8
  end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kitabu::Exporter::CSS do
4
+ let(:root) { SPECDIR.join("support/mybook") }
5
+
6
+ before do
7
+ Kitabu::Exporter::CSS.export(root)
8
+ end
9
+
10
+ it "generates css files" do
11
+ expect(root.join("output/styles/epub.css")).to be_file
12
+ expect(root.join("output/styles/pdf.css")).to be_file
13
+ expect(root.join("output/styles/print.css")).to be_file
14
+ expect(root.join("output/styles/html.css")).to be_file
15
+ end
16
+ end
@@ -1,11 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Kitabu::Parser::Epub do
3
+ describe Kitabu::Exporter::Epub do
4
4
  let(:root) { SPECDIR.join("support/mybook") }
5
5
 
6
6
  before do
7
- Kitabu::Parser::HTML.parse(root)
8
- Kitabu::Parser::Epub.parse(root)
7
+ Kitabu::Exporter::HTML.export(root)
8
+ Kitabu::Exporter::Epub.export(root)
9
9
  end
10
10
 
11
11
  it "generates e-pub" do
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ describe Kitabu::Exporter::HTML do
4
+ let(:root) { SPECDIR.join("support/mybook") }
5
+ let(:format) { described_class.new(root) }
6
+
7
+ context "when generating HTML" do
8
+ let(:file) { SPECDIR.join("support/mybook/output/mybook.html") }
9
+ let(:html) { File.read(file) }
10
+ before { format.export }
11
+
12
+ it "keeps html file around" do
13
+ expect(file).to be_file
14
+ end
15
+
16
+ it "has several chapters" do
17
+ expect(html).to have_tag("div.chapter", 3)
18
+ end
19
+
20
+ it "uses config file" do
21
+ expect(html).to have_tag("div.imprint p", "Copyright (C) 2010 John Doe.")
22
+ end
23
+
24
+ it "renders changelog" do
25
+ expect(html).to have_tag("div.changelog h2", "Revisions")
26
+ end
27
+
28
+ it "renders erb" do
29
+ expect(html).to have_tag("h2", "ERB")
30
+ end
31
+
32
+ it "renders erb blocks" do
33
+ expect(html).to have_tag("div.note.info > p", "This is a note!")
34
+ end
35
+ end
36
+ end
@@ -1,11 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Kitabu::Parser::Mobi, kindlegen: Kitabu::Dependency.kindlegen? do
3
+ describe Kitabu::Exporter::Mobi, kindlegen: Kitabu::Dependency.kindlegen? do
4
4
  let(:root) { SPECDIR.join("support/mybook") }
5
5
 
6
6
  before do
7
- Kitabu::Parser::HTML.parse(root)
8
- Kitabu::Parser::Mobi.parse(root)
7
+ Kitabu::Exporter::HTML.export(root)
8
+ Kitabu::Exporter::Mobi.export(root)
9
9
  end
10
10
 
11
11
  it "generates mobi" do
@@ -1,11 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Kitabu::Parser::PDF, prince: Kitabu::Dependency.prince? do
3
+ describe Kitabu::Exporter::PDF, prince: Kitabu::Dependency.prince? do
4
4
  let(:root) { SPECDIR.join("support/mybook") }
5
5
 
6
6
  before do
7
- Kitabu::Parser::HTML.new(root).parse
8
- Kitabu::Parser::PDF.new(root).parse
7
+ Kitabu::Exporter::HTML.new(root).export
8
+ Kitabu::Exporter::PDF.new(root).export
9
9
  end
10
10
 
11
11
  it "creates html with css identifier" do
@@ -1,11 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Kitabu::Parser::Txt, html2text: Kitabu::Dependency.html2text? do
3
+ describe Kitabu::Exporter::Txt, html2text: Kitabu::Dependency.html2text? do
4
4
  let(:root) { SPECDIR.join("support/mybook") }
5
5
 
6
6
  before do
7
- Kitabu::Parser::HTML.parse(root)
8
- Kitabu::Parser::Txt.parse(root)
7
+ Kitabu::Exporter::HTML.export(root)
8
+ Kitabu::Exporter::Txt.export(root)
9
9
  end
10
10
 
11
11
  it "generates text file" do
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kitabu::Footnotes::HTML do
4
+ let(:footnotes) {
5
+ Kitabu::Markdown.render <<-MARKDOWN.strip_heredoc
6
+ ohai[^1] and kthxbai[^2]
7
+
8
+ ohai[^1] again.
9
+
10
+ [^1]: Hello
11
+ [^2]: OK, thanks. Bye!
12
+ MARKDOWN
13
+ }
14
+
15
+ let(:content) {
16
+ <<-HTML.strip_heredoc
17
+ <div class="chapter">
18
+ #{footnotes}
19
+ </div>
20
+
21
+ <div class="chapter">
22
+ #{footnotes}
23
+ </div>
24
+ HTML
25
+ }
26
+
27
+ let(:html) {
28
+ Kitabu::Footnotes::HTML.process(content).html
29
+ }
30
+
31
+ let(:chapter1) { html.css('.chapter:first-of-type').first }
32
+ let(:chapter2) { html.css('.chapter:last-of-type').first }
33
+
34
+ it 'sets starting index' do
35
+ expect(chapter1).to have_tag('.footnotes ol[start="1"]')
36
+ expect(chapter2).to have_tag('.footnotes ol[start="3"]')
37
+ end
38
+
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}")
42
+ end
43
+ end
44
+
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)
48
+ end
49
+
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)
54
+
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)
58
+ end
59
+
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"]')
63
+
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"]')
66
+ end
67
+ end
@@ -1,11 +1,12 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
- describe Kitabu::Parser::HTML do
3
+ describe Kitabu::SourceList do
4
4
  let(:root) { SPECDIR.join("support/mybook") }
5
+ let(:format) { Kitabu::Exporter::HTML.new(root) }
6
+ let(:entries) { source_list.entries }
5
7
  let(:source) { root.join("text") }
6
- let(:parser) { described_class.new(root) }
7
- let(:entries) { parser.entries }
8
8
  let(:relative) { entries.collect {|e| e.to_s.gsub(/^#{Regexp.escape(source.to_s)}\//, "")} }
9
+ subject(:source_list) { Kitabu::SourceList.new(root) }
9
10
 
10
11
  context "when filtering entries" do
11
12
  it "skips dot directories" do
@@ -37,34 +38,4 @@ describe Kitabu::Parser::HTML do
37
38
  expect(relative.fourth).to be_nil
38
39
  end
39
40
  end
40
-
41
- context "when generating HTML" do
42
- let(:file) { SPECDIR.join("support/mybook/output/mybook.html") }
43
- let(:html) { File.read(file) }
44
- before { parser.parse }
45
-
46
- it "keeps html file around" do
47
- expect(file).to be_file
48
- end
49
-
50
- it "has several chapters" do
51
- expect(html).to have_tag("div.chapter", 3)
52
- end
53
-
54
- it "uses config file" do
55
- expect(html).to have_tag("div.imprint p", "Copyright (C) 2010 John Doe.")
56
- end
57
-
58
- it "renders changelog" do
59
- expect(html).to have_tag("div.changelog h2", "Revisions")
60
- end
61
-
62
- it "renders erb" do
63
- expect(html).to have_tag("h2", "ERB")
64
- end
65
-
66
- it "renders erb blocks" do
67
- expect(html).to have_tag("div.note.info > p", "This is a note!")
68
- end
69
- end
70
41
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Kitabu::Stats do
4
4
  let(:root_dir) { double("root dir").as_null_object }
5
- let(:parser) { double("parser").as_null_object }
5
+ let(:format) { double("format").as_null_object }
6
6
  let(:content) { "" }
7
7
  subject(:stats) { Kitabu::Stats.new(root_dir) }
8
8
 
@@ -11,18 +11,18 @@ describe Kitabu::Stats do
11
11
  }
12
12
 
13
13
  context "getting content" do
14
- it "parses content" do
15
- expect(Kitabu::Parser::HTML)
14
+ it "generates content" do
15
+ expect(Kitabu::Exporter::HTML)
16
16
  .to receive(:new)
17
17
  .with(root_dir)
18
- .and_return(parser)
18
+ .and_return(format)
19
19
 
20
20
  Kitabu::Stats.new(root_dir).content
21
21
  end
22
22
 
23
- it "returns parser content" do
24
- allow(Kitabu::Parser::HTML).to receive_message_chain(:new).and_return(parser)
25
- allow(parser).to receive_message_chain(:content).and_return("some content")
23
+ 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
26
 
27
27
  expect(Kitabu::Stats.new(root_dir).content).to eql("some content")
28
28
  end