Skip to content

Instantly share code, notes, and snippets.

@hainuo
Last active August 29, 2015 14:27
Show Gist options
  • Save hainuo/1d9c65d44e831b493e53 to your computer and use it in GitHub Desktop.
Save hainuo/1d9c65d44e831b493e53 to your computer and use it in GitHub Desktop.
ruby 将markdown 转换为epub mobi pdf
#!/usr/bin/env ruby
# Simple script to generate EPUB book (which could be also converted
# to MOBI then) from site sources
#
# It depends on on 'eeepub' ruby gem and also you should have
# ebook-convert executable somewhere in path (or use --path argument
# for that)
#
# Usage is simple:
#
# gem install eeepub
# ./script/publish
require 'eeepub'
require 'date'
require 'fileutils'
require 'optparse'
calibre_path = '/Applications/calibre.app/Contents/MacOS'
OptionParser.new do |opts|
opts.banner = "Usage: #{ARGV[0]} [options]"
opts.on("-p", "--calibre-path PATH", "The path to ebook-convert binary, it also look in PATH env (default: #{calibre_path})") do |v|
calibre_path = v
end
opts.on_tail("-?", "--help", "Show this message") do
puts opts
exit
end
end.parse!
ENV["PATH"] = "#{ENV["PATH"]}:#{calibre_path}"
def executable?(bin)
ENV["PATH"].split(":").any? do |path|
File.executable?(File.join(path, bin))
end
end
unless executable?("ebook-convert")
abort("ebook-convert not found in PATH. Use --calibre-path option to specify custom path")
end
today = Date.today
system("jekyll build")
GUIDE_DIR = File.expand_path("../..", __FILE__)
ORIGINAL_DIR = "#{GUIDE_DIR}/_site"
TEMP_DIR = "epub_tmp"
EBOOK_DIR = File.join GUIDE_DIR, "ebooks"
FileUtils.mkdir_p("#{TEMP_DIR}/images")
FileUtils.cp(Dir["#{ORIGINAL_DIR}/images/*"], "#{TEMP_DIR}/images")
FileUtils.mkdir_p("#{TEMP_DIR}/css")
FileUtils.cp("#{ORIGINAL_DIR}/css/styles.css", "#{TEMP_DIR}/css")
File.open("#{TEMP_DIR}/css/styles.css", "a+") do |f|
f.puts <<-EOS.gsub(/^\s*/, "")
/* epub patch */
body {width:100%;}
p {width:100%;}
EOS
end
Dir["#{ORIGINAL_DIR}/*.html"].each do |f|
old = File.read(f)
new = old.gsub(%r("/css/styles.css"), %q("css/styles.css"))
File.write("#{TEMP_DIR}/#{File.basename(f)}", new)
end
navigation = [
{:label => "Preface", :content => "preface.html"},
{:label => "Introduction", :content => "intro.html"},
{:label => "Part 1: Objects", :content => "minimum.html#chapter", :nav => [
{:label => "Chapter 1: A Minimal Introduction to Ruby", :content => "minimum.html"},
{:label => "Chapter 2: Objects", :content => "object.html"},
{:label => "Chapter 3: Names and name tables", :content => "name.html"},
{:label => "Chapter 4: Classes and modules", :content => "class.html"},
{:label => "Chapter 5: Garbage collection", :content => "gc.html"},
{:label => "Chapter 6: Variables and constants", :content => "variable.html"},
{:label => "Chapter 7: Security", :content => "security.html"}
]},
{:label => "Part 2: Syntax analysis", :content => "spec.html#chapter", :nav => [
{:label => "Chapter 8: Ruby Language Details", :content => "spec.html"},
{:label => "Chapter 9: yacc crash course", :content => "yacc.html"},
{:label => "Chapter 10: Parser", :content => "parser.html"},
{:label => "Chapter 11: Finite-state scanner", :content => "contextual.html"},
{:label => "Chapter 12: Syntax tree construction", :content => "syntree.html"}
]},
{:label => "Part 3: Evaluation", :content => "evaluator.html#chapter", :nav => [
{:label => "Chapter 13: Structure of the evaluator", :content => "evaluator.html"},
{:label => "Chapter 14: Context", :content => "module.html"},
{:label => "Chapter 15: Methods", :content => "method.html"},
{:label => "Chapter 16: Blocks", :content => "iterator.html"},
{:label => "Chapter 17: Dynamic evaluation", :content => "anyeval.html"}
]},
{:label => "Part 4: Around the evaluator", :content => "load.html#chapter", :nav => [
{:label => "Chapter 18: Loading", :content => "load.html"},
{:label => "Chapter 19: Threads", :content => "thread.html"}
]},
{:label => "Final chapter: Ruby's future", :content => "fin.html"}
]
file_list = Dir["#{TEMP_DIR}/images/*"].map{|f| {f => "images"}}
file_list.push("#{TEMP_DIR}/css/styles.css" => "css")
def scan_navigation(nav, acc)
nav.each do |n|
if n[:content] && n[:content] !~ /#.*$/
acc.push("#{TEMP_DIR}/#{n[:content]}")
end
if n[:nav]
scan_navigation(n[:nav], acc)
end
end
end
scan_navigation(navigation, file_list)
epub = EeePub.make do
title 'Ruby Hacking Guide'
creator 'Minero AOKI, Vincent ISAMBART, Clifford Escobar CAOILE'
rights 'The original work is Copyright © 2002 - 2004 Minero AOKI. Translated by Vincent ISAMBART and Clifford Escobar CAOILE This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike2.5 License'
date today
identifier 'http://ruby-hacking-guide.github.io/', :scheme => 'URL', :id => 'ruby-hacking-guide.github.io'
cover "images/book_cover.jpg"
files file_list
nav navigation
end
# because the source files are using HTML5 and epub prefer XML, we
# call initial output as dirty and rely on calibre to sanitize and
# build well-formed outputs
STDERR.print("write dirty EPUB ...")
FileUtils.mkdir_p EBOOK_DIR
sha = `git rev-parse HEAD`[0..5]
base_path = "#{EBOOK_DIR}/rhg-#{today}_#{sha}"
epub.save("#{base_path}-dirty.epub")
FileUtils.rm_rf("#{TEMP_DIR}")
STDERR.puts(" ok")
# now pass dirty file to calibre to produce PDF, MOBI and EPUB
STDERR.puts("RECONVERT EPUB ...")
system("ebook-convert #{base_path}-dirty.epub #{base_path}.epub")
STDERR.puts("RECONVERT EPUB ... ok")
STDERR.print("CONVERT TO MOBI ...")
system("ebook-convert #{base_path}-dirty.epub #{base_path}.pdf")
STDERR.puts("CONVERT TO MOBI ... ok")
STDERR.print("CONVERT TO PDF ...")
system("ebook-convert #{base_path}-dirty.epub #{base_path}.mobi")
STDERR.puts("CONVERT TO PDF ... ok")
STDERR.print("remove dirty EPUB ...")
FileUtils.rm_rf("#{base_path}-dirty.epub")
STDERR.puts(" ok")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment