module GitScribe::Generate

Public Instance Methods

do_docbook() click to toggle source
# File lib/git-scribe/generate.rb, line 30
def do_docbook
  return true if @done['docbook']
  info "GENERATING DOCBOOK"

  if ex("asciidoc -b docbook --doctype book -v #{BOOK_FILE}")
    @done['docbook'] = true
    'book.xml'
  end
end
do_ebook() click to toggle source
# File lib/git-scribe/generate.rb, line 107
def do_ebook
  do_pdf
  do_epub
  do_mobi
  zip_ebook
end
do_epub() click to toggle source
# File lib/git-scribe/generate.rb, line 74
def do_epub
  return true if @done['epub']

  info "GENERATING EPUB"

  generate_docinfo
  # TODO: look for custom stylesheets
  cmd = "#{a2x_wss('epub')} -a docinfo -k -v #{BOOK_FILE}"
  return false unless ex(cmd)

  @done['epub'] = true
end
do_html() click to toggle source
# File lib/git-scribe/generate.rb, line 114
def do_html
  return true if @done['html']
  info "GENERATING HTML"

  # TODO: look for custom stylesheets
  cmd = "asciidoc -a scriptsdir='javascripts' -a linkcss -a stylesdir='stylesheets' -a theme=scribe #{BOOK_FILE}"
  return false unless ex(cmd)

  @done['html'] = true
end
do_mobi() click to toggle source
# File lib/git-scribe/generate.rb, line 87
def do_mobi
  return true if @done['mobi']

  do_epub

  info "GENERATING MOBI"

  decorate_epub_for_mobi

  cmd = "kindlegen -verbose book_for_mobi.epub -o book.mobi"
  return false unless ex(cmd)

  cmd = @wd +  '/scripts/post-mobi.sh'
  if File.exists?(cmd) && File.executable?(cmd)
    return false unless ex(cmd)
  end

  @done['mobi'] = true
end
do_pdf() click to toggle source
# File lib/git-scribe/generate.rb, line 40
def do_pdf
  return true if @done['pdf']

  info "GENERATING PDF"
  do_docbook

  @decorate.docbook

  # TODO: start chapters on the recto page
  # (initial.page.number=auto-odd? break.before=page-even?)
  strparams = {
    'callout.graphics' => 1,
    'navig.graphics' => 1,
    'admon.textlabel' => 1,
    'admon.graphics' => 1,
    #'page.width' => '7.5in',
    #'page.height' => '9in',
    'body.font.family' => "'WenQuanYi Zen Hei'",
    'title.font.family' => "'WenQuanYi Micro Hei'",
    'monospace.font.family' => "'Liberation Mono'"
  }
  param = strparams.map { |k, v| "--stringparam #{k} #{v}" }.join(' ')
  cmd = "xsltproc  --nonet #{param} --output #{local('book.fo')} #{base('docbook-xsl/fo.xsl')} #{local('book.xml')}"
  ex(cmd)

  @decorate.fop

  cmd = "fop -c #{base('docbook-xsl/fop.xconf')} -fo #{local('book.fo')} -pdf #{local('book.pdf')}"
  ex(cmd)

  return false unless $?.exitstatus == 0
  @done['pdf'] = true
end
do_site() click to toggle source
# File lib/git-scribe/generate.rb, line 125
def do_site
  info "GENERATING SITE"

  prepare_output_dir("site")
  Dir.chdir("site") do
    ex("asciidoc -b docbook #{BOOK_FILE}")
    xsldir = base('docbook-xsl/xhtml')
    ex("xsltproc --stringparam html.stylesheet stylesheets/scribe.css --nonet #{xsldir}/chunk.xsl book.xml")

    clean_site
  end
end
gen(args = []) click to toggle source

generate the new media

# File lib/git-scribe/generate.rb, line 4
def gen(args = [])
  @done = {}  # what we've generated already
  @remove_when_done = []
  @wd = Dir.getwd

  type = first_arg(args) || 'all'
  prepare_output_dir

  types = type == 'all' ? OUTPUT_TYPES : [type]

  ret = false
  output = []
  Dir.chdir("output") do
    types.each do |out_type|
      call = 'do_' + out_type
      if self.respond_to? call
        ret = self.send call
      else
        die "NOT A THING: #{call}"
      end
    end
    clean_up
    ret
  end
