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