class Softcover::Builders::Pdf

Public Instance Methods

build!(options={}) click to toggle source
# File lib/softcover/builders/pdf.rb, line 7
def build!(options={})
  make_png_from_gif
  if manifest.markdown?
    # Build the HTML to produce PolyTeX as a side-effect,
    # then update the manifest to reduce PDF generation
    # to a previously solved problem.
    Softcover::Builders::Html.new.build!
    opts = options.merge({ source: :polytex, origin: :markdown})
    self.manifest = Softcover::BookManifest.new(opts)
  end

  write_master_latex_file(manifest)

  # Build the PolyTeX filename so it accepts both 'foo' and 'foo.tex'.
  basename = File.basename(manifest.filename, '.tex')
  book_filename = basename + '.tex'

  # In debug mode, execute `xelatex` and exit.
  if options[:debug]
    execute "#{xelatex} #{book_filename}"
    return    # only gets called in test env
  end

  polytex_filenames = manifest.pdf_chapter_filenames << book_filename
  polytex_filenames.each do |filename|
    polytex = File.read(filename)
    latex   = Polytexnic::Pipeline.new(polytex,
                                       language_labels: language_labels).
                                      to_latex
    if filename == book_filename
      latex.gsub!(/\\include{(.*?)}/) do
        "\\include{#{Softcover::Utils.tmpify(manifest, $1)}.tmp}"
      end
    end
    File.write(Softcover::Utils.tmpify(manifest, filename), latex)
  end
  write_pygments_file(:latex, Softcover::Directories::STYLES)
  copy_polytexnic_sty(options)

  # Renaming the PDF in the command is necessary because `execute`
  # below uses `exec` (except in tests, where it breaks). Since `exec`
  # causes the Ruby process to end, any Ruby code after `exec`
  # is ignored.
  # (The reason for using `exec` is so that LaTeX errors get emitted to
  # the screen rather than just hanging the process.)
  cmd = "#{pdf_cmd(book_filename, options)} " +
        "; #{rename_pdf(basename, options)}"
  # Here we use `system` when making a preview because the preview command
  # needs to run after the main PDF build.
  if options[:quiet] || options[:silent]
    silence_stream(STDERR) do
      silence { options[:preview] ? system(cmd) : execute(cmd) }
    end
  elsif options[:'find-overfull']
    silence_stream(STDERR) { execute(cmd) }
  else
    options[:preview] ? system(cmd) : execute(cmd)
  end
end

Private Instance Methods

build_pdf(book_filename, options={}) click to toggle source

Returns the command to build the PDF (once).

# File lib/softcover/builders/pdf.rb, line 95
def build_pdf(book_filename, options={})
  tmp_filename = Softcover::Utils.tmpify(manifest, book_filename)
  if options[:nonstop] || options[:silent] || options[:quiet]
    # Use nonstop to prevent LaTeX from hanging in quiet/silent mode.
    nonstop = "--interaction=nonstopmode"
    "#{xelatex} #{nonstop} #{tmp_filename} #{options[:filters]}"
        else
    "#{xelatex} #{tmp_filename} #{options[:filters]}"
  end
end
convert() click to toggle source

Returns the executable to ImageMagick's `convert` program.

# File lib/softcover/builders/pdf.rb, line 90
def convert
  @convert ||= executable(dependency_filename(:convert))
end
copy_polytexnic_sty(options) click to toggle source

Copies the style file to ensure it's always fresh.

# File lib/softcover/builders/pdf.rb, line 151
def copy_polytexnic_sty(options)
  softcover_sty  = File.join(Softcover::Directories::STYLES,
                             'softcover.sty')
  source_sty     = File.join(Softcover::Utils.template_dir(options), 
                             softcover_sty)
  FileUtils.cp source_sty, softcover_sty
end
keep_tmp_files?(options) click to toggle source

Keeps tmp files when running once, including when finding overfull. The main purpose is to keep the *.aux files around for the ToC, xrefs, etc.

# File lib/softcover/builders/pdf.rb, line 146
def keep_tmp_files?(options)
  options[:once] || options[:'find-overfull'] || Softcover.test?
end
make_png_from_gif() click to toggle source

Make a PNG for each GIF in the images/ directory.

# File lib/softcover/builders/pdf.rb, line 77
def make_png_from_gif
  gif_pattern = File.join('images', '**', '*.gif')
  gif_files = Dir.glob(gif_pattern).reject { |f| File.directory?(f) }
  gif_files.each do |gif|
    dir = File.dirname(gif)
    ext = File.extname(gif)
    img = File.basename(gif, ext)
    png = File.join(dir, "#{img}.png")
    system "#{convert} #{gif} #{png}"
  end
end
pdf_cmd(book_filename, options={}) click to toggle source

Returns the full command to build the PDF.

# File lib/softcover/builders/pdf.rb, line 107
def pdf_cmd(book_filename, options={})
  if options[:once]
    build_pdf(book_filename, options)
  elsif options[:'find-overfull']
    # The way we do things, code listings show up as "Overfull", but
    # they're actually fine, so filter them out.
    filter_out_listings = "grep -v 3.22281pt"
    # Because each chapter typically lives in a separate file, it's
    # hard to correlate Overfull line numbers with lines in the source,
    # so we use grep's -A flag to provide some context instead. Authors
    # can then use their text editors' search function to find the
    # corresponding place in the text.
    show_context = 'grep -A 3 "Overfull \\\\\\\\hbox"'
    build_pdf(book_filename,
              filters: "| #{filter_out_listings} | #{show_context}" )
  else
    # Run the command twice (to guarantee up-to-date cross-references).
    cmd = build_pdf(book_filename, options)
    "#{cmd} ; #{cmd}"
  end
end
rename_pdf(basename, options={}) click to toggle source

Returns the command to rename the temp PDF. The purpose is to match the original filename. For example, foo_bar.tex should produce foo_bar.pdf. While we're at it, we move it to the standard ebooks/ directory.

# File lib/softcover/builders/pdf.rb, line 133
def rename_pdf(basename, options={})
  tmp_pdf = basename + '.tmp.pdf'
  name    = options[:preview] ? basename + '-preview' : basename
  pdf     = name + '.pdf'
  mkdir('ebooks')
  # Remove the intermediate tmp files unless only running once.
  rm_tmp = keep_tmp_files?(options) ? "" : "&& rm -f *.tmp.*"
  "mv -f #{tmp_pdf} #{File.join('ebooks', pdf)} #{rm_tmp}"
end
xelatex() click to toggle source

Returns the `xelatex` executable. The `xelatex` program is roughly equivalent to the more standard `pdflatex`, but has better support for Unicode.

# File lib/softcover/builders/pdf.rb, line 72
def xelatex
  @xelatex ||= executable(dependency_filename(:latex))
end