end

Private Instance Methods

a2x(type) click to toggle source
# File lib/git-scribe/generate.rb, line 179
def a2x(type)
  "a2x -f #{type} -d book "
end
a2x_wss(type) click to toggle source
# File lib/git-scribe/generate.rb, line 175
def a2x_wss(type)
  a2x(type) + " --stylesheet=stylesheets/scribe.css"
end
add_epub_etype() click to toggle source
# File lib/git-scribe/generate.rb, line 192
def add_epub_etype
  Dir.chdir('book.epub.d') do
    FileUtils.cp 'mimetype', 'etype'
  end
end
add_epub_toc() click to toggle source
# File lib/git-scribe/generate.rb, line 198
def add_epub_toc
  build_html_toc
  add_html_toc_to_opf
end
add_html_toc_to_opf() click to toggle source
# File lib/git-scribe/generate.rb, line 233
def add_html_toc_to_opf
  Dir.chdir('book.epub.d/OEBPS') do
    opf = File.read('content.opf')
    opf = add_html_toc_to_opf_manifest(opf)
    opf = add_html_toc_to_opf_spine(opf)
    opf = add_html_toc_to_opf_guide(opf)
    File.open('content.opf', 'w') do |f|
      f.puts opf
    end
  end
end
add_html_toc_to_opf_guide(opf) click to toggle source
# File lib/git-scribe/generate.rb, line 257
def add_html_toc_to_opf_guide(opf)
  opf.sub(/<\/guide>/) { |s|
    "  " +
    %q|<reference href="toc.html" type="toc" title="Table of Contents"/>| +
    "\n  " +
    s }
end
add_html_toc_to_opf_manifest(opf) click to toggle source
# File lib/git-scribe/generate.rb, line 245
def add_html_toc_to_opf_manifest(opf)
  opf.sub(/<item[^>]+id="ncxtoc".+?>/) { |s|
    s + "\n" +
      %q|    <item id="htmltoc" | +
                %q|media-type="application/xhtml+xml" | +
                %q|href="toc.html"/>| }
end
add_html_toc_to_opf_spine(opf) click to toggle source
# File lib/git-scribe/generate.rb, line 252
def add_html_toc_to_opf_spine(opf)
  opf.sub(/<itemref idref="cover".+?>/) { |s|
    s + "\n" +
      %q|    <itemref idref="htmltoc" linear="no"/>| }
end
book_title() click to toggle source
# File lib/git-scribe/generate.rb, line 340
def book_title
  do_html

  source = File.read("book.html")
  t = /\<title>(.*?)<\/title\>/.match(source)

  t ? t[1] : 'Title'
end
build_html_toc() click to toggle source
# File lib/git-scribe/generate.rb, line 203
    def build_html_toc
      Dir.chdir('book.epub.d/OEBPS') do
        ncx = File.read('toc.ncx')
        titles = ncx.scan(%r{^          <ncx:text>(.+?)</ncx:text>}m).flatten
        urls = ncx.scan(%r{^        <ncx:content src="(.+?)"/>}m).flatten

        titles_and_urls = titles.zip(urls).reject { |entry|
          entry[1].match(/^pr\d+.html$/) &&
          !entry[0].match(/introduction/i)
        }

        File.open("toc.html", 'w') do |f|
          f.puts('<?xml version="1.0" encoding="UTF-8"?>')
          f.puts('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Table of Contents</title></head><body>')
          titles_and_urls.each do |entry|
            f.puts <<_EOM
<div>
<span class="chapter">
<a href="#{entry[1]}">#{entry[0]}</a>
</span>
</div>
_EOM
          end
          f.puts('</body></html>')
        end
      end
    end
clean_epub_css() click to toggle source
# File lib/git-scribe/generate.rb, line 308
def clean_epub_css
  Dir.chdir('book.epub.d/OEBPS/stylesheets') do
    content = File.read('scribe.css')
    File.open('scribe.css', 'w') do |f|
      f.write content.sub(/^pre[^}]+/m) { |s|
        s + "  font-size: 8px;\n"
      }
    end
  end
