verku 0.8.0.p
Sign up to get free protection for your applications and to get access to all the features.
- 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
|