class LatexToPdf

Public Class Methods

config() click to toggle source
# File lib/rails-latex/latex_to_pdf.rb, line 2
def self.config
  @config||={
    :recipe => [
    #  {
    #    :command => 'pdflatex',
    #    :arguments => ['-halt-on-error', '-shell-escape', '-interaction=batchmode'],
    #    :extra_arguments => [],
    #    :runs => 1
    #  }
    ],
    :command => 'pdflatex',
    :arguments => ['-halt-on-error'],
    :default_arguments => ['-shell-escape', '-interaction=batchmode'],
    workdir: ->() { "#{Process.pid}-#{Thread.current.hash}" },
    preservework: false,
    basedir: File.join(Rails.root, 'tmp', 'rails-latex'),
    :parse_runs => 1
  }
end
escape_latex(text) click to toggle source

Escapes LaTex special characters in text so that they wont be interpreted as LaTex commands.

This method will use RedCloth to do the escaping if available.

# File lib/rails-latex/latex_to_pdf.rb, line 107
def self.escape_latex(text)
  # :stopdoc:
  unless instance_variable_defined?(:@latex_escaper) && @latex_escaper
    if defined?(RedCloth::Formatters::LATEX)
      class << (@latex_escaper=RedCloth.new(''))
        include RedCloth::Formatters::LATEX
      end
    else
      class << (@latex_escaper=Object.new)
        ESCAPE_RE=/([{}_$&%#])|([\\^~|<>])/
        ESC_MAP={
          '\\' => 'backslash',
          '^' => 'asciicircum',
          '~' => 'asciitilde',
          '|' => 'bar',
          '<' => 'less',
          '>' => 'greater',
        }

        def latex_esc(text)   # :nodoc:
          text.gsub(ESCAPE_RE) {|m|
            if $1
              "\\#{m}"
            else
              "\\text#{ESC_MAP[m]}{}"
            end
          }
        end
      end
    end
    # :startdoc:
  end

  @latex_escaper.latex_esc(text.to_s.to_str).html_safe
end
generate_pdf(code, config) click to toggle source

Converts a string of LaTeX code into a binary string of PDF.

By default, pdflatex is used to convert the file and creates the directory +#{Rails.root}/tmp/rails-latex/+ to store intermediate files.

The config argument defaults to LatexToPdf.config but can be overridden using @latex_config.

# File lib/rails-latex/latex_to_pdf.rb, line 29
def self.generate_pdf(code, config)
  config = self.config.merge(config)
  recipe = config[:recipe]

  # Deprecated legacy mode, if no recipe found
  if recipe.length == 0
    if config != self.config
      Rails.logger.warn("Using command, arguments and parse_runs is deprecated in favor of recipe")
    end
    # Regression fix -- ability to override some arguments (-halt-on-error) but not other (-interaction),
    #                   this is expected behaviour as seen in test_broken_doc_overriding_halt_on_error.
    #                   Will be fixed in rails-latex 3
    recipe = [{
      :command => config[:command],
      :arguments => config[:arguments] + config[:default_arguments],
      :runs => config[:parse_runs]
    }]
  end

  # Create directory, prepare additional supporting files (.cls, .sty, ...)
  dir = File.join(config[:basedir], config[:workdir].call)
  input = File.join(dir, 'input.tex')
  FileUtils.mkdir_p(dir)
  supporting = config[:supporting]
  if supporting.kind_of?(String) or supporting.kind_of?(Pathname) or (supporting.kind_of?(Array) and supporting.length > 0)
    FileUtils.cp_r(supporting, dir)
  end
  File.open(input,'wb') {|io| io.write(code)}

  # Process recipe
  recipe.each do |item|
    command = item[:command] || config[:command]
    runs = item[:runs] || config[:parse_runs]
    args = item[:arguments] || config[:arguments] + config[:default_arguments]
    args += item[:extra_arguments].to_a + ['input']
    kwargs = {:out => ["input.log", "a"]}
    Rails.logger.info "Running '#{command} #{args.join(' ')}' in #{dir} #{runs} times..."
    Process.waitpid(
      fork do
        begin
          Dir.chdir dir
          (runs - 1).times do
            clean_exit = system command, *args, **kwargs
            Process.exit! 1 unless clean_exit
          end
          exec command, *args, **kwargs
        rescue
          File.open("input.log", 'a'){|io|
            io.write("#{$!.message}:\n#{$!.backtrace.join("\n")}\n")
          }
        ensure
          Process.exit! 1
        end
      end
    )
  end

  # Finish
  if $?.exitstatus.zero? && File.exist?(pdf_file=input.sub(/\.tex$/,'.pdf'))
    cmd = config[:preservework] ? :cp : :mv
    FileUtils.send(cmd, input, File.join(config[:basedir], 'input.tex'))
    FileUtils.send(cmd, input.sub(/\.tex$/,'.log'),
                   File.join(config[:basedir], 'input.log'))
    result = File.read(pdf_file)
    FileUtils.rm_rf(dir) unless config[:preservework]
  else
    raise RailsLatex::ProcessingError.new(
      "rails-latex failed: See #{input.sub(/\.tex$/,'.log')} for details",
      File.open(input).read,
      File.open(input.sub(/\.tex$/,'.log')).read
    )
  end
  result
end