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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +49 -0
  4. data/BUILD.md +6 -0
  5. data/Gemfile +14 -0
  6. data/Gemfile.lock +82 -0
  7. data/LICENSE.md +22 -0
  8. data/README.md +149 -0
  9. data/Rakefile +72 -0
  10. data/VERSION +1 -0
  11. data/bin/verku +5 -0
  12. data/lib/verku.rb +56 -0
  13. data/lib/verku/adapters/markdown.rb +44 -0
  14. data/lib/verku/cli.rb +93 -0
  15. data/lib/verku/dependency.rb +19 -0
  16. data/lib/verku/exporter.rb +77 -0
  17. data/lib/verku/extensions/string.rb +19 -0
  18. data/lib/verku/generator.rb +55 -0
  19. data/lib/verku/parser.rb +85 -0
  20. data/lib/verku/parser/epub.rb +187 -0
  21. data/lib/verku/parser/html.rb +245 -0
  22. data/lib/verku/parser/mobi.rb +17 -0
  23. data/lib/verku/parser/pdf.rb +54 -0
  24. data/lib/verku/parser/txt.rb +1 -0
  25. data/lib/verku/stats.rb +114 -0
  26. data/lib/verku/stream.rb +27 -0
  27. data/lib/verku/toc.rb +6 -0
  28. data/lib/verku/toc/epub.rb +41 -0
  29. data/lib/verku/toc/html.rb +78 -0
  30. data/lib/verku/version.rb +10 -0
  31. data/templates/config.erb +80 -0
  32. data/templates/cover.jpg +0 -0
  33. data/templates/dp-logo.png +0 -0
  34. data/templates/epub/back.erb +22 -0
  35. data/templates/epub/copyright.erb +46 -0
  36. data/templates/epub/cover.erb +12 -0
  37. data/templates/epub/cover.html +12 -0
  38. data/templates/epub/page.erb +15 -0
  39. data/templates/epub/user.css +500 -0
  40. data/templates/extras.tex +1 -0
  41. data/templates/html/copyright.erb +46 -0
  42. data/templates/html/layout.css +352 -0
  43. data/templates/html/layout.erb +45 -0
  44. data/templates/html/syntax.css +58 -0
  45. data/templates/html/thanks.erb +21 -0
  46. data/templates/html/user.css +7 -0
  47. data/templates/latex.erb +416 -0
  48. data/templates/merovex-logo.jpg +0 -0
  49. data/templates/merovex-logo.png +0 -0
  50. data/templates/pdf/layout.erb +418 -0
  51. data/templates/rakefile.rb +103 -0
  52. data/templates/readme.erb +3 -0
  53. data/templates/text/01-Getting-Started.md +27 -0
  54. data/templates/text/02-Creating-Chapters.md +22 -0
  55. data/templates/text/03-Generating-Output.md +2 -0
  56. data/templates/text/10-Test-Markdown.md +157 -0
  57. data/test/helper.rb +34 -0
  58. data/test/test_bookmaker.rb +7 -0
  59. data/verku.gemspec +142 -0
  60. 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
@@ -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