end
clean_epub_html() click to toggle source
# File lib/git-scribe/generate.rb, line 293
def clean_epub_html
  Dir.glob('book.epub.d/OEBPS/*.html').
    each { |file| clean_html(file) }
end
clean_html(file) click to toggle source
# File lib/git-scribe/generate.rb, line 298
def clean_html(file)
  content = File.read(file)
  File.open(file, 'w') do |f|
    f.write content.
      gsub(%r"<li(.*?)>\s*(.+?)\s*</li>"m, '<li\1>\2</li>').
      gsub(%r"<li(.*?)>\s+(.+?)\s*</li>"m, '<li\1>\2</li>').
      gsub(%r'<h([123] class="title".*?)><a (id=".+?")[></a]+>'m, '<h\1 \2>')
  end
end
clean_site() click to toggle source
# File lib/git-scribe/generate.rb, line 349
def clean_site
  source = File.read('index.html')
  html = Nokogiri::HTML.parse(source, nil, 'utf-8')

  sections = []
  c = -1

  # each chapter
  html.css('.toc > dl').each do |section|
    section.children.each do |item|
      if item.name == 'dt' # section
        c += 1
        sections[c] ||= {'number' => c}
        link = item.css('a').first
        sections[c]['title'] = title = link.text
        sections[c]['href'] = href = link['href']
        clean_title = title.downcase.gsub(/[^a-z0-9\-_]+/, '_') + '.html'
        sections[c]['link'] = clean_title
        if href[0, 10] == 'index.html'
          sections[c]['link'] = 'title.html'
        end
        sections[c]['sub'] = []
      end
      if item.name == 'dd' # subsection
        item.css('dt').each do |sub|
          link = sub.css('a').first
          data = {}
          data['title'] = title = link.text
          data['href'] = href = link['href']
          data['link'] = sections[c]['link'] + '#' + href.split('#').last
          sections[c]['sub'] << data
        end
      end
    end
  end

  book_title = html.css('head > title').text
  content = html.css('body > div')[1]
  content.css('.toc').first.remove
  content = content.inner_html

  sections.each do |s|
    content.gsub!(s['href'], s['link'])
  end

  template_dir = File.join(SCRIBE_ROOT, 'site', 'default')

  # copy the template files in
  files = Dir.glob(template_dir + '/*')
  FileUtils.cp_r files, '.'

  index_template = liquid_template('index.html')
  page_template = liquid_template('page.html')

  # write the index page
  main_data = {
    'book_title' => book_title,
    'sections' => sections
  }
  File.open('index.html', 'w+') do |f|
    f.puts index_template.render( main_data )
  end

  # write the title page
  File.open('title.html', 'w+') do |f|
    data = {
      'title' => sections.first['title'],
      'sub' => sections.first['sub'],
      'prev' => {'link' => 'index.html', 'title' => "Main"},
      'home' => {'link' => 'index.html', 'title' => "Home"},
      'next' => sections[1],
      'content' => content
    }
    data.merge!(main_data)
    f.puts page_template.render( data )
  end

  # write the other pages
  sections.each_with_index do |section, i|

    if i > 0 # skip title page
      source = File.read(section['href'])
      html = Nokogiri::HTML.parse(source, nil, 'utf-8')

      content = html.css('body > div')[1].to_html
      sections.each do |s|
        content.gsub!(s['href'], s['link'])
      end

      File.open(section['link'], 'w+') do |f|
        next_section = nil
        if i <= sections.size
          next_section = sections[i+1]
        end
        data = {
          'title' => section['title'],
          'sub' => section['sub'],
          'prev' => sections[i-1],
          'home' => {'link' => 'index.html', 'title' => "Home"},
          'next' => next_section,
          'content' => content
        }
        data.merge!(main_data)
        f.puts page_template.render( data )
      end
      #File.unlink(section['href'])

      info i
      info section['title']
      info section['href']
      info section['link']
    end

    #File.unlink
  end
  sections
