aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Choi <dhchoi@gmail.com>2012-11-28 11:25:32 -0500
committerDaniel Choi <dhchoi@gmail.com>2012-12-01 18:08:10 -0500
commite8fe1d1a20e1e2c142002b47795a81b8f1fa7d42 (patch)
treecfe142cf4904d23f75cb218c72ef9045379d0960
parentdaa7b4e2f0f045af0dbecc6f531976fe68132cab (diff)
downloadrails-e8fe1d1a20e1e2c142002b47795a81b8f1fa7d42.tar.gz
rails-e8fe1d1a20e1e2c142002b47795a81b8f1fa7d42.tar.bz2
rails-e8fe1d1a20e1e2c142002b47795a81b8f1fa7d42.zip
Add periodical-style TOC and navigation to Kindle version of guides
-rw-r--r--guides/Rakefile6
-rw-r--r--guides/rails_guides/generator.rb6
-rw-r--r--guides/rails_guides/kindle.rb119
-rw-r--r--guides/source/kindle/rails_guides.opf.erb2
4 files changed, 128 insertions, 5 deletions
diff --git a/guides/Rakefile b/guides/Rakefile
index 7881a3d9b3..d6dd950d01 100644
--- a/guides/Rakefile
+++ b/guides/Rakefile
@@ -13,6 +13,12 @@ namespace :guides do
desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/kindlepublishing"
task :kindle do
+ unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/
+ abort "Please `gem install kindlerb`"
+ end
+ unless `convert` =~ /convert/
+ abort "Please install ImageMagick`"
+ end
ENV['KINDLE'] = '1'
Rake::Task['guides:generate:html'].invoke
end
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index 3b124ef236..579697ee53 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -112,11 +112,9 @@ module RailsGuides
end
def generate_mobi
- opf = "#{output_dir}/rails_guides.opf"
+ require 'rails_guides/kindle'
out = "#{output_dir}/kindlegen.out"
-
- system "kindlegen #{opf} -o #{mobi} > #{out} 2>&1"
- puts "Guides compiled as Kindle book to #{mobi}"
+ Kindle.generate(output_dir, mobi, out)
puts "(kindlegen log at #{out})."
end
diff --git a/guides/rails_guides/kindle.rb b/guides/rails_guides/kindle.rb
new file mode 100644
index 0000000000..09eecd5634
--- /dev/null
+++ b/guides/rails_guides/kindle.rb
@@ -0,0 +1,119 @@
+#!/usr/bin/env ruby
+
+unless `which kindlerb`
+ abort "Please gem install kindlerb"
+end
+
+require 'nokogiri'
+require 'fileutils'
+require 'yaml'
+require 'date'
+
+module Kindle
+ extend self
+
+ def generate(output_dir, mobi_outfile, logfile)
+ output_dir = File.absolute_path(output_dir)
+ Dir.chdir output_dir do
+ puts "=> Using output dir: #{output_dir}"
+ puts "=> Arranging html pages in document order"
+ toc = File.read("toc.ncx")
+ doc = Nokogiri::XML(toc).xpath("//ncx:content", 'ncx' => "http://www.daisy.org/z3986/2005/ncx/")
+ html_pages = doc.select {|c| c[:src]}.map {|c| c[:src]}.uniq
+
+ generate_front_matter(html_pages)
+
+ generate_sections(html_pages)
+
+ generate_document_metadata(mobi_outfile)
+
+ puts "Creating MOBI document with kindlegen. This make take a while."
+ cmd = "kindlerb . > #{File.absolute_path logfile} 2>&1"
+ puts cmd
+ system(cmd)
+ puts "MOBI document generated at #{File.expand_path(mobi_outfile, output_dir)}"
+ end
+ end
+
+ def generate_front_matter(html_pages)
+ frontmatter = []
+ html_pages.delete_if {|x|
+ if x =~ /(toc|welcome|credits|copyright).html/
+ frontmatter << x unless x =~ /toc/
+ true
+ end
+ }
+ html = frontmatter.map {|x|
+ Nokogiri::HTML(File.open(x)).at("body").inner_html
+ }.join("\n")
+
+ fdoc = Nokogiri::HTML(html)
+ fdoc.search("h3").each do |h3|
+ h3.name = 'h4'
+ end
+ fdoc.search("h2").each do |h2|
+ h2.name = 'h3'
+ h2['id'] = h2.inner_text.gsub(/\s/, '-')
+ end
+ add_head_section fdoc, "Front Matter"
+ File.open("frontmatter.html",'w') {|f| f.puts fdoc.to_html}
+ html_pages.unshift "frontmatter.html"
+ end
+
+ def generate_sections(html_pages)
+ FileUtils::rm_rf("sections/")
+ html_pages.each_with_index do |page, section_idx|
+ FileUtils::mkdir_p("sections/%03d" % section_idx)
+ doc = Nokogiri::HTML(File.open(page))
+ title = doc.at("title").inner_text.gsub("Ruby on Rails Guides: ", '')
+ title = page.capitalize.gsub('.html', '') if title.strip == ''
+ File.open("sections/%03d/_section.txt" % section_idx, 'w') {|f| f.puts title}
+ doc.xpath("//h3[@id]").each_with_index do |h3,item_idx|
+ subsection = h3.inner_text
+ content = h3.xpath("./following-sibling::*").take_while {|x| x.name != "h3"}.map {|x| x.to_html}
+ item = Nokogiri::HTML(h3.to_html + content.join("\n"))
+ item_path = "sections/%03d/%03d.html" % [section_idx, item_idx]
+ add_head_section(item, subsection)
+ item.search("img").each do |img|
+ img['src'] = "#{Dir.pwd}/#{img['src']}"
+ end
+ item.xpath("//li/p").each {|p| p.swap(p.children); p.remove}
+ File.open(item_path, 'w') {|f| f.puts item.to_html}
+ end
+ end
+ end
+
+ def generate_document_metadata(mobi_outfile)
+ puts "=> Generating _document.yml"
+ x = Nokogiri::XML(File.open("rails_guides.opf")).remove_namespaces!
+ cover_jpg = "#{Dir.pwd}/images/rails_guides_kindle_cover.jpg"
+ cover_gif = cover_jpg.sub(/jpg$/, 'gif')
+ puts `convert #{cover_jpg} #{cover_gif}`
+ document = {
+ 'doc_uuid' => x.at("package")['unique-identifier'],
+ 'title' => x.at("title").inner_text.gsub(/\(.*$/, " v2"),
+ 'publisher' => x.at("publisher").inner_text,
+ 'author' => x.at("creator").inner_text,
+ 'subject' => x.at("subject").inner_text,
+ 'date' => x.at("date").inner_text,
+ 'cover' => cover_gif,
+ 'masthead' => nil,
+ 'mobi_outfile' => mobi_outfile
+ }
+ puts document.to_yaml
+ File.open("_document.yml", 'w'){|f| f.puts document.to_yaml}
+ end
+
+ def add_head_section(doc, title)
+ head = Nokogiri::XML::Node.new "head", doc
+ title_node = Nokogiri::XML::Node.new "title", doc
+ title_node.content = title
+ title_node.parent = head
+ css = Nokogiri::XML::Node.new "link", doc
+ css['rel'] = 'stylesheet'
+ css['type'] = 'text/css'
+ css['href'] = "#{Dir.pwd}/stylesheets/kindle.css"
+ css.parent = head
+ doc.at("body").before head
+ end
+end
diff --git a/guides/source/kindle/rails_guides.opf.erb b/guides/source/kindle/rails_guides.opf.erb
index 4e07664fd0..547abcbc19 100644
--- a/guides/source/kindle/rails_guides.opf.erb
+++ b/guides/source/kindle/rails_guides.opf.erb
@@ -32,7 +32,7 @@
<item id="toc" media-type="application/x-dtbncx+xml" href="toc.ncx" />
- <item id="cover" media-type="image/jpeg" href="images/rails_guides_kindle_cover.jpg"/>
+ <item id="cover" media-type="image/jpg" href="images/rails_guides_kindle_cover.jpg"/>
</manifest>
<spine toc="toc">