1 # The LaTeX class. 2 # Note that methods with a ! in them work like the * versions of the LaTeX 3 # functions, and methods with a ? in them do not print a newline. 4 # Alternatively, you can use _star and _suppress, if you prefer a more 5 # English-like syntax. 6 class LaTeX 7 def initialize() 8 @nesting = 0 9 @indent = " " 10 end 11 12 # Allows the user to change the default indenting (default is two spaces 13 # per nesting) 14 attr_accessor :indent 15 16 # Return the string for a newline 17 def newline() 18 return "\\\n" 19 end 20 21 # Return the string for a newline that won't break a page 22 def newline!() 23 return "\\*\n" 24 end 25 26 # Return a string for the LaTeX symbol 27 def latex() 28 return "\\LaTeX" 29 end 30 31 # Return a string for a comment, ended with a carriage-return 32 def comment(comment) 33 return "% #{comment}\n" 34 end 35 36 # Let % be an alternative way to specify a comment 37 alias_method :%, :comment #, 38 39 # Return an indented string, terminated by a newline if it isn't a comment 40 # that is already newline-terminated 41 def indent(str) 42 s = indent?(str) 43 if not s =~ /^\s*%.*\n/ then 44 s << "\n" 45 end 46 return s 47 end 48 49 # Return an indented string that is never newline-terminated 50 def indent?(str) 51 s = "" 52 @nesting.times do 53 s << @indent 54 end 55 s << str 56 return s 57 end 58 59 # Create a new LaTeX command 60 def newcommand(cmd, func) 61 method_missing("newcommand", "\\#{cmd}", func) 62 end 63 64 # Print a LaTeX command using the rules specified above 65 def method_missing(symbol, *args) 66 symbol = symbol.to_s.gsub('!', '*') 67 symbol = symbol.to_s.gsub('_star', '*') 68 nl = !(symbol =~ /(\?|_suppress)\*$/) 69 symbol = symbol.gsub('\?', '') 70 symbol = symbol.gsub('_suppress', '') 71 s = "" 72 if block_given? then 73 s << __begin__(symbol, *args) << __gen_newline__(nl) 74 nesting_tmp = @nesting 75 @nesting = @nesting.succ 76 s << proc.call() 77 @nesting = nesting_tmp 78 s << __end__(symbol) << __gen_newline__(nl) 79 else 80 s << indent?("\\#{symbol}#{__arg_list__(args)}#{__gen_newline__(nl)}") 81 end 82 return s 83 end 84 85 alias_method :__cmd__, :method_missing 86 alias_method :__env__, :method_missing 87 88 # Return the arguments of a LaTeX function; Use an array to specify 89 # optional arguments 90 def __arg_list__(args) 91 s = "" 92 args.each do |arg| 93 case arg 94 when Array 95 s << "[" 96 arg.each do |a| 97 s << "#{a}," 98 end 99 s.chop! 100 s << "]" 101 else 102 s << "{#{arg}}" 103 end 104 end 105 return s 106 end 107 108 # Return a newline if nl is true, otherwise return an empty string 109 def __gen_newline__(nl) 110 return nl ? "\n" : "" 111 end 112 113 def __begin__(symbol, *args) 114 return indent?("\\begin{#{symbol}}#{__arg_list__(args)}") 115 end 116 117 def __end__(symbol) 118 return indent?("\\end{#{symbol}}") 119 end 120 end 121 122 if __FILE__ == $0 then 123 l = LaTeX.new 124 s = 125 l.documentclass("article") + 126 l.newcommand("foo", l.latex) + 127 l.newenvironment("myitemize", l.__begin__("itemize"), l.__end__("itemize")) + 128 l.document { 129 l.title("#{l.LARGE?} This is a test") + 130 l.author("Me") + 131 l.date() + 132 l.maketitle() + 133 134 l.section("Writing #{l.foo_suppress} documents in Ruby") { 135 l.indent(l % "This is a comment.") + 136 l.indent("I can put text here.") 137 } + 138 139 l.section("More about #{l.foo_suppress} and Ruby") { 140 l.myitemize { 141 l.item?(["a)"]) + "This is item a.\n" + 142 l.item?(["b)"]) + "This is item b.\n" 143 } 144 } 145 } 146 puts s 147 end