class DocBook::Epub

Constants

CALLOUT_EXT
CALLOUT_FULL_PATH
CALLOUT_LIMIT
CALLOUT_PATH
CHECKER
META_DIR
MIMETYPE
OEBPS_DIR
OUTPUT_DIR
STYLESHEET
XSLT_PROCESSOR
ZIPPER

Attributes

output_dir[R]

Public Class Methods

invalid?(file) click to toggle source
# File lib/docbook.rb, line 48
def self.invalid?(file)
  # Obnoxiously, we can't just check for a non-zero output...
  cmd = %Q(#{CHECKER} "#{file}")
  output = `#{cmd} 2>&1`

  if $?.to_i == 0
    return false
  else  
    STDERR.puts output if $DEBUG
    return output
  end  
end
new(docbook_file, output_dir=OUTPUT_DIR, css_file=nil, customization_layer=nil, embedded_fonts=[]) click to toggle source
# File lib/docbook.rb, line 22
def initialize(docbook_file, output_dir=OUTPUT_DIR, css_file=nil, customization_layer=nil, embedded_fonts=[])
  @docbook_file = docbook_file
  @output_dir = output_dir
  @meta_dir  = File.join(@output_dir, META_DIR)
  @oebps_dir = File.join(@output_dir, OEBPS_DIR)
  @css_file = css_file ? File.expand_path(css_file) : css_file
  @embedded_fonts = embedded_fonts
  @to_delete = []
  
  if customization_layer
    @stylesheet = File.expand_path(customization_layer)
  else
    @stylesheet = STYLESHEET
  end

  unless File.exist?(@docbook_file)
    raise ArgumentError.new("File #{@docbook_file} does not exist")
  end
end

Public Instance Methods

render_to_file(output_file, verbose=false) click to toggle source
# File lib/docbook.rb, line 42
def render_to_file(output_file, verbose=false)
  render_to_epub(output_file, verbose)
  bundle_epub(output_file, verbose)
  cleanup_files(@to_delete)
end

Private Instance Methods

bundle_epub(output_file, verbose) click to toggle source
# File lib/docbook.rb, line 96
def bundle_epub(output_file, verbose)  

  quiet = verbose ? "" : "-q"
  mimetype_filename = write_mimetype()
  meta   = File.basename(@meta_dir)
  oebps  = File.basename(@oebps_dir)
  images = copy_images()
  csses  = copy_csses()
  fonts  = copy_fonts()
  callouts = copy_callouts()
  # zip -X -r ../book.epub mimetype META-INF OEBPS
  # Double-quote stylesheet & file to help Windows cmd.exe
  zip_cmd = %Q(cd "#{@output_dir}" &&  #{ZIPPER} #{quiet} -X -r  "#{File.expand_path(output_file)}" "#{mimetype_filename}" "#{meta}" "#{oebps}")
  puts zip_cmd if $DEBUG
  success = system(zip_cmd)
  raise "Could not bundle into .epub file to #{output_file}" unless success
end
cleanup_files(file_list) click to toggle source
# File lib/docbook.rb, line 195
def cleanup_files(file_list)
  file_list.flatten.each {|f|
    # Yikes
    FileUtils.rm_r(f, :force => true )
  }  
end
collapse_docbook() click to toggle source

Input must be collapsed because REXML couldn't find figures in files that were XIncluded or added by ENTITY

http://sourceforge.net/tracker/?func=detail&aid=2750442&group_id=21935&atid=373747
# File lib/docbook.rb, line 117
def collapse_docbook
  # Double-quote stylesheet & file to help Windows cmd.exe
  collapsed_file = File.join(File.expand_path(File.dirname(@docbook_file)), 
                             '.collapsed.' + File.basename(@docbook_file))
  entity_collapse_command = %Q(xmllint --loaddtd --noent -o "#{collapsed_file}" "#{@docbook_file}")
  entity_success = system(entity_collapse_command)
  raise "Could not collapse named entites in #{@docbook_file}" unless entity_success

  xinclude_collapse_command = %Q(xmllint --xinclude -o "#{collapsed_file}" "#{collapsed_file}")
  xinclude_success = system(xinclude_collapse_command)
  raise "Could not collapse XIncludes in #{@docbook_file}" unless xinclude_success

  @to_delete << collapsed_file
  return collapsed_file
end
copy_callouts() click to toggle source
# File lib/docbook.rb, line 133
def copy_callouts
  new_callout_images = []
  if has_callouts?
    calloutglob = "#{CALLOUT_FULL_PATH}/*#{CALLOUT_EXT}"
    Dir.glob(calloutglob).each {|img|
      img_new_filename = File.join(@oebps_dir, CALLOUT_PATH, File.basename(img))

      # TODO: What to rescue for these two?
      FileUtils.mkdir_p(File.dirname(img_new_filename)) 
      FileUtils.cp(img, img_new_filename)
      @to_delete << img_new_filename
      new_callout_images << img
    }  
  end  
  return new_callout_images
end
copy_csses() click to toggle source
# File lib/docbook.rb, line 160
def copy_csses
  if @css_file 
    css_new_filename = File.join(@oebps_dir, File.basename(@css_file))
    FileUtils.cp(@css_file, css_new_filename)
  end
end
copy_fonts() click to toggle source
# File lib/docbook.rb, line 150
def copy_fonts
  new_fonts = []
  @embedded_fonts.each {|font_file|
    font_new_filename = File.join(@oebps_dir, File.basename(font_file))
    FileUtils.cp(font_file, font_new_filename)
    new_fonts << font_file
  }
  return new_fonts
end
copy_images() click to toggle source
# File lib/docbook.rb, line 167
def copy_images
  image_references = get_image_refs()
  new_images = []
  image_references.each {|img|
    # TODO: It'd be cooler if we had a filetype lookup rather than just
    # extension
    if img =~ /\.(svg|png|gif|jpe?g|xml)/i
      img_new_filename = File.join(@oebps_dir, img)
      img_full = File.join(File.expand_path(File.dirname(@docbook_file)), img)

      # TODO: What to rescue for these two?
      FileUtils.mkdir_p(File.dirname(img_new_filename)) 
      puts(img_full + ": " + img_new_filename) if $DEBUG
      FileUtils.cp(img_full, img_new_filename)
      @to_delete << img_new_filename
      new_images << img_full
    end
  }  
  return new_images
end
get_image_refs() click to toggle source

Returns an Array of all of the (image) @filerefs in a document

# File lib/docbook.rb, line 203
def get_image_refs
  parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
  image_refs = []
  while parser.has_next?
    el = parser.pull
    if el.start_element? and (el[0] == "imagedata" or el[0] == "graphic")
      image_refs << el[1]['fileref'] 
    end  
  end
  return image_refs.uniq
end
has_callouts?() click to toggle source

Returns true if the document has code callouts

# File lib/docbook.rb, line 216
def has_callouts?
  parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
  while parser.has_next?
    el = parser.pull
    if el.start_element? and (el[0] == "calloutlist" or el[0] == "co")
      return true
    end  
  end
  return false
end
render_to_epub(output_file, verbose) click to toggle source
# File lib/docbook.rb, line 62
def render_to_epub(output_file, verbose)  
  @collapsed_docbook_file = collapse_docbook()

  chunk_quietly =   "--stringparam chunk.quietly " + (verbose ? '0' : '1')
  callout_path =    "--stringparam callout.graphics.path #{CALLOUT_PATH}/"
  callout_limit =   "--stringparam callout.graphics.number.limit #{CALLOUT_LIMIT}"
  callout_ext =     "--stringparam callout.graphics.extension #{CALLOUT_EXT}" 
  html_stylesheet = "--stringparam html.stylesheet #{File.basename(@css_file)}" if @css_file
  base =            "--stringparam base.dir #{OEBPS_DIR}/" 
  unless @embedded_fonts.empty? 
    embedded_fonts = @embedded_fonts.map {|f| File.basename(f)}.join(',')
    font =            "--stringparam epub.embedded.fonts \"#{embedded_fonts}\"" 
  end  
  meta =            "--stringparam epub.metainf.dir #{META_DIR}/" 
  oebps =           "--stringparam epub.oebps.dir #{OEBPS_DIR}/" 
  options = [chunk_quietly, 
             callout_path, 
             callout_limit, 
             callout_ext, 
             base, 
             font, 
             meta, 
             oebps, 
             html_stylesheet,
            ].join(" ")
  # Double-quote stylesheet & file to help Windows cmd.exe
  db2epub_cmd = %Q(cd "#{@output_dir}" && #{XSLT_PROCESSOR} #{options} "#{@stylesheet}" "#{@collapsed_docbook_file}")
  STDERR.puts db2epub_cmd if $DEBUG
  success = system(db2epub_cmd)
  raise "Could not render as .epub to #{output_file} (#{db2epub_cmd})" unless success
  @to_delete << Dir["#{@meta_dir}/*"]
  @to_delete << Dir["#{@oebps_dir}/*"]
end
write_mimetype() click to toggle source
# File lib/docbook.rb, line 188
def write_mimetype
  mimetype_filename = File.join(@output_dir, "mimetype")
  File.open(mimetype_filename, "w") {|f| f.print MIMETYPE}
  @to_delete << mimetype_filename
  return File.basename(mimetype_filename)
end