kitabu 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +7 -5
- data/lib/kitabu.rb +12 -1
- data/lib/kitabu/cli.rb +1 -1
- data/lib/kitabu/exporter.rb +5 -5
- data/lib/kitabu/{parser.rb → exporter/base.rb} +9 -11
- data/lib/kitabu/exporter/css.rb +24 -0
- data/lib/kitabu/{parser → exporter}/epub.rb +2 -2
- data/lib/kitabu/exporter/html.rb +109 -0
- data/lib/kitabu/{parser → exporter}/mobi.rb +2 -2
- data/lib/kitabu/exporter/pdf.rb +43 -0
- data/lib/kitabu/{parser → exporter}/txt.rb +2 -2
- data/lib/kitabu/footnotes/base.rb +33 -0
- data/lib/kitabu/footnotes/html.rb +52 -0
- data/lib/kitabu/footnotes/pdf.rb +47 -0
- data/lib/kitabu/source_list.rb +73 -0
- data/lib/kitabu/stats.rb +1 -1
- data/lib/kitabu/stream.rb +1 -1
- data/lib/kitabu/toc/html.rb +6 -6
- data/lib/kitabu/version.rb +1 -1
- data/spec/kitabu/exporter/css_spec.rb +16 -0
- data/spec/kitabu/{parser → exporter}/epub_spec.rb +3 -3
- data/spec/kitabu/exporter/html_spec.rb +36 -0
- data/spec/kitabu/{parser → exporter}/mobi_spec.rb +3 -3
- data/spec/kitabu/{parser → exporter}/pdf_spec.rb +3 -3
- data/spec/kitabu/{parser → exporter}/txt_spec.rb +3 -3
- data/spec/kitabu/footnotes/html_spec.rb +67 -0
- data/spec/kitabu/{parser/html_spec.rb → source_list_spec.rb} +5 -34
- data/spec/kitabu/stats_spec.rb +7 -7
- data/templates/templates/styles/pdf.scss +1 -47
- data/templates/text/04_Dynamic_Content.erb +1 -1
- metadata +29 -54
- data/examples/kitabu/output/epub/images/.gitkeep +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.svg +0 -19
- data/examples/kitabu/output/epub/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-word.svg +0 -14
- data/examples/kitabu/output/epub/images/kitabu.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu.svg +0 -20
- data/examples/kitabu/output/epub/section_0.html +0 -266
- data/examples/kitabu/output/epub/section_1.html +0 -246
- data/examples/kitabu/output/epub/section_2.html +0 -520
- data/examples/kitabu/output/epub/section_3.html +0 -282
- data/examples/kitabu/output/epub/section_4.html +0 -276
- data/examples/kitabu/output/epub/styles/epub.css +0 -437
- data/examples/kitabu/output/epub/styles/html.css +0 -712
- data/examples/kitabu/output/epub/styles/pdf.css +0 -840
- data/examples/kitabu/output/epub/styles/print.css +0 -1278
- data/examples/kitabu/output/epub/toc.html +0 -37
- data/examples/kitabu/output/images/.gitkeep +0 -0
- data/examples/kitabu/output/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/images/kitabu-icon.svg +0 -19
- data/examples/kitabu/output/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/images/kitabu-word.svg +0 -14
- data/examples/kitabu/output/images/kitabu.png +0 -0
- data/examples/kitabu/output/images/kitabu.svg +0 -20
- data/examples/kitabu/output/kitabu.epub +0 -0
- data/examples/kitabu/output/kitabu.html +0 -513
- data/examples/kitabu/output/kitabu.mobi +0 -0
- data/examples/kitabu/output/kitabu.pdf +0 -0
- data/examples/kitabu/output/kitabu.pdf.html +0 -729
- data/examples/kitabu/output/kitabu.print.html +0 -729
- data/examples/kitabu/output/kitabu.print.pdf +0 -0
- data/examples/kitabu/output/kitabu.txt +0 -440
- data/examples/kitabu/output/styles/epub.css +0 -437
- data/examples/kitabu/output/styles/html.css +0 -712
- data/examples/kitabu/output/styles/pdf.css +0 -840
- data/examples/kitabu/output/styles/print.css +0 -1278
- data/lib/kitabu/parser/html.rb +0 -208
- data/lib/kitabu/parser/pdf.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99b16e5ab09105d5dbb28f37ce455d787a62fdee
|
4
|
+
data.tar.gz: dd1b28e6cd2a2d910073d82464d9b1ac235c0660
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c06222c9fd8e790581de00cbc1020a1bb9db90df276a59936cbba614cc0eb6f54c289114eff26289aa9dce89d695861de2abab4e265fdef12f22fc49de14e1f2
|
7
|
+
data.tar.gz: d6e3629e8c61d471788a95455af7f54e92e231e29b74087fa63a4498a1c6846a85371e0471452f713700cf1ad261652ac8d7ab356688c0e8eda928f2f875f1d5
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
[![Code Climate](https://codeclimate.com/github/fnando/kitabu/badges/gpa.svg)](https://codeclimate.com/github/fnando/kitabu)
|
5
5
|
[![Test Coverage](https://codeclimate.com/github/fnando/kitabu/badges/coverage.svg)](https://codeclimate.com/github/fnando/kitabu)
|
6
6
|
|
7
|
-
|
7
|
+
Kitabu is a framework for creating e-books from Markdown using Ruby. Using Prince PDF generator, you'll be able to get high quality PDFs. Also supports EPUB, Mobi, Text and HTML generation.
|
8
|
+
|
9
|
+
While Prince is too expensive (495USD for a single user license), the free version available at <http://www.princexml.com/download> generates a PDF with a small logo on the first page, which is removed when sent to a printer; you can use it locally for viewing the results immediately. When you're done writing your e-book, you can use [DocRaptor](http://docraptor.com), which have plans starting at $15/mo.
|
8
10
|
|
9
11
|
## Features
|
10
12
|
|
@@ -16,8 +18,8 @@ While Prince is too expensive (495USD for a single user license), the free versi
|
|
16
18
|
|
17
19
|
## Installation
|
18
20
|
|
19
|
-
To install Kitabu, you
|
20
|
-
If you
|
21
|
+
To install Kitabu, you'll need a working Ruby 2.0+ installation.
|
22
|
+
If you're cool with it, just run the following command to install it.
|
21
23
|
|
22
24
|
gem install kitabu
|
23
25
|
|
@@ -119,13 +121,13 @@ You'll want to see your progress eventually; it's time for you to generate the b
|
|
119
121
|
|
120
122
|
Kitabu can generate a Table of Contents (TOC) based on your h2-h6 tags. The h1 tag is discarded because it's meant to be the book title.
|
121
123
|
|
122
|
-
To print the TOC, you need to print a variable called
|
124
|
+
To print the TOC, you need to print a variable called `toc`, using the eRb tag.
|
123
125
|
|
124
126
|
<%= toc %>
|
125
127
|
|
126
128
|
#### Using ERB
|
127
129
|
|
128
|
-
You can also have
|
130
|
+
You can also have `.erb` files. You can mix Markdown and HTML, like the following:
|
129
131
|
|
130
132
|
## This the chapter title
|
131
133
|
|
data/lib/kitabu.rb
CHANGED
@@ -15,6 +15,7 @@ require "thor/group"
|
|
15
15
|
require "yaml"
|
16
16
|
require "cgi"
|
17
17
|
require "erb"
|
18
|
+
require "open3"
|
18
19
|
|
19
20
|
require "redcarpet"
|
20
21
|
require "rouge"
|
@@ -39,8 +40,18 @@ module Kitabu
|
|
39
40
|
require "kitabu/toc"
|
40
41
|
require "kitabu/cli"
|
41
42
|
require "kitabu/markdown"
|
42
|
-
require "kitabu/
|
43
|
+
require "kitabu/source_list"
|
43
44
|
require "kitabu/exporter"
|
45
|
+
require "kitabu/exporter/base"
|
46
|
+
require "kitabu/exporter/html"
|
47
|
+
require "kitabu/exporter/epub"
|
48
|
+
require "kitabu/exporter/mobi"
|
49
|
+
require "kitabu/exporter/pdf"
|
50
|
+
require "kitabu/exporter/txt"
|
51
|
+
require "kitabu/exporter/css"
|
52
|
+
require "kitabu/footnotes/base"
|
53
|
+
require "kitabu/footnotes/html"
|
54
|
+
require "kitabu/footnotes/pdf"
|
44
55
|
require "kitabu/stream"
|
45
56
|
require "kitabu/dependency"
|
46
57
|
require "kitabu/stats"
|
data/lib/kitabu/cli.rb
CHANGED
data/lib/kitabu/exporter.rb
CHANGED
@@ -29,11 +29,11 @@ module Kitabu
|
|
29
29
|
export_txt = [nil, "txt"].include?(options[:only])
|
30
30
|
|
31
31
|
exported = []
|
32
|
-
exported <<
|
33
|
-
exported <<
|
34
|
-
exported <<
|
35
|
-
exported <<
|
36
|
-
exported <<
|
32
|
+
exported << HTML.export(root_dir)
|
33
|
+
exported << PDF.export(root_dir) if export_pdf && Dependency.prince?
|
34
|
+
exported << Epub.export(root_dir) if export_epub
|
35
|
+
exported << Mobi.export(root_dir) if export_mobi && Dependency.kindlegen?
|
36
|
+
exported << Txt.export(root_dir) if export_txt && Dependency.html2text?
|
37
37
|
|
38
38
|
if exported.all?
|
39
39
|
color = :green
|
@@ -1,13 +1,5 @@
|
|
1
|
-
require 'open3'
|
2
|
-
|
3
1
|
module Kitabu
|
4
|
-
|
5
|
-
autoload :HTML , "kitabu/parser/html"
|
6
|
-
autoload :PDF , "kitabu/parser/pdf"
|
7
|
-
autoload :Epub , "kitabu/parser/epub"
|
8
|
-
autoload :Mobi , "kitabu/parser/mobi"
|
9
|
-
autoload :Txt , "kitabu/parser/txt"
|
10
|
-
|
2
|
+
class Exporter
|
11
3
|
class Base
|
12
4
|
# The e-book directory.
|
13
5
|
#
|
@@ -17,8 +9,8 @@ module Kitabu
|
|
17
9
|
#
|
18
10
|
attr_accessor :source
|
19
11
|
|
20
|
-
def self.
|
21
|
-
new(root_dir).
|
12
|
+
def self.export(root_dir)
|
13
|
+
new(root_dir).export
|
22
14
|
end
|
23
15
|
|
24
16
|
def initialize(root_dir)
|
@@ -26,6 +18,12 @@ module Kitabu
|
|
26
18
|
@source = root_dir.join("text")
|
27
19
|
end
|
28
20
|
|
21
|
+
#
|
22
|
+
#
|
23
|
+
def source_list
|
24
|
+
@source_list ||= SourceList.new(root_dir)
|
25
|
+
end
|
26
|
+
|
29
27
|
# Return directory's basename.
|
30
28
|
#
|
31
29
|
def name
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kitabu
|
2
|
+
class Exporter
|
3
|
+
class CSS < Base
|
4
|
+
attr_reader :root_dir
|
5
|
+
|
6
|
+
def export
|
7
|
+
files = Dir[root_dir.join("templates/styles/*.{scss,sass}").to_s]
|
8
|
+
options = {
|
9
|
+
style: :expanded,
|
10
|
+
line_numbers: true,
|
11
|
+
load_paths: [root_dir.join("templates/styles")]
|
12
|
+
}
|
13
|
+
|
14
|
+
files.each do |file|
|
15
|
+
_, file_name, syntax = *File.basename(file).match(/(.*?)\.(.*?)$/)
|
16
|
+
engine = Sass::Engine.new(File.read(file), options.merge(syntax: syntax.to_sym))
|
17
|
+
target = root_dir.join("output/styles", "#{file_name}.css")
|
18
|
+
FileUtils.mkdir_p(File.dirname(target))
|
19
|
+
File.open(target, "w") {|io| io << engine.render }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Kitabu
|
2
|
-
|
2
|
+
class Exporter
|
3
3
|
class Epub < Base
|
4
4
|
def sections
|
5
5
|
@sections ||= html.css("div.chapter").each_with_index.map do |chapter, index|
|
@@ -20,7 +20,7 @@ module Kitabu
|
|
20
20
|
@html ||= Nokogiri::HTML(html_path.read)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def export
|
24
24
|
copy_styles!
|
25
25
|
copy_images!
|
26
26
|
set_metadata!
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Kitabu
|
2
|
+
class Exporter
|
3
|
+
class HTML < Base
|
4
|
+
class << self
|
5
|
+
# The footnote index control. We have to manipulate footnotes
|
6
|
+
# because each chapter starts from 1, so we have duplicated references.
|
7
|
+
#
|
8
|
+
attr_accessor :footnote_index
|
9
|
+
end
|
10
|
+
|
11
|
+
# Parse all files and save the parsed content
|
12
|
+
# to <tt>output/book_name.html</tt>.
|
13
|
+
#
|
14
|
+
def export
|
15
|
+
copy_images!
|
16
|
+
export_stylesheets!
|
17
|
+
|
18
|
+
File.open(root_dir.join("output/#{name}.html"), "w") do |file|
|
19
|
+
file << parse_layout(content)
|
20
|
+
end
|
21
|
+
|
22
|
+
true
|
23
|
+
rescue Exception => error
|
24
|
+
handle_error(error)
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_footnote_index!
|
29
|
+
self.class.footnote_index = 1
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return all chapters wrapped in a <tt>div.chapter</tt> tag.
|
33
|
+
#
|
34
|
+
def content
|
35
|
+
String.new.tap do |content|
|
36
|
+
source_list.each_chapter do |files|
|
37
|
+
content << %[<div class="chapter">#{render_chapter(files)}</div>]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
# Render +file+ considering its extension.
|
44
|
+
#
|
45
|
+
def render_file(file)
|
46
|
+
if format(file) == :erb
|
47
|
+
content = render_template(file, config)
|
48
|
+
else
|
49
|
+
content = File.read(file)
|
50
|
+
end
|
51
|
+
|
52
|
+
Kitabu::Markdown.render(content)
|
53
|
+
end
|
54
|
+
|
55
|
+
def format(file)
|
56
|
+
if File.extname(file) == '.erb'
|
57
|
+
:erb
|
58
|
+
else
|
59
|
+
:markdown
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Parse layout file, making available all configuration entries.
|
64
|
+
#
|
65
|
+
def parse_layout(html)
|
66
|
+
toc = TOC::HTML.generate(html)
|
67
|
+
content = Footnotes::HTML.process(toc.content).html.css('html').first.inner_html
|
68
|
+
|
69
|
+
locals = config.merge({
|
70
|
+
content: content,
|
71
|
+
toc: toc.to_html,
|
72
|
+
changelog: render_changelog
|
73
|
+
})
|
74
|
+
|
75
|
+
render_template(root_dir.join("templates/html/layout.erb"), locals)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Render changelog file.
|
79
|
+
# This file can be used to inform any book change.
|
80
|
+
#
|
81
|
+
def render_changelog
|
82
|
+
changelog = Dir[root_dir.join("text/CHANGELOG.*")].first
|
83
|
+
render_file(changelog) if changelog
|
84
|
+
end
|
85
|
+
|
86
|
+
# Render all +files+ from a given chapter.
|
87
|
+
#
|
88
|
+
def render_chapter(files)
|
89
|
+
String.new.tap do |chapter|
|
90
|
+
files.each do |file|
|
91
|
+
chapter << render_file(file) << "\n\n"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Copy images
|
97
|
+
#
|
98
|
+
def copy_images!
|
99
|
+
copy_directory("images", "output/images")
|
100
|
+
end
|
101
|
+
|
102
|
+
# Export all root stylesheets.
|
103
|
+
#
|
104
|
+
def export_stylesheets!
|
105
|
+
Exporter::CSS.new(root_dir).export
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Kitabu
|
2
|
+
class Exporter
|
3
|
+
class PDF < Base
|
4
|
+
def export
|
5
|
+
apply_footnotes!
|
6
|
+
spawn_command ["prince", html_for_pdf.to_s, "-o", pdf_file.to_s]
|
7
|
+
spawn_command ["prince", html_for_print.to_s, "-o", print_file.to_s]
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply_footnotes!
|
11
|
+
html = Footnotes::PDF.process(html_file.read).html
|
12
|
+
create_html_file(html_for_print, html, 'print')
|
13
|
+
create_html_file(html_for_pdf, html, 'pdf')
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_html_file(target, html, class_name)
|
17
|
+
html.css("html").first.set_attribute "class", class_name
|
18
|
+
html.css("link[name=stylesheet]").first.set_attribute "href", "styles/#{class_name}.css"
|
19
|
+
File.open(target, "w") {|f| f << html.to_html }
|
20
|
+
end
|
21
|
+
|
22
|
+
def html_for_pdf
|
23
|
+
root_dir.join("output/#{name}.pdf.html")
|
24
|
+
end
|
25
|
+
|
26
|
+
def html_for_print
|
27
|
+
root_dir.join("output/#{name}.print.html")
|
28
|
+
end
|
29
|
+
|
30
|
+
def html_file
|
31
|
+
root_dir.join("output/#{name}.html")
|
32
|
+
end
|
33
|
+
|
34
|
+
def pdf_file
|
35
|
+
root_dir.join("output/#{name}.pdf")
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_file
|
39
|
+
root_dir.join("output/#{name}.print.pdf")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Kitabu
|
2
|
+
module Footnotes
|
3
|
+
class Base
|
4
|
+
# Set the content that will be modified.
|
5
|
+
attr_accessor :content
|
6
|
+
|
7
|
+
# Set the Nokogiri html object.
|
8
|
+
attr_accessor :html
|
9
|
+
|
10
|
+
# Set the footnote index.
|
11
|
+
attr_reader :footnote_index
|
12
|
+
|
13
|
+
# Process content, fixing footnotes numbering.
|
14
|
+
# Returns a string representing the new markup.
|
15
|
+
#
|
16
|
+
def self.process(content)
|
17
|
+
footnotes = new(content)
|
18
|
+
footnotes.process
|
19
|
+
footnotes
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(content)
|
23
|
+
@content = content
|
24
|
+
@html = Nokogiri::HTML(content)
|
25
|
+
@footnote_index = 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def increment_footnote_index!
|
29
|
+
@footnote_index += 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Kitabu
|
2
|
+
module Footnotes
|
3
|
+
class HTML < Base
|
4
|
+
def process
|
5
|
+
html.css('.chapter').each(&method(:process_chapter))
|
6
|
+
end
|
7
|
+
|
8
|
+
def process_chapter(chapter)
|
9
|
+
footnotes = chapter.css('.footnotes').first
|
10
|
+
return unless footnotes
|
11
|
+
list = footnotes.css('ol').first
|
12
|
+
list.set_attribute 'start', footnote_index
|
13
|
+
|
14
|
+
chapter.css('.footnotes li').each do |footnote|
|
15
|
+
process_footnote(chapter, footnote)
|
16
|
+
increment_footnote_index!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_footnote(chapter, footnote)
|
21
|
+
current_index = footnote.get_attribute('id').gsub(/[^\d]/m, '')
|
22
|
+
footnote.set_attribute 'id', "fn#{footnote_index}"
|
23
|
+
|
24
|
+
process_links_to_footnote(chapter, current_index)
|
25
|
+
process_rev_links(chapter, current_index)
|
26
|
+
process_ref_elements(chapter, current_index)
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_links_to_footnote(chapter, current_index)
|
30
|
+
chapter.css("a[href='#fn#{current_index}']").each do |link|
|
31
|
+
link.set_attribute 'href', "#fn#{footnote_index}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_rev_links(chapter, current_index)
|
36
|
+
chapter.css("a[href='#fnref#{current_index}']").each do |link|
|
37
|
+
link.set_attribute 'href', "#fnref#{footnote_index}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_ref_elements(chapter, current_index)
|
42
|
+
chapter.css("sup[id=fnref#{current_index}]").each_with_index do |sup, index|
|
43
|
+
if index.zero?
|
44
|
+
sup.set_attribute 'id', "fnref#{footnote_index}"
|
45
|
+
else
|
46
|
+
sup.remove_attribute 'id'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|