math_ml 0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +49 -0
- data/Rakefile.utirake +334 -0
- data/lib/math_ml/element.rb +227 -0
- data/lib/math_ml/latex/builtin_commands.rb +547 -0
- data/lib/math_ml/latex.rb +1097 -0
- data/lib/math_ml/string.rb +32 -0
- data/lib/math_ml/util.rb +350 -0
- data/lib/math_ml.rb +25 -0
- data/spec/math_ml_element_spec.rb +32 -0
- data/spec/math_ml_latex_macro_spec.rb +122 -0
- data/spec/math_ml_latex_parser_spec.rb +479 -0
- data/spec/math_ml_latex_scanner_spec.rb +202 -0
- data/spec/math_ml_spec.rb +14 -0
- data/spec/math_ml_string_spec.rb +29 -0
- data/spec/math_ml_util_spec.rb +700 -0
- data/spec/util.rb +32 -0
- metadata +96 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# Extension of String class by MathML Library
|
4
|
+
#
|
5
|
+
# Copyright (C) 2007, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
6
|
+
# You can redistribute it and/or modify it under GPL2.
|
7
|
+
#
|
8
|
+
|
9
|
+
require "math_ml"
|
10
|
+
|
11
|
+
module MathML
|
12
|
+
module String
|
13
|
+
@@mathml_latex_parser = nil
|
14
|
+
def self.mathml_latex_parser
|
15
|
+
@@mathml_latex_parser = MathML::LaTeX::Parser.new unless @@mathml_latex_parser
|
16
|
+
@@mathml_latex_parser
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.mathml_latex_parser=(mlp)
|
20
|
+
raise TypeError unless mlp.is_a?(MathML::LaTeX::Parser) || mlp==nil
|
21
|
+
@@mathml_latex_parser = mlp
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_mathml(displaystyle=false)
|
25
|
+
MathML::String.mathml_latex_parser.parse(self, displaystyle)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class String
|
31
|
+
include MathML::String
|
32
|
+
end
|
data/lib/math_ml/util.rb
ADDED
@@ -0,0 +1,350 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# Utility for MathML Library
|
4
|
+
#
|
5
|
+
# Copyright (C) 2006, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
6
|
+
# You can redistribute it and/or modify it under GPL2.
|
7
|
+
#
|
8
|
+
|
9
|
+
require "math_ml"
|
10
|
+
|
11
|
+
module MathML::Util
|
12
|
+
ESCAPES = {"<"=>"lt",
|
13
|
+
">"=>"gt",
|
14
|
+
"&"=>"amp",
|
15
|
+
"\""=>"quot",
|
16
|
+
"'"=>"apos"
|
17
|
+
}
|
18
|
+
INVALID_RE = /(?!)/
|
19
|
+
EQNARRAY_RE = /\\begin\s*\{eqnarray\}(#{MathML::LaTeX::MBEC}*?)\\end\s*\{eqnarray\}/
|
20
|
+
SINGLE_COMMAND_RE = /(\\([a-zA-Z]+))[ \t]?/
|
21
|
+
|
22
|
+
def self.escapeXML(s, br=false)
|
23
|
+
r = s.gsub(/[<>&"']/){|m| "&#{ESCAPES[m]};"}
|
24
|
+
br ? r.gsub(/\n/, "<br />\n") : r
|
25
|
+
end
|
26
|
+
|
27
|
+
def escapeXML(s, br=false)
|
28
|
+
MathML::Util.escapeXML(s, br)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.collect_regexp(a)
|
32
|
+
if a
|
33
|
+
a = [a].flatten
|
34
|
+
a.size>0 ? Regexp.new(a.inject(""){|r, i| i.is_a?(Regexp) ? "#{r}#{i.to_s}|" : r}.chop) : INVALID_RE
|
35
|
+
else
|
36
|
+
INVALID_RE
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def collect_regexp(a)
|
41
|
+
MathML::Util.collect_regexp(a)
|
42
|
+
end
|
43
|
+
|
44
|
+
class MathData
|
45
|
+
attr_reader :math_list, :msrc_list, :dmath_list, :dsrc_list, :escape_list, :esrc_list, :user_list, :usrc_list
|
46
|
+
def initialize
|
47
|
+
@math_list = []
|
48
|
+
@msrc_list = []
|
49
|
+
@dmath_list = []
|
50
|
+
@dsrc_list = []
|
51
|
+
@escape_list = []
|
52
|
+
@esrc_list = []
|
53
|
+
@user_list = []
|
54
|
+
@usrc_list = []
|
55
|
+
end
|
56
|
+
|
57
|
+
def update(s)
|
58
|
+
@math_list.concat(s.math_list)
|
59
|
+
@msrc_list.concat(s.msrc_list)
|
60
|
+
@dmath_list.concat(s.dmath_list)
|
61
|
+
@dsrc_list.concat(s.dsrc_list)
|
62
|
+
@escape_list.concat(s.escape_list)
|
63
|
+
@esrc_list.concat(s.esrc_list)
|
64
|
+
@user_list.concat(s.user_list)
|
65
|
+
@usrc_list.concat(s.usrc_list)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class SimpleLaTeX
|
70
|
+
include MathML::Util
|
71
|
+
@@default_latex = nil
|
72
|
+
DEFAULT = {
|
73
|
+
:delimiter=>"\001",
|
74
|
+
:math_env_list=>[
|
75
|
+
/\$((?:\\.|[^\\\$])#{MathML::LaTeX::MBEC}*?)\$/m,
|
76
|
+
/\\\((#{MathML::LaTeX::MBEC}*?)\\\)/m
|
77
|
+
],
|
78
|
+
:dmath_env_list=>[
|
79
|
+
/\$\$(#{MathML::LaTeX::MBEC}*?)\$\$/m,
|
80
|
+
/\\\[(#{MathML::LaTeX::MBEC}*?)\\\]/m
|
81
|
+
],
|
82
|
+
:escape_list=>[
|
83
|
+
/\\(.)/m
|
84
|
+
],
|
85
|
+
:through_list=>[
|
86
|
+
],
|
87
|
+
:escape_any=> false,
|
88
|
+
:without_parse=>false
|
89
|
+
}
|
90
|
+
|
91
|
+
def initialize(options = {})
|
92
|
+
@params = DEFAULT.merge(options)
|
93
|
+
@params[:parser] = MathML::LaTeX::Parser.new unless @params[:parser] || @params[:without_parse]
|
94
|
+
|
95
|
+
@params[:math_envs] = collect_regexp(@params[:math_env_list])
|
96
|
+
@params[:dmath_envs] = collect_regexp(@params[:dmath_env_list])
|
97
|
+
@params[:escapes] = collect_regexp(@params[:escape_list])
|
98
|
+
@params[:throughs] = collect_regexp(@params[:through_list])
|
99
|
+
reset_encode_proc
|
100
|
+
reset_rescue_proc
|
101
|
+
reset_decode_proc
|
102
|
+
reset_unencode_proc
|
103
|
+
end
|
104
|
+
|
105
|
+
def reset_encode_proc
|
106
|
+
@encode_proc_re = INVALID_RE
|
107
|
+
@encode_proc = nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_encode_proc(*re, &proc)
|
111
|
+
@encode_proc_re = collect_regexp(re)
|
112
|
+
@encode_proc = proc
|
113
|
+
end
|
114
|
+
|
115
|
+
def reset_rescue_proc
|
116
|
+
@rescue_proc = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def set_rescue_proc(&proc)
|
120
|
+
@rescue_proc = proc
|
121
|
+
end
|
122
|
+
|
123
|
+
def reset_decode_proc
|
124
|
+
@decode_proc = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def set_decode_proc(&proc)
|
128
|
+
@decode_proc = proc
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_unencode_proc(&proc)
|
132
|
+
@unencode_proc = proc
|
133
|
+
end
|
134
|
+
|
135
|
+
def reset_unencode_proc
|
136
|
+
@unencode_proc = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def encode(src, *proc_re, &proc)
|
140
|
+
if proc_re.size>0 && proc_re[0].is_a?(MathData)
|
141
|
+
data = proc_re.shift
|
142
|
+
else
|
143
|
+
data = MathData.new
|
144
|
+
end
|
145
|
+
|
146
|
+
proc_re = proc_re.size==0 ? @encode_proc_re : collect_regexp(proc_re)
|
147
|
+
proc = @encode_proc unless proc
|
148
|
+
|
149
|
+
s = StringScanner.new(src)
|
150
|
+
encoded = ""
|
151
|
+
|
152
|
+
until s.eos?
|
153
|
+
if s.scan(/(.*?)(((((#{@params[:throughs]})|#{@params[:dmath_envs]})|#{@params[:math_envs]})|#{proc_re})|#{@params[:escapes]})/m)
|
154
|
+
encoded << s[1]
|
155
|
+
case
|
156
|
+
when s[6]
|
157
|
+
encoded << s[6]
|
158
|
+
when s[5], s[4]
|
159
|
+
env_src = s[5] || s[4]
|
160
|
+
if @params[:dmath_envs]=~env_src
|
161
|
+
encoded << "#{@params[:delimiter]}d#{data.dsrc_list.size}#{@params[:delimiter]}"
|
162
|
+
data.dsrc_list << env_src
|
163
|
+
else
|
164
|
+
encoded << "#{@params[:delimiter]}m#{data.msrc_list.size}#{@params[:delimiter]}"
|
165
|
+
data.msrc_list << env_src
|
166
|
+
end
|
167
|
+
when s[3]
|
168
|
+
size = s[3].size
|
169
|
+
s.pos = left = s.pos-size
|
170
|
+
if r=proc.call(s)
|
171
|
+
right = s.pos
|
172
|
+
encoded << "#{@params[:delimiter]}u#{data.user_list.size}#{@params[:delimiter]}"
|
173
|
+
data.user_list << r
|
174
|
+
data.usrc_list << s.string[left...right]
|
175
|
+
else
|
176
|
+
encoded << s.peek(size)
|
177
|
+
s.pos = s.pos+size
|
178
|
+
end
|
179
|
+
when s[2]
|
180
|
+
encoded << "#{@params[:delimiter]}e#{data.escape_list.size}#{@params[:delimiter]}"
|
181
|
+
@params[:escapes]=~s[2]
|
182
|
+
data.esrc_list << s[2]
|
183
|
+
data.escape_list << escapeXML($+, true)
|
184
|
+
end
|
185
|
+
else
|
186
|
+
encoded << s.rest
|
187
|
+
s.terminate
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
parse(data, @params[:parser]) unless @params[:without_parse]
|
192
|
+
|
193
|
+
return encoded, data
|
194
|
+
end
|
195
|
+
|
196
|
+
def error_to_html(e)
|
197
|
+
"<br />\n#{escapeXML(e.message)}<br />\n<code>#{escapeXML(e.done).gsub(/\n/, "<br />\n")}<strong>#{escapeXML(e.rest).gsub(/\n/, "<br />\n")}</strong></code><br />"
|
198
|
+
end
|
199
|
+
|
200
|
+
def latex_parser
|
201
|
+
@params[:parser] = MathML::LaTeX::Parser.new unless @params[:parser]
|
202
|
+
@params[:parser]
|
203
|
+
end
|
204
|
+
|
205
|
+
def parse(data, parser=nil)
|
206
|
+
parser = latex_parser unless parser
|
207
|
+
(data.math_list.size...data.msrc_list.size).each do |i|
|
208
|
+
begin
|
209
|
+
@params[:math_envs]=~data.msrc_list[i]
|
210
|
+
data.math_list[i] = parser.parse($+)
|
211
|
+
rescue MathML::LaTeX::ParseError => e
|
212
|
+
if @rescue_proc
|
213
|
+
data.math_list[i] = @rescue_proc.call(e)
|
214
|
+
else
|
215
|
+
data.math_list[i] = error_to_html(e)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
(data.dmath_list.size...data.dsrc_list.size).each do |i|
|
220
|
+
begin
|
221
|
+
@params[:dmath_envs]=~data.dsrc_list[i]
|
222
|
+
data.dmath_list[i] = parser.parse($+, true)
|
223
|
+
rescue MathML::LaTeX::ParseError => e
|
224
|
+
if @rescue_proc
|
225
|
+
data.dmath_list[i] = @rescue_proc.call(e)
|
226
|
+
else
|
227
|
+
data.dmath_list[i] = error_to_html(e)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def decode(encoded, data, without_parsed = false, &proc)
|
234
|
+
return nil if encoded==nil
|
235
|
+
proc = @decode_proc unless proc
|
236
|
+
encoded.gsub(/#{Regexp.escape(@params[:delimiter])}([demu])(\d+)#{Regexp.escape(@params[:delimiter])}/) do
|
237
|
+
i = $2.to_i
|
238
|
+
t, d, s =
|
239
|
+
case $1
|
240
|
+
when "d"
|
241
|
+
[:dmath, without_parsed ? escapeXML(data.dsrc_list[i], true) : data.dmath_list[i], data.dsrc_list[i]]
|
242
|
+
when "e"
|
243
|
+
[:escape, data.escape_list[i], data.esrc_list[i]]
|
244
|
+
when "m"
|
245
|
+
[:math, without_parsed ? escapeXML(data.msrc_list[i], true) : data.math_list[i], data.msrc_list[i]]
|
246
|
+
when "u"
|
247
|
+
[:user, data.user_list[i], data.usrc_list[i]]
|
248
|
+
end
|
249
|
+
if proc
|
250
|
+
proc.call(d, :type=>t, :index=>i, :src=>s) || d
|
251
|
+
else
|
252
|
+
d
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def decode_partial(type, encoded, data, &proc)
|
258
|
+
return nil if encoded==nil
|
259
|
+
head =
|
260
|
+
case type
|
261
|
+
when :math
|
262
|
+
"m"
|
263
|
+
when :dmath
|
264
|
+
"d"
|
265
|
+
when :escape
|
266
|
+
"e"
|
267
|
+
when :user
|
268
|
+
"u"
|
269
|
+
else
|
270
|
+
return
|
271
|
+
end
|
272
|
+
encoded.gsub(/#{Regexp.escape(@params[:delimiter])}#{head}(\d+)#{Regexp.escape(@params[:delimiter])}/) do
|
273
|
+
i = $1.to_i
|
274
|
+
t, d, s =
|
275
|
+
case head
|
276
|
+
when "d"
|
277
|
+
[:dmath, data.dmath_list[i], data.dsrc_list[i]]
|
278
|
+
when "e"
|
279
|
+
[:escape, data.escape_list[i], data.esrc_list[i]]
|
280
|
+
when "m"
|
281
|
+
[:math, data.math_list[i], data.msrc_list[i]]
|
282
|
+
when "u"
|
283
|
+
[:user, data.user_list[i], data.usrc_list[i]]
|
284
|
+
end
|
285
|
+
if proc
|
286
|
+
proc.call(d, :type=>t, :index=>i, :src=>s) || "#{@params[:delimiter]}#{head}#{i}#{@params[:delimiter]}"
|
287
|
+
else
|
288
|
+
d
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def unencode(encoded, data, without_escape=false, &proc)
|
294
|
+
return nil if encoded==nil
|
295
|
+
proc = @unencode_proc unless proc
|
296
|
+
encoded.gsub(/#{Regexp.escape(@params[:delimiter])}([demu])(\d+)#{Regexp.escape(@params[:delimiter])}/) do
|
297
|
+
i = $2.to_i
|
298
|
+
t, s =
|
299
|
+
case $1
|
300
|
+
when "d"
|
301
|
+
[:dmath, data.dsrc_list[i]]
|
302
|
+
when "e"
|
303
|
+
[:escape, data.esrc_list[i]]
|
304
|
+
when "m"
|
305
|
+
[:math, data.msrc_list[i]]
|
306
|
+
when "u"
|
307
|
+
[:user, data.usrc_list[i]]
|
308
|
+
end
|
309
|
+
s = escapeXML(s, true) unless without_escape
|
310
|
+
if proc
|
311
|
+
proc.call(s, :type=>t, :index=>i) || s
|
312
|
+
else
|
313
|
+
s
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.encode(src)
|
319
|
+
@@default_latex = self.new unless @@default_latex
|
320
|
+
@@default_latex.encode(src)
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.decode(src, data)
|
324
|
+
@@default_latex.decode(src, data)
|
325
|
+
end
|
326
|
+
|
327
|
+
def parse_eqnarray(src, parser=nil)
|
328
|
+
src = "\\begin{array}{ccc}#{src}\\end{array}"
|
329
|
+
parser = latex_parser unless parser
|
330
|
+
begin
|
331
|
+
parser.parse(src, true)
|
332
|
+
rescue MathML::LaTeX::ParseError => e
|
333
|
+
e = MathML::LaTeX::ParseError.new(e.message,
|
334
|
+
e.rest.sub(/\\end\{array\}\z/, '\end{eqnarray}'),
|
335
|
+
e.done.sub(/\A\\begin\{array\}\{ccc\}/, '\begin{eqnarray}'))
|
336
|
+
@rescue_proc ? @rescue_proc.call(e) : error_to_html(e)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def parse_single_command(src, parser=nil)
|
341
|
+
s = src[SINGLE_COMMAND_RE, 1]
|
342
|
+
parser = latex_parser unless parser
|
343
|
+
begin
|
344
|
+
parser.parse(s)
|
345
|
+
rescue MathML::LaTeX::ParseError => e
|
346
|
+
src[SINGLE_COMMAND_RE, 2]
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
data/lib/math_ml.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# MathML Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2005, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL2.
|
5
|
+
|
6
|
+
require "strscan"
|
7
|
+
module MathML
|
8
|
+
require "eim_xml"
|
9
|
+
|
10
|
+
class XMLElement < EimXML::Element
|
11
|
+
def pop
|
12
|
+
@contents.pop
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.pcstring(s, encoded=false)
|
17
|
+
EimXML::PCString.new(s, encoded)
|
18
|
+
end
|
19
|
+
|
20
|
+
class Error < StandardError; end
|
21
|
+
end
|
22
|
+
|
23
|
+
require "math_ml/element"
|
24
|
+
require "math_ml/latex"
|
25
|
+
require "math_ml/latex/builtin_commands"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "math_ml"
|
2
|
+
|
3
|
+
describe MathML::Element do
|
4
|
+
it "#display_style and #as_display_style" do
|
5
|
+
MathML::Element.new("test").display_style.should == nil
|
6
|
+
e = MathML::Element.new("test")
|
7
|
+
r = e.as_display_style
|
8
|
+
r.should equal(e)
|
9
|
+
e.display_style.should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "#pop" do
|
13
|
+
e = MathML::Element.new("super")
|
14
|
+
s = MathML::Element.new("sub")
|
15
|
+
|
16
|
+
e.pop.should be_nil
|
17
|
+
|
18
|
+
e << s
|
19
|
+
e.pop.should equal(s)
|
20
|
+
e.pop.should be_nil
|
21
|
+
|
22
|
+
e << "text"
|
23
|
+
e.pop.should == "text"
|
24
|
+
e.pop.should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "#to_s" do
|
28
|
+
e = MathML::Element.new("e")
|
29
|
+
e << "test<"
|
30
|
+
e.to_s.should == "<e>test<</e>"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require "math_ml"
|
2
|
+
require "spec/util"
|
3
|
+
|
4
|
+
describe MathML::LaTeX::Macro do
|
5
|
+
include MathML::Spec::Util
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@src = <<'EOT'
|
9
|
+
\newcommand{\newcom}{test}
|
10
|
+
\newcommand{\paramcom}[2]{param2 #2, param1 #1.}
|
11
|
+
\newcommand\ALPHA\alpha
|
12
|
+
\newcommand\BETA[1]\beta
|
13
|
+
\newcommand{\nothing}{}
|
14
|
+
\newenvironment{newenv}{begin_newenv}{end_newenv}
|
15
|
+
\newenvironment{paramenv}[2]{begin 1:#1, 2:#2}{end 2:#2 1:#1}
|
16
|
+
\newenvironment{nothing}{}{}
|
17
|
+
\newenvironment{separated environment}{sep}{env}
|
18
|
+
\newenvironment ENV
|
19
|
+
EOT
|
20
|
+
end
|
21
|
+
|
22
|
+
before do
|
23
|
+
@m = MathML::LaTeX::Macro.new
|
24
|
+
@m.parse(@src)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "#parse" do
|
28
|
+
@m = MathML::LaTeX::Macro.new
|
29
|
+
lambda{@m.parse(@src)}.should_not raise_error
|
30
|
+
|
31
|
+
@m = MathML::LaTeX::Macro.new
|
32
|
+
lambda{@m.parse('\newcommand{notcommand}{}')}.should raise_parse_error("Need newcommand.", '\\newcommand{', "notcommand}{}")
|
33
|
+
lambda{@m.parse('\newcommand{\separated command}{}')}.should raise_parse_error("Syntax error.", '\newcommand{\separated', " command}{}")
|
34
|
+
lambda{@m.parse('\newcommand{\nobody}')}.should raise_parse_error("Need parameter.", '\newcommand{\nobody}', "")
|
35
|
+
lambda{@m.parse('\newcommand{\noparam}{#1}')}.should raise_parse_error("Parameter \# too large.", '\newcommand{\noparam}{#', "1}")
|
36
|
+
lambda{@m.parse('\newcommand{\overopt}[1]{#1#2}')}.should raise_parse_error("Parameter \# too large.", '\newcommand{\overopt}[1]{#1#', "2}")
|
37
|
+
lambda{@m.parse('\newcommand{\strangeopt}[-1]')}.should raise_parse_error("Need positive number.", '\newcommand{\strangeopt}[', "-1]")
|
38
|
+
lambda{@m.parse('\newcommand{\strangeopt}[a]')}.should raise_parse_error("Need positive number.", '\newcommand{\strangeopt}[', "a]")
|
39
|
+
|
40
|
+
lambda{@m.parse('\newenvironment{\command}{}{}')}.should raise_parse_error("Syntax error.", '\newenvironment{', '\command}{}{}')
|
41
|
+
lambda{@m.parse('\newenvironment{nobegin}')}.should raise_parse_error("Need begin block.", '\newenvironment{nobegin}', "")
|
42
|
+
lambda{@m.parse('\newenvironment{noend}{}')}.should raise_parse_error("Need end block.", '\newenvironment{noend}{}', "")
|
43
|
+
lambda{@m.parse('\newenvironment{noparam}{#1}{}')}.should raise_parse_error("Parameter \# too large.", '\newenvironment{noparam}{#', "1}{}")
|
44
|
+
lambda{@m.parse('\newenvironment{overparam}[1]{#1#2}{}')}.should raise_parse_error("Parameter \# too large.", '\newenvironment{overparam}[1]{#1#', "2}{}")
|
45
|
+
lambda{@m.parse('\newenvironment{strangeparam}[-1]{}{}')}.should raise_parse_error("Need positive number.", '\newenvironment{strangeparam}[', "-1]{}{}")
|
46
|
+
lambda{@m.parse('\newenvironment{strangeparam}[a]{}{}')}.should raise_parse_error("Need positive number.", '\newenvironment{strangeparam}[', "a]{}{}")
|
47
|
+
|
48
|
+
lambda{@m.parse('\newcommand{\valid}{OK} \invalid{\test}{NG}')}.should raise_parse_error("Syntax error.", '\newcommand{\valid}{OK} ', '\invalid{\test}{NG}')
|
49
|
+
lambda{@m.parse('\newcommand{\valid}{OK} invalid{\test}{NG}')}.should raise_parse_error("Syntax error.", '\newcommand{\valid}{OK} ', 'invalid{\test}{NG}')
|
50
|
+
|
51
|
+
lambda{@m.parse('\newcommand{\newcom}[test')}.should raise_parse_error("Option not closed.", '\newcommand{\newcom}', '[test')
|
52
|
+
lambda{@m.parse('\newcommand{\newcom}[1][test')}.should raise_parse_error("Option not closed.", '\newcommand{\newcom}[1]', '[test')
|
53
|
+
lambda{@m.parse('\newcommand{\newcom}[1][]{#1#2}')}.should raise_parse_error("Parameter \# too large.", '\newcommand{\newcom}[1][]{#1#', '2}')
|
54
|
+
lambda{@m.parse('\newenvironment{newenv}[1][test')}.should raise_parse_error("Option not closed.", '\newenvironment{newenv}[1]', '[test')
|
55
|
+
lambda{@m.parse('\newenvironment{newenv}[1][test')}.should raise_parse_error("Option not closed.", '\newenvironment{newenv}[1]', '[test')
|
56
|
+
|
57
|
+
lambda{@m.parse('\newcommand{\newcom')}.should raise_parse_error("Block not closed.", '\newcommand', '{\newcom')
|
58
|
+
lambda{@m.parse('\newcommand{\newcom}{test1{test2}{test3')}.should raise_parse_error("Block not closed.", '\newcommand{\newcom}', '{test1{test2}{test3')
|
59
|
+
|
60
|
+
lambda{@m.parse('\newenvironment{newenv}[1][]{#1 #2}')}.should raise_parse_error("Parameter \# too large.", '\newenvironment{newenv}[1][]{#1 #', '2}')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "#commands" do
|
64
|
+
@m.commands("newcom").num.should == 0
|
65
|
+
@m.commands("paramcom").num.should == 2
|
66
|
+
@m.commands("no").should == nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it "#expand_command" do
|
70
|
+
@m.expand_command("not coommand", []).should == nil
|
71
|
+
|
72
|
+
@m.expand_command("newcom", []).should == "test"
|
73
|
+
@m.expand_command("newcom", ["dummy_param"]).should == "test"
|
74
|
+
@m.expand_command("paramcom", ["1", "2"]).should == "param2 2, param1 1."
|
75
|
+
@m.expand_command("paramcom", ["12", "34"]).should == "param2 34, param1 12."
|
76
|
+
lambda{@m.expand_command("paramcom", ["12"])}.should raise_parse_error("Need more parameter.", "", "")
|
77
|
+
lambda{@m.expand_command("paramcom", [])}.should raise_parse_error("Need more parameter.", "", "")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "#environments" do
|
81
|
+
@m.environments("newenv").num.should == 0
|
82
|
+
@m.environments("paramenv").num.should == 2
|
83
|
+
@m.environments("not_env").should == nil
|
84
|
+
@m.environments("separated environment").num.should == 0
|
85
|
+
end
|
86
|
+
|
87
|
+
it "#expand_environment" do
|
88
|
+
@m.expand_environment('notregistered', "dummy", []).should == nil
|
89
|
+
@m.expand_environment("newenv", "body", []).should == ' begin_newenv body end_newenv '
|
90
|
+
@m.expand_environment("paramenv", "body", ["1", "2"]).should == ' begin 1:1, 2:2 body end 2:2 1:1 '
|
91
|
+
@m.expand_environment("paramenv", "body", ["12", "34"]).should == ' begin 1:12, 2:34 body end 2:34 1:12 '
|
92
|
+
lambda{@m.expand_environment("paramenv", "body", ["1"])}.should raise_parse_error("Need more parameter.", "", "")
|
93
|
+
lambda{@m.expand_environment("paramenv", "body", [])}.should raise_parse_error("Need more parameter.", "", "")
|
94
|
+
@m.expand_environment("nothing", "body", []).should == ' body '
|
95
|
+
@m.expand_environment("separated environment", "body", []).should == ' sep body env '
|
96
|
+
@m.expand_environment("E", "body", []).should == ' N body V '
|
97
|
+
end
|
98
|
+
|
99
|
+
it "#expand_with_options" do
|
100
|
+
src = <<'EOT'
|
101
|
+
\newcommand{\opt}[1][x]{#1}
|
102
|
+
\newcommand{\optparam}[2][]{#1#2}
|
103
|
+
\newenvironment{newenv}[1][x]{s:#1}{e:#1}
|
104
|
+
\newenvironment{optenv}[2][]{s:#1}{e:#2}
|
105
|
+
EOT
|
106
|
+
|
107
|
+
m = MathML::LaTeX::Macro.new
|
108
|
+
m.parse(src)
|
109
|
+
|
110
|
+
m.expand_command("opt", []).should == 'x'
|
111
|
+
m.expand_command("opt", [], "1").should == '1'
|
112
|
+
|
113
|
+
m.expand_command("optparam", ["1"]).should == '1'
|
114
|
+
m.expand_command("optparam", ["1"], "2").should == '21'
|
115
|
+
|
116
|
+
m.expand_environment("newenv", "test", []).should == " s:x test e:x "
|
117
|
+
m.expand_environment("newenv", "test", [], "1").should == " s:1 test e:1 "
|
118
|
+
|
119
|
+
m.expand_environment("optenv", "test", ["1"]).should == " s: test e:1 "
|
120
|
+
m.expand_environment("optenv", "test", ["1"], "2").should == " s:2 test e:1 "
|
121
|
+
end
|
122
|
+
end
|