verku 0.8.0.p
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 +7 -0
- data/.document +5 -0
- data/.gitignore +49 -0
- data/BUILD.md +6 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +82 -0
- data/LICENSE.md +22 -0
- data/README.md +149 -0
- data/Rakefile +72 -0
- data/VERSION +1 -0
- data/bin/verku +5 -0
- data/lib/verku.rb +56 -0
- data/lib/verku/adapters/markdown.rb +44 -0
- data/lib/verku/cli.rb +93 -0
- data/lib/verku/dependency.rb +19 -0
- data/lib/verku/exporter.rb +77 -0
- data/lib/verku/extensions/string.rb +19 -0
- data/lib/verku/generator.rb +55 -0
- data/lib/verku/parser.rb +85 -0
- data/lib/verku/parser/epub.rb +187 -0
- data/lib/verku/parser/html.rb +245 -0
- data/lib/verku/parser/mobi.rb +17 -0
- data/lib/verku/parser/pdf.rb +54 -0
- data/lib/verku/parser/txt.rb +1 -0
- data/lib/verku/stats.rb +114 -0
- data/lib/verku/stream.rb +27 -0
- data/lib/verku/toc.rb +6 -0
- data/lib/verku/toc/epub.rb +41 -0
- data/lib/verku/toc/html.rb +78 -0
- data/lib/verku/version.rb +10 -0
- data/templates/config.erb +80 -0
- data/templates/cover.jpg +0 -0
- data/templates/dp-logo.png +0 -0
- data/templates/epub/back.erb +22 -0
- data/templates/epub/copyright.erb +46 -0
- data/templates/epub/cover.erb +12 -0
- data/templates/epub/cover.html +12 -0
- data/templates/epub/page.erb +15 -0
- data/templates/epub/user.css +500 -0
- data/templates/extras.tex +1 -0
- data/templates/html/copyright.erb +46 -0
- data/templates/html/layout.css +352 -0
- data/templates/html/layout.erb +45 -0
- data/templates/html/syntax.css +58 -0
- data/templates/html/thanks.erb +21 -0
- data/templates/html/user.css +7 -0
- data/templates/latex.erb +416 -0
- data/templates/merovex-logo.jpg +0 -0
- data/templates/merovex-logo.png +0 -0
- data/templates/pdf/layout.erb +418 -0
- data/templates/rakefile.rb +103 -0
- data/templates/readme.erb +3 -0
- data/templates/text/01-Getting-Started.md +27 -0
- data/templates/text/02-Creating-Chapters.md +22 -0
- data/templates/text/03-Generating-Output.md +2 -0
- data/templates/text/10-Test-Markdown.md +157 -0
- data/test/helper.rb +34 -0
- data/test/test_bookmaker.rb +7 -0
- data/verku.gemspec +142 -0
- metadata +317 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Kitabu
|
2
|
+
class Markdown
|
3
|
+
# Supported Markdown libraries
|
4
|
+
#
|
5
|
+
MARKDOWN_LIBRARIES = %w[Kramdown]
|
6
|
+
|
7
|
+
# Retrieve preferred Markdown processor.
|
8
|
+
# You'll need one of the following libraries:
|
9
|
+
#
|
10
|
+
# # RDiscount: https://rubygems.org/gems/rdiscount
|
11
|
+
# # Maruku: https://rubygems.org/gems/maruku
|
12
|
+
# # PEGMarkdown: https://rubygems.org/gems/rpeg-markdown
|
13
|
+
# # BlueCloth: https://rubygems.org/gems/bluecloth
|
14
|
+
# # Redcarpet: https://rubygems.org/gems/redcarpet
|
15
|
+
# # Kramdown: http://kramdown.rubyforge.org/
|
16
|
+
#
|
17
|
+
# Note: RDiscount will always be installed as Kitabu's dependency but only used when no
|
18
|
+
# alternative library is available.
|
19
|
+
#
|
20
|
+
def self.engine
|
21
|
+
@engine ||= Object.const_get(MARKDOWN_LIBRARIES.find {|lib| Object.const_defined?(lib)})
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.to_latex(content)
|
25
|
+
case engine.name
|
26
|
+
when "Redcarpet"
|
27
|
+
# render = Redcarpet::Render::HTML.new(:hard_wrap => true, :xhtml => true)
|
28
|
+
# Redcarpet::Markdown.new(render).render(content)
|
29
|
+
else
|
30
|
+
engine.new(content).to_latex
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# Convert Markdown to HTML.
|
34
|
+
def self.to_html(content)
|
35
|
+
case engine.name
|
36
|
+
when "Redcarpet"
|
37
|
+
render = Redcarpet::Render::HTML.new(:hard_wrap => true, :xhtml => true)
|
38
|
+
Redcarpet::Markdown.new(render).render(content)
|
39
|
+
else
|
40
|
+
engine.new(content).to_html
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/verku/cli.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'thor'
|
3
|
+
require 'verku/version'
|
4
|
+
module Verku
|
5
|
+
class Cli < Thor
|
6
|
+
FORMATS = %w[pdf draft proof html epub mobi txt]
|
7
|
+
check_unknown_options!
|
8
|
+
|
9
|
+
def self.exit_on_failure?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
def initialize(args = [], options = {}, config = {})
|
13
|
+
if (config[:current_task] || config[:current_command]).name == "new" && args.empty?
|
14
|
+
raise Error, "The e-Book path is required. For details run: verku help new"
|
15
|
+
end
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "create", "Start new work"
|
20
|
+
map %w(create new) => :create
|
21
|
+
def create(path)
|
22
|
+
puts "Verku -- A Million Monkeys Writing Your Masterpiece."
|
23
|
+
generator = Generator.new
|
24
|
+
generator.destination_root = path.squish.gsub(' ','-')
|
25
|
+
generator.invoke_all
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "compile [OPTIONS]", "Export e-book"
|
29
|
+
map %w(compile export build) => :export
|
30
|
+
method_option :only, :type => :string, :desc => "Can be one of: #{FORMATS.join(", ")}"
|
31
|
+
method_option :open, :type => :boolean, :desc => "Automatically open PDF (Preview.app for Mac OS X and xdg-open for Linux)"
|
32
|
+
def export
|
33
|
+
inside_ebook!
|
34
|
+
if options[:only] && !FORMATS.include?(options[:only])
|
35
|
+
raise Error, "The --only option need to be one of: #{FORMATS.join(", ")}"
|
36
|
+
end
|
37
|
+
Verku::Exporter.run(root_dir, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "pdf", "Export PDF only"
|
41
|
+
def pdf
|
42
|
+
inside_ebook!
|
43
|
+
Verku::Exporter.run(root_dir, {:only => 'pdf'})
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "version", "Prints the Verku's version information"
|
47
|
+
map %w(-v --version) => :version
|
48
|
+
def version
|
49
|
+
say "Verku version #{Verku::Version::STRING}"
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "stats", "Display some stats about your e-book"
|
53
|
+
def stats
|
54
|
+
inside_ebook!
|
55
|
+
stats = Verku::Stats.new(root_dir)
|
56
|
+
|
57
|
+
say [
|
58
|
+
# "Chapters: #{stats.chapters}",
|
59
|
+
"Goal: #{sprintf("%7d", stats.target)}",
|
60
|
+
"Words: #{sprintf("%7d", stats.words)}",
|
61
|
+
" -------",
|
62
|
+
"Left: #{sprintf("%7d", stats.remaining)}",
|
63
|
+
"\nProgress: #{sprintf("%5d", stats.today)}"
|
64
|
+
].join("\n")
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "move old_id new_id", "Move scene to new sequence."
|
68
|
+
def move(oid,nid)
|
69
|
+
s = Structure.new(root_dir)
|
70
|
+
s.move(oid,nid)
|
71
|
+
end
|
72
|
+
desc "trash [OPTIONS]", "Move scene to trash."
|
73
|
+
def trash(scene_id)
|
74
|
+
s = Structure.new(root_dir)
|
75
|
+
s.trash(scene_id)
|
76
|
+
end
|
77
|
+
private
|
78
|
+
def config
|
79
|
+
YAML.load_file(config_path).with_indifferent_access
|
80
|
+
end
|
81
|
+
def config_path
|
82
|
+
root_dir.join("_verku.yml")
|
83
|
+
end
|
84
|
+
def root_dir
|
85
|
+
@root ||= Pathname.new(Dir.pwd)
|
86
|
+
end
|
87
|
+
def inside_ebook!
|
88
|
+
unless File.exist?(config_path)
|
89
|
+
raise Error, "You have to run this command from inside an e-book directory."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Verku
|
2
|
+
class Dependency
|
3
|
+
def self.kindlegen?
|
4
|
+
@kindlegen ||= `which kindlegen` && $?.success?
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.xelatex?
|
8
|
+
@xelatex ||= `which xelatex` && $?.success?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.html2text?
|
12
|
+
@html2text ||= `which html2text` && $?.success?
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.pygments_rb?
|
16
|
+
@pygments_rb ||= defined?(Pygments)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Verku
|
2
|
+
class Exporter
|
3
|
+
def self.run(root_dir, options)
|
4
|
+
exporter = new(root_dir, options)
|
5
|
+
exporter.export!
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :root_dir
|
9
|
+
attr_accessor :options
|
10
|
+
|
11
|
+
def initialize(root_dir, options)
|
12
|
+
@root_dir = root_dir
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def ui
|
17
|
+
@ui ||= Thor::Base.shell.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def export!
|
21
|
+
helper = root_dir.join("config/helper.rb")
|
22
|
+
load(helper) if helper.exist?
|
23
|
+
|
24
|
+
raise "Missing Templates directory (_templates)" unless File.exist?("_templates")
|
25
|
+
raise "Missing Images directory (_images)" unless File.exist?("_images")
|
26
|
+
raise "Missing Output directory (builds)" unless File.exist?("builds")
|
27
|
+
|
28
|
+
puts "Missing Kindlegen" unless Dependency.kindlegen?
|
29
|
+
puts "Missing XeLatex" unless Dependency.xelatex?
|
30
|
+
# puts "Missing Html2Text" unless Dependency.html2text?
|
31
|
+
|
32
|
+
export_pdf = [nil, "pdf"].include?(options[:only])
|
33
|
+
export_html = [nil, "html", "mobi", "epub"].include?(options[:only])
|
34
|
+
export_epub = [nil, "mobi", "epub"].include?(options[:only])
|
35
|
+
export_mobi = [nil, "mobi"].include?(options[:only])
|
36
|
+
export_txt = [nil, "txt"].include?(options[:only])
|
37
|
+
|
38
|
+
exported = []
|
39
|
+
exported << Parser::PDF.parse(root_dir) if export_pdf && Dependency.xelatex?# && Dependency.prince?
|
40
|
+
exported << Parser::HTML.parse(root_dir) if export_html
|
41
|
+
epub_done = Parser::Epub.parse(root_dir) if export_epub
|
42
|
+
exported << epub_done
|
43
|
+
exported << Parser::Mobi.parse(root_dir) if export_mobi && epub_done && Dependency.kindlegen?
|
44
|
+
# exported << Parser::Txt.parse(root_dir) if export_txt && Dependency.html2text?
|
45
|
+
|
46
|
+
if exported.all?
|
47
|
+
color = :green
|
48
|
+
message = options[:auto] ? "exported!" : "** e-book has been exported"
|
49
|
+
|
50
|
+
if options[:open] && export_pdf
|
51
|
+
filepath = root_dir.join("output/#{File.basename(root_dir)}.pdf")
|
52
|
+
|
53
|
+
if RUBY_PLATFORM =~ /darwin/
|
54
|
+
IO.popen("open -a Preview.app '#{filepath}'").close
|
55
|
+
elsif RUBY_PLATFORM =~ /linux/
|
56
|
+
Process.detach(Process.spawn("xdg-open '#{filepath}'", :out => "/dev/null"))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Notifier.notify(
|
61
|
+
:image => Verku::ROOT.join("_templates/ebook.png"),
|
62
|
+
:title => "Verku",
|
63
|
+
:message => "Your \"#{config[:title]}\" e-book has been exported!"
|
64
|
+
)
|
65
|
+
else
|
66
|
+
color = :red
|
67
|
+
message = options[:auto] ? "could not be exported!" : "** e-book couldn't be exported"
|
68
|
+
end
|
69
|
+
|
70
|
+
ui.say message, color
|
71
|
+
end
|
72
|
+
|
73
|
+
def config
|
74
|
+
Verku.config(root_dir)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class String
|
2
|
+
def to_permalink
|
3
|
+
str = ActiveSupport::Multibyte::Chars.new(self.dup)
|
4
|
+
str = str.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s
|
5
|
+
str.gsub!(/[^-\w\d]+/xim, "-")
|
6
|
+
str.gsub!(/-+/xm, "-")
|
7
|
+
str.gsub!(/^-?(.*?)-?$/, '\1')
|
8
|
+
str.downcase!
|
9
|
+
str
|
10
|
+
end
|
11
|
+
def to_latex
|
12
|
+
require 'kramdown'
|
13
|
+
Kramdown::Document.new(self.dup).to_latex
|
14
|
+
end
|
15
|
+
def to_html
|
16
|
+
require 'kramdown'
|
17
|
+
Kramdown::Document.new(self.dup).to_html
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Verku
|
2
|
+
class Generator < Thor::Group
|
3
|
+
include Thor::Actions
|
4
|
+
def self.source_root
|
5
|
+
File.dirname(__FILE__) + "/../../templates"
|
6
|
+
end
|
7
|
+
def build_config_file
|
8
|
+
# require "uuidtools"
|
9
|
+
@title = File.basename(destination_root).gsub('-', ' ')
|
10
|
+
@name = full_name
|
11
|
+
@uuid = SecureRandom.uuid
|
12
|
+
@year = Date.today.year
|
13
|
+
template "config.erb", "_verku.yml"
|
14
|
+
template "readme.erb", "README.md"
|
15
|
+
end
|
16
|
+
def copy_templates
|
17
|
+
copy_file "pdf/layout.erb", "_templates/pdf/layout.erb"
|
18
|
+
copy_file "merovex-logo.png", "_images/logo.png"
|
19
|
+
|
20
|
+
copy_file "html/layout.erb", "_templates/html/layout.erb"
|
21
|
+
copy_file "html/thanks.erb", "_templates/html/thanks.erb"
|
22
|
+
copy_file "html/copyright.erb", "_templates/html/copyright.erb"
|
23
|
+
copy_file "html/user.css", "_templates/html/user.css"
|
24
|
+
copy_file "html/layout.css", "_templates/html/layout.css"
|
25
|
+
copy_file "html/syntax.css", "_templates/html/syntax.css"
|
26
|
+
|
27
|
+
copy_file "epub/back.erb", "_templates/epub/back.html"
|
28
|
+
copy_file "epub/copyright.erb", "_templates/epub/copyright.erb"
|
29
|
+
copy_file "epub/cover.erb", "_templates/epub/cover.erb"
|
30
|
+
copy_file "epub/cover.html", "_templates/epub/cover.html"
|
31
|
+
copy_file "epub/page.erb", "_templates/epub/page.erb"
|
32
|
+
copy_file "epub/user.css", "_templates/epub/user.css"
|
33
|
+
|
34
|
+
copy_file "cover.jpg", "_images/cover.jpg"
|
35
|
+
copy_file "rakefile.rb", "Rakefile"
|
36
|
+
copy_file "extras.tex", "_extras/dedications.tex"
|
37
|
+
end
|
38
|
+
def copy_sample_text
|
39
|
+
directory "text", "text"
|
40
|
+
end
|
41
|
+
def create_directories
|
42
|
+
empty_directory "builds"
|
43
|
+
empty_directory "docs"
|
44
|
+
empty_directory "_images"
|
45
|
+
end
|
46
|
+
private
|
47
|
+
# Retrieve user's name using finger.
|
48
|
+
# Defaults to <tt>John Doe</tt>.
|
49
|
+
#
|
50
|
+
def full_name
|
51
|
+
name = `finger $USER 2> /dev/null | grep Login | colrm 1 46`.chomp
|
52
|
+
name.empty? ? "John Doe" : name.squish
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/verku/parser.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Verku
|
4
|
+
module Parser
|
5
|
+
autoload :HTML , "verku/parser/html"
|
6
|
+
autoload :PDF , "verku/parser/pdf"
|
7
|
+
autoload :Epub , "verku/parser/epub"
|
8
|
+
autoload :Mobi , "verku/parser/mobi"
|
9
|
+
# autoload :Txt , "verku/parser/txt"
|
10
|
+
|
11
|
+
class Base
|
12
|
+
# The e-book directory.
|
13
|
+
#
|
14
|
+
attr_accessor :root_dir
|
15
|
+
|
16
|
+
# Where the text files are stored.
|
17
|
+
#
|
18
|
+
attr_accessor :source
|
19
|
+
|
20
|
+
def self.parse(root_dir)
|
21
|
+
new(root_dir).parse
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(root_dir)
|
25
|
+
@root_dir = Pathname.new(root_dir)
|
26
|
+
@source = root_dir.join("text")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return directory's basename.
|
30
|
+
#
|
31
|
+
def name
|
32
|
+
File.basename(root_dir)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return the configuration file.
|
36
|
+
#
|
37
|
+
def config
|
38
|
+
Verku.config(root_dir)
|
39
|
+
end
|
40
|
+
def entries
|
41
|
+
return @entries unless @entries.nil?
|
42
|
+
files = Dir["text/**/*.tex"]
|
43
|
+
@entries = {}
|
44
|
+
files.each do |f|
|
45
|
+
k = File.dirname(f)
|
46
|
+
k.gsub!('text/','')
|
47
|
+
@entries[k] = [] if @entries[k].nil?
|
48
|
+
@entries[k] << f
|
49
|
+
end
|
50
|
+
return @entries
|
51
|
+
end
|
52
|
+
def render_template(file, locals = {})
|
53
|
+
ERB.new(File.read(file)).result OpenStruct.new(locals).instance_eval{ binding }
|
54
|
+
end
|
55
|
+
def read_content(file)
|
56
|
+
content = File.read(file)
|
57
|
+
data = {}
|
58
|
+
begin
|
59
|
+
# YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
60
|
+
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
61
|
+
# content = "\n#{$'}\n"
|
62
|
+
content = $POSTMATCH
|
63
|
+
data = SafeYAML.load($1)
|
64
|
+
# data = YAML.load($1)
|
65
|
+
end
|
66
|
+
return [content, data]
|
67
|
+
rescue SyntaxError => e
|
68
|
+
puts "YAML Exception reading #{path}: #{e.message}"
|
69
|
+
rescue Exception => e
|
70
|
+
puts "Error reading file #{path}: #{e.message}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
def spawn_command(cmd)
|
74
|
+
begin
|
75
|
+
stdout_and_stderr, status = Open3.capture2e(*cmd)
|
76
|
+
rescue Errno::ENOENT => e
|
77
|
+
puts e.message
|
78
|
+
else
|
79
|
+
puts stdout_and_stderr unless status.success?
|
80
|
+
status.success?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module Verku
|
3
|
+
module Parser
|
4
|
+
class Epub < Base
|
5
|
+
def sections
|
6
|
+
@sections ||= html.css("div.chapter").each_with_index.map do |chapter, index|
|
7
|
+
OpenStruct.new({
|
8
|
+
:index => index,
|
9
|
+
:filename => "section_#{index}.html",
|
10
|
+
:filepath => tmp_dir.join("section_#{index}.html").to_s,
|
11
|
+
:html => Nokogiri::HTML(chapter.inner_html)
|
12
|
+
})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def epub; @epub ||= EeePub.make ;end
|
16
|
+
def html; @html ||= Nokogiri::HTML(html_path.read); end
|
17
|
+
def parse
|
18
|
+
puts "-- Exporting EPUB"
|
19
|
+
epub.title config["title"]
|
20
|
+
epub.language config["language"]
|
21
|
+
epub.creator config["authors"].to_sentence
|
22
|
+
epub.publisher config["publisher"]
|
23
|
+
epub.date config["published_at"]
|
24
|
+
epub.uid config["uid"]
|
25
|
+
epub.identifier config["identifier"]["id"], :scheme => config["identifier"]["type"]
|
26
|
+
if cover_image.nil?
|
27
|
+
puts " - Consider adding a cover images in /images."
|
28
|
+
else
|
29
|
+
epub.cover cover_image
|
30
|
+
end
|
31
|
+
write_coverpage!
|
32
|
+
write_thankspage!
|
33
|
+
write_copyright!
|
34
|
+
write_sections!
|
35
|
+
write_backpage!
|
36
|
+
write_toc!
|
37
|
+
epub.files cover_page + thanks_page + sections.map(&:filepath) + back_page + copyright_page + assets
|
38
|
+
epub.nav navigation
|
39
|
+
|
40
|
+
epub.save(epub_path)
|
41
|
+
true
|
42
|
+
rescue Exception
|
43
|
+
p $!, $@
|
44
|
+
false
|
45
|
+
end
|
46
|
+
def back_page
|
47
|
+
return Dir[back_path] if File.exist?(back_path)
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
def cover_page
|
51
|
+
Dir[cover_path]
|
52
|
+
end
|
53
|
+
def copyright_page
|
54
|
+
Dir[copyright_path]
|
55
|
+
end
|
56
|
+
def thanks_page
|
57
|
+
Dir[thanks_path]
|
58
|
+
end
|
59
|
+
def write_backpage!
|
60
|
+
contents = render_template(root_dir.join("_templates/epub/back.html"), config)
|
61
|
+
File.open(back_path,"w") do |file|
|
62
|
+
file << contents
|
63
|
+
end
|
64
|
+
end
|
65
|
+
def write_coverpage!
|
66
|
+
contents = render_template(root_dir.join("_templates/epub/cover.html"), config)
|
67
|
+
puts "Writing cover page. #{cover_path}"
|
68
|
+
#
|
69
|
+
# raise File.dirname(cover_path).inspect
|
70
|
+
FileUtils.mkdir_p(File.dirname(cover_path))
|
71
|
+
File.open(cover_path,"w") do |file|
|
72
|
+
file << contents
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def write_copyright!
|
76
|
+
contents = render_template(root_dir.join("_templates/html/copyright.erb"), config)
|
77
|
+
# File.open('help.html','w').write(contents)
|
78
|
+
FileUtils.mkdir_p(File.dirname(copyright_path))
|
79
|
+
File.open(copyright_path,"w") do |file|
|
80
|
+
file << contents
|
81
|
+
end
|
82
|
+
end
|
83
|
+
def write_thankspage!
|
84
|
+
contents = render_template(root_dir.join("_templates/html/thanks.erb"), config)
|
85
|
+
# File.open('help.html','w').write(contents)
|
86
|
+
FileUtils.mkdir_p(File.dirname(thanks_path))
|
87
|
+
File.open(thanks_path,"w") do |file|
|
88
|
+
file << contents
|
89
|
+
end
|
90
|
+
end
|
91
|
+
def write_toc!
|
92
|
+
toc = TOC::Epub.new(navigation)
|
93
|
+
FileUtils.mkdir_p(File.dirname(toc_path))
|
94
|
+
File.open(toc_path, "w") do |file|
|
95
|
+
file << toc.to_html
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def write_sections!
|
100
|
+
# First we need to get all ids, which are used as
|
101
|
+
# the anchor target.
|
102
|
+
links = sections.inject({}) do |buffer, section|
|
103
|
+
section.html.css("[id]").each do |element|
|
104
|
+
anchor = "##{element["id"]}"
|
105
|
+
buffer[anchor] = "#{section.filename}#{anchor}"
|
106
|
+
end
|
107
|
+
|
108
|
+
buffer
|
109
|
+
end
|
110
|
+
|
111
|
+
# Then we can normalize all links and
|
112
|
+
# manipulate other paths.
|
113
|
+
#
|
114
|
+
sections.each do |section|
|
115
|
+
section.html.css("a[href^='#']").each do |link|
|
116
|
+
href = link["href"]
|
117
|
+
link.set_attribute("href", links.fetch(href, href))
|
118
|
+
end
|
119
|
+
|
120
|
+
# Replace all srcs.
|
121
|
+
#
|
122
|
+
section.html.css("[src]").each do |element|
|
123
|
+
src = File.basename(element["src"]).gsub(/\.svg$/, ".png")
|
124
|
+
element.set_attribute("src", src)
|
125
|
+
element.set_attribute("alt", "")
|
126
|
+
element.node_name = "img"
|
127
|
+
end
|
128
|
+
|
129
|
+
FileUtils.mkdir_p(tmp_dir)
|
130
|
+
File.open(section.filepath, "w") do |file|
|
131
|
+
body = section.html.css("body").to_xhtml.gsub(%r[<body>(.*?)</body>]m, "\\1")
|
132
|
+
file << render_chapter(body)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
def render_chapter(content)
|
137
|
+
locals = config.merge(:content => content)
|
138
|
+
render_template(template_path, locals)
|
139
|
+
end
|
140
|
+
def assets
|
141
|
+
@assets ||= begin
|
142
|
+
assets = Dir[root_dir.join("_templates/epub/*.css")]
|
143
|
+
assets += Dir[root_dir.join("images/**/*.{jpg,png,gif}")]
|
144
|
+
assets
|
145
|
+
end
|
146
|
+
end
|
147
|
+
def cover_image
|
148
|
+
path = Dir[root_dir.join("images/cover-#{name}.{jpg,png,gif}").to_s.downcase].first
|
149
|
+
return File.basename(path) if path && File.exist?(path)
|
150
|
+
end
|
151
|
+
def navigation
|
152
|
+
sections.map do |section| {
|
153
|
+
:label => section.html.css("h2:first-of-type").text,
|
154
|
+
:content => section.filename
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
def template_path
|
159
|
+
root_dir.join("_templates/epub/page.erb")
|
160
|
+
end
|
161
|
+
def html_path
|
162
|
+
root_dir.join("builds/#{name}.html")
|
163
|
+
end
|
164
|
+
def epub_path
|
165
|
+
root_dir.join("builds/#{name}.epub")
|
166
|
+
end
|
167
|
+
def tmp_dir
|
168
|
+
root_dir.join("builds/tmp")
|
169
|
+
end
|
170
|
+
def cover_path
|
171
|
+
tmp_dir.join("cover.html")
|
172
|
+
end
|
173
|
+
def thanks_path
|
174
|
+
tmp_dir.join("thanks.html")
|
175
|
+
end
|
176
|
+
def back_path
|
177
|
+
tmp_dir.join("back.html")
|
178
|
+
end
|
179
|
+
def copyright_path
|
180
|
+
tmp_dir.join("copyright.html")
|
181
|
+
end
|
182
|
+
def toc_path
|
183
|
+
tmp_dir.join("toc.html")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|