Class: LatexToPdf

Inherits:
Object
  • Object
show all
Defined in:
lib/rails-latex/latex_to_pdf.rb

Class Method Summary collapse

Class Method Details

.configObject



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/rails-latex/latex_to_pdf.rb', line 3

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'],
    :parse_runs => 1
  }
end

.escape_latex(text) ⇒ Object

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.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rails-latex/latex_to_pdf.rb', line 103

def self.escape_latex(text)
  # :stopdoc:
  unless @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).html_safe
end

.generate_pdf(code, config) ⇒ Object

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.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rails-latex/latex_to_pdf.rb', line 27

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(Rails.root, 'tmp', 'rails-latex', "#{Process.pid}-#{Thread.current.hash}")
  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(' ')} #{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'))
    FileUtils.mv(input, File.join(dir, '..', 'input.tex'))
    FileUtils.mv(input.sub(/\.tex$/,'.log'), File.join(dir, '..', 'input.log'))
    result = File.read(pdf_file)
    FileUtils.rm_rf(dir)
  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