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.
- 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
data/lib/kitabu/parser/html.rb
DELETED
@@ -1,208 +0,0 @@
|
|
1
|
-
module Kitabu
|
2
|
-
module Parser
|
3
|
-
class HTML < Base
|
4
|
-
# List of directories that should be skipped.
|
5
|
-
#
|
6
|
-
IGNORE_DIR = %w[. .. .svn]
|
7
|
-
|
8
|
-
# Files that should be skipped.
|
9
|
-
#
|
10
|
-
IGNORE_FILES = /^(CHANGELOG|TOC)\..*?$/
|
11
|
-
|
12
|
-
# List of recognized extensions.
|
13
|
-
#
|
14
|
-
EXTENSIONS = %w[md erb]
|
15
|
-
|
16
|
-
class << self
|
17
|
-
# The footnote index control. We have to manipulate footnotes
|
18
|
-
# because each chapter starts from 1, so we have duplicated references.
|
19
|
-
#
|
20
|
-
attr_accessor :footnote_index
|
21
|
-
end
|
22
|
-
|
23
|
-
# Parse all files and save the parsed content
|
24
|
-
# to <tt>output/book_name.html</tt>.
|
25
|
-
#
|
26
|
-
def parse
|
27
|
-
reset_footnote_index!
|
28
|
-
copy_images!
|
29
|
-
export_stylesheets!
|
30
|
-
|
31
|
-
File.open(root_dir.join("output/#{name}.html"), "w") do |file|
|
32
|
-
file << parse_layout(content)
|
33
|
-
end
|
34
|
-
|
35
|
-
true
|
36
|
-
rescue Exception => error
|
37
|
-
handle_error(error)
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
|
-
def reset_footnote_index!
|
42
|
-
self.class.footnote_index = 1
|
43
|
-
end
|
44
|
-
|
45
|
-
# Return all chapters wrapped in a <tt>div.chapter</tt> tag.
|
46
|
-
#
|
47
|
-
def content
|
48
|
-
String.new.tap do |chapters|
|
49
|
-
entries.each do |entry|
|
50
|
-
files = chapter_files(entry)
|
51
|
-
|
52
|
-
# no markup files, so skip to the next one!
|
53
|
-
next if files.empty?
|
54
|
-
|
55
|
-
chapters << %[<div class="chapter">#{render_chapter(files)}</div>]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Return a list of all recognized files.
|
61
|
-
#
|
62
|
-
def entries
|
63
|
-
Dir.entries(source).sort.inject([]) do |buffer, entry|
|
64
|
-
buffer << source.join(entry) if valid_entry?(entry)
|
65
|
-
buffer
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
def chapter_files(entry)
|
71
|
-
# Chapters can be files outside a directory.
|
72
|
-
if File.file?(entry)
|
73
|
-
[entry]
|
74
|
-
else
|
75
|
-
Dir["#{entry}/**/*.{#{EXTENSIONS.join(",")}}"].sort
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Check if path is a valid entry.
|
80
|
-
# Files/directories that start with a dot or underscore will be skipped.
|
81
|
-
#
|
82
|
-
def valid_entry?(entry)
|
83
|
-
entry !~ /^(\.|_)/ && (valid_directory?(entry) || valid_file?(entry))
|
84
|
-
end
|
85
|
-
|
86
|
-
# Check if path is a valid directory.
|
87
|
-
#
|
88
|
-
def valid_directory?(entry)
|
89
|
-
File.directory?(source.join(entry)) && !IGNORE_DIR.include?(File.basename(entry))
|
90
|
-
end
|
91
|
-
|
92
|
-
# Check if path is a valid file.
|
93
|
-
#
|
94
|
-
def valid_file?(entry)
|
95
|
-
ext = File.extname(entry).gsub(/\./, "").downcase
|
96
|
-
File.file?(source.join(entry)) && EXTENSIONS.include?(ext) && entry !~ IGNORE_FILES
|
97
|
-
end
|
98
|
-
|
99
|
-
# Render +file+ considering its extension.
|
100
|
-
#
|
101
|
-
def render_file(file)
|
102
|
-
if format(file) == :erb
|
103
|
-
content = render_template(file, config)
|
104
|
-
else
|
105
|
-
content = File.read(file)
|
106
|
-
end
|
107
|
-
|
108
|
-
content = Kitabu::Markdown.render(content)
|
109
|
-
render_footnotes(content)
|
110
|
-
end
|
111
|
-
|
112
|
-
def render_footnotes(content)
|
113
|
-
html = Nokogiri::HTML(content)
|
114
|
-
footnotes = html.css("p[id^='fn']")
|
115
|
-
|
116
|
-
return content if footnotes.empty?
|
117
|
-
|
118
|
-
reset_footnote_index! unless self.class.footnote_index
|
119
|
-
|
120
|
-
footnotes.each do |fn|
|
121
|
-
index = self.class.footnote_index
|
122
|
-
actual_index = fn["id"].gsub(/[^\d]/, "")
|
123
|
-
|
124
|
-
fn.set_attribute("id", "_fn#{index}")
|
125
|
-
|
126
|
-
html.css("a[href='#fn#{actual_index}']").each do |link|
|
127
|
-
link.set_attribute("href", "#_fn#{index}")
|
128
|
-
end
|
129
|
-
|
130
|
-
html.css("a[href='#fnr#{actual_index}']").each do |link|
|
131
|
-
link.set_attribute("href", "#_fnr#{index}")
|
132
|
-
end
|
133
|
-
|
134
|
-
html.css("[id=fnr#{actual_index}]").each do |tag|
|
135
|
-
tag.set_attribute("id", "_fnr#{index}")
|
136
|
-
end
|
137
|
-
|
138
|
-
self.class.footnote_index += 1
|
139
|
-
end
|
140
|
-
|
141
|
-
html.css("body").inner_html
|
142
|
-
end
|
143
|
-
|
144
|
-
def format(file)
|
145
|
-
if File.extname(file) == '.erb'
|
146
|
-
:erb
|
147
|
-
else
|
148
|
-
:markdown
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Parse layout file, making available all configuration entries.
|
153
|
-
#
|
154
|
-
def parse_layout(html)
|
155
|
-
toc = TOC::HTML.generate(html)
|
156
|
-
locals = config.merge({
|
157
|
-
content: toc.content,
|
158
|
-
toc: toc.to_html,
|
159
|
-
changelog: render_changelog
|
160
|
-
})
|
161
|
-
render_template(root_dir.join("templates/html/layout.erb"), locals)
|
162
|
-
end
|
163
|
-
|
164
|
-
# Render changelog file.
|
165
|
-
# This file can be used to inform any book change.
|
166
|
-
#
|
167
|
-
def render_changelog
|
168
|
-
changelog = Dir[root_dir.join("text/CHANGELOG.*")].first
|
169
|
-
render_file(changelog) if changelog
|
170
|
-
end
|
171
|
-
|
172
|
-
# Render all +files+ from a given chapter.
|
173
|
-
#
|
174
|
-
def render_chapter(files)
|
175
|
-
String.new.tap do |chapter|
|
176
|
-
files.each do |file|
|
177
|
-
chapter << render_file(file) << "\n\n"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
# Copy images
|
183
|
-
#
|
184
|
-
def copy_images!
|
185
|
-
copy_directory("images", "output/images")
|
186
|
-
end
|
187
|
-
|
188
|
-
# Export all root stylesheets.
|
189
|
-
#
|
190
|
-
def export_stylesheets!
|
191
|
-
files = Dir[root_dir.join("templates/styles/*.{scss,sass}").to_s]
|
192
|
-
options = {
|
193
|
-
style: :expanded,
|
194
|
-
line_numbers: true,
|
195
|
-
load_paths: [root_dir.join("templates/styles")]
|
196
|
-
}
|
197
|
-
|
198
|
-
files.each do |file|
|
199
|
-
_, file_name, syntax = *File.basename(file).match(/(.*?)\.(.*?)$/)
|
200
|
-
engine = Sass::Engine.new(File.read(file), options.merge(syntax: syntax.to_sym))
|
201
|
-
target = root_dir.join("output/styles", "#{file_name}.css")
|
202
|
-
FileUtils.mkdir_p(File.dirname(target))
|
203
|
-
File.open(target, "w") {|io| io << engine.render }
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
data/lib/kitabu/parser/pdf.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
module Kitabu
|
2
|
-
module Parser
|
3
|
-
class PDF < Base
|
4
|
-
def parse
|
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 = Nokogiri::HTML(html_file.read)
|
12
|
-
footnote_count = 1
|
13
|
-
|
14
|
-
# https://github.com/sparklemotion/nokogiri/issues/339
|
15
|
-
html.css("html").first.tap do |element|
|
16
|
-
next unless element
|
17
|
-
element.delete("xmlns")
|
18
|
-
element.delete("xml:lang")
|
19
|
-
end
|
20
|
-
|
21
|
-
chapters = html.css(".chapter")
|
22
|
-
|
23
|
-
chapters.each do |chapter|
|
24
|
-
footnotes = chapter.css(".footnotes li")
|
25
|
-
|
26
|
-
footnotes.each do |fn|
|
27
|
-
# Get current footnote number
|
28
|
-
footnote_number = footnote_count
|
29
|
-
footnote_count += 1
|
30
|
-
|
31
|
-
# Remove rev links
|
32
|
-
fn.css('[rev=footnote]').map(&:remove)
|
33
|
-
|
34
|
-
# Create an element for storing the footnote description
|
35
|
-
fn_desc = Nokogiri::XML::Node.new('span', Nokogiri::HTML::DocumentFragment.parse(''))
|
36
|
-
fn_desc.set_attribute 'class', 'fn-desc'
|
37
|
-
fn_desc.inner_html = fn.css('p').map(&:inner_html).join("\n")
|
38
|
-
|
39
|
-
# Find ref based on footnote's id
|
40
|
-
fn_id = fn.get_attribute('id')
|
41
|
-
ref = chapter.css("a[href='##{fn_id}']").first
|
42
|
-
|
43
|
-
# Go up to parent and reformat it.
|
44
|
-
sup = ref.parent
|
45
|
-
sup.delete("id")
|
46
|
-
sup.set_attribute 'class', 'fn-ref'
|
47
|
-
sup.inner_html = ''
|
48
|
-
|
49
|
-
# Finally, add the description after the <sup> tag.
|
50
|
-
sup.after(fn_desc)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Remove the footnotes element
|
54
|
-
chapter.css('.footnotes').map(&:remove)
|
55
|
-
end
|
56
|
-
|
57
|
-
create_html_file(html_for_print, html, 'print')
|
58
|
-
create_html_file(html_for_pdf, html, 'pdf')
|
59
|
-
end
|
60
|
-
|
61
|
-
def create_html_file(target, html, class_name)
|
62
|
-
html.css("html").first.set_attribute "class", class_name
|
63
|
-
html.css("link[name=stylesheet]").first.set_attribute "href", "styles/#{class_name}.css"
|
64
|
-
File.open(target, "w") {|f| f << html.to_html }
|
65
|
-
end
|
66
|
-
|
67
|
-
def html_for_pdf
|
68
|
-
root_dir.join("output/#{name}.pdf.html")
|
69
|
-
end
|
70
|
-
|
71
|
-
def html_for_print
|
72
|
-
root_dir.join("output/#{name}.print.html")
|
73
|
-
end
|
74
|
-
|
75
|
-
def html_file
|
76
|
-
root_dir.join("output/#{name}.html")
|
77
|
-
end
|
78
|
-
|
79
|
-
def pdf_file
|
80
|
-
root_dir.join("output/#{name}.pdf")
|
81
|
-
end
|
82
|
-
|
83
|
-
def print_file
|
84
|
-
root_dir.join("output/#{name}.print.pdf")
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|