end
clean_up() click to toggle source
# File lib/git-scribe/generate.rb, line 154
def clean_up
  FileUtils.rm Dir.glob('**/*.asc')
  FileUtils.rm_r @remove_when_done
end
decorate_epub_for_mobi() click to toggle source
# File lib/git-scribe/generate.rb, line 183
def decorate_epub_for_mobi
  add_epub_etype
  add_epub_toc
  flatten_ncx
  clean_epub_html
  clean_epub_css
  zip_epub_for_mobi
end
ex(command) click to toggle source
# File lib/git-scribe/generate.rb, line 159
def ex(command)
  out = `#{command} 2>&1`
  info out
  $?.exitstatus == 0
end
flatten_ncx() click to toggle source
# File lib/git-scribe/generate.rb, line 265
def flatten_ncx
  nav_points = ncx_nav_points.map { |x| x.gsub(/^\s+/, '') }

  Dir.chdir('book.epub.d/OEBPS') do
    ncx = File.read('toc.ncx')

    File.open("toc.ncx", 'w') do |f|
      f.write ncx.sub(
        /<ncx:navMap>.+<\/ncx:navMap>/m,
        "<ncx:navMap>\n#{nav_points.join("\n")}\n</ncx:navMap>"
      )
    end
  end
end
generate_docinfo() click to toggle source
# File lib/git-scribe/generate.rb, line 165
def generate_docinfo
  docinfo_template = liquid_template('book-docinfo.xml')
  File.open('book-docinfo.xml', 'w+') do |f|
    cover  = @config['cover'] || 'images/cover.jpg'
    data = {'title'       => book_title,
            'cover_image' => cover}
    f.puts docinfo_template.render( data )
  end
end
liquid_template(file) click to toggle source
# File lib/git-scribe/generate.rb, line 468
def liquid_template(file)
  template_dir = File.join(SCRIBE_ROOT, 'site', 'default')
  Liquid::Template.parse(File.read(File.join(template_dir, file)))
end
ncx_nav_points() click to toggle source
# File lib/git-scribe/generate.rb, line 280
def ncx_nav_points
  nav_points = []

  Dir.chdir('book.epub.d/OEBPS') do
    nav_points = File.read('toc.ncx').
      scan(%r{<ncx:navPoint.+?<ncx:content src=.+?/>}m)
  end

  nav_points.
    flatten.
    map { |x| x + "\n</ncx:navPoint>" }
end
prepare_output_dir(dir='output') click to toggle source
# File lib/git-scribe/generate.rb, line 139
def prepare_output_dir(dir='output')
  FileUtils.mkdir_p(dir)
  FileUtils.cp_r "#{@wd}/book/.", dir, :remove_destination => true

  FileUtils.mkdir_p("#{dir}/stylesheets")
  FileUtils.cp_r File.join(SCRIBE_ROOT, 'stylesheets'), dir

  FileUtils.mkdir_p("#{dir}/javascripts")
  FileUtils.cp_r File.join(SCRIBE_ROOT, 'javascripts'), dir

  FileUtils.mkdir_p("#{dir}/images/icons")
  FileUtils.cp_r File.join(SCRIBE_ROOT, 'icons'),
                 "#{dir}/images"
end
zip_ebook() click to toggle source
# File lib/git-scribe/generate.rb, line 329
def zip_ebook
  file_name = book_title.downcase.gsub(/\s+/, '_')

  Dir.mkdir(file_name) rescue nil
  FileUtils.cp 'book.pdf', "#{file_name}/#{file_name}.pdf"
  FileUtils.cp 'book.epub', "#{file_name}/#{file_name}.epub"
  FileUtils.cp 'book.mobi', "#{file_name}/#{file_name}.mobi"

  ex("zip #{file_name}.zip #{file_name} -r")
end
zip_epub_for_mobi() click to toggle source
# File lib/git-scribe/generate.rb, line 319
def zip_epub_for_mobi
  @remove_when_done <<
    'book.epub.d' <<
    'book_for_mobi.epub'

  Dir.chdir('book.epub.d') do
    ex("zip ../book_for_mobi.epub . -r")
  end
end