module Latex @@replacements = [ [ /\&/, '\\\&'], [ / "/, " ``"], [ /\$/, "\\\$"], [ /\%/, "\\\%"], [ /#/, "\\\#"], [ /\~/, "$\\sim$"], [ /…/, "\\ldots"], [ /ö/, "\\\"o"], [ /ò/, '\\\`o'] ] def Latex.replacements @@replacements end class Builder def initialize(out) @out = out @commands = {} latex_command(:section) latex_command(:subsection) latex_command(:subsubsection) latex_command(:section!) latex_command(:subsection!) latex_command(:subsubsection!) latex_command(:renewcommand) latex_command(:textbf, yield_arg: true) latex_command(:textit, yield_arg: true) latex_command(:texttt, yield_arg: true) latex_command(:textsf, yield_arg: true) latex_command(:emph, yield_arg: true) latex_command(:huge) latex_command(:Huge) latex_command(:large) latex_command(:Large) latex_command(:small) latex_command(:Small) latex_command(:tiny) latex_command(:footnotesize) latex_command(:verbatim, environment: true) latex_command(:pagestyle) latex_command(:documentclass, arg_optional:[true,false]) latex_command(:usepackage) latex_command(:vspace) latex_command(:vspace!) latex_command(:fullpage) latex_command(:document, environment: true) latex_command(:hrule) latex_command(:nopagebreak) latex_command(:noindent) latex_command(:hfill) latex_command(:smallskip) latex_command(:medskip) latex_command(:bigskip) latex_command(:itemize , arg_optional:[true], environment: true) latex_command(:enumerate , arg_optional:[true], environment: true) latex_command(:item) latex_command(:tabular, environment: true) latex_command(:parbox, yield_arg: true) latex_command(:url) latex_command(:center, environment: true) end def puts_direct(data) @out.puts data end def print_direct(data) @out.print(data) end def safe_text(txt) Latex.replacements.fold(txt.to_s) { |t, s| t.gsub(*s) } end def puts(data) puts_direct(safe_text(data)) end def print(data) print_direct(safe_text(data)) end def latex_command(command, options = {}) @commands[command.to_sym] = ({ arg_optional: [], yield_arg: false, environment: false, literal: command.to_s.gsub(/!/, "*") }.merge(options)) end def method_missing(m, *args, &block) raise "Method Missing: #{m}" unless @commands.has_key?(m) options = @commands[m] if options[:environment] print_direct "\\begin{#{options[:literal]}}" else print_direct "\\#{options[:literal]}" end args.zip(options[:arg_optional]).each { |a,at| case at when nil,false then print_direct "{#{safe_text a}}" when true then print_direct "[#{safe_text a}]" end } if options[:environment] puts_direct "" yield puts_direct "\\end{#{options[:literal]}}" else if options[:yield_arg] print_direct "{" yield print_direct "}" end puts_direct "" end end def build_itemize(array, *args) config = {} if args[-1].is_a? Hash config = args.pop() end if(array.length > 0) if config.fetch(:enumerate, false) then enumerate(*args) do array.each do |r| item yield r end end else itemize(*args) do array.each do |r| item yield r end end end end end def endl(size = nil) puts_direct "\\\\#{if size.nil? then "" else "[#{size}]" end}" end def wrap print_direct "{" yield print_direct "}" end def em_dash print_direct "---" end end end