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,479 @@
|
|
1
|
+
require "eim_xml/parser"
|
2
|
+
require "eim_xml/dsl"
|
3
|
+
require "math_ml"
|
4
|
+
require "spec/util"
|
5
|
+
|
6
|
+
describe MathML::LaTeX::Parser do
|
7
|
+
include MathML::Spec::Util
|
8
|
+
|
9
|
+
def check_chr(tag, src)
|
10
|
+
src.scan(/./) do |c|
|
11
|
+
smml(c).should == "<#{tag}>#{c}</#{tag}>"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_hash(tag, hash)
|
16
|
+
hash.each do |k, v|
|
17
|
+
smml(k).should == "<#{tag}>#{v}</#{tag}>"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_entity(tag, hash)
|
22
|
+
check_hash(tag, hash.inject({}){|r, i| r[i[0]]="&#{i[1]};"; r})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Spec#strip_math_ml" do
|
26
|
+
src = "<math test='dummy'> <a> b </a> <c> d </c></math>"
|
27
|
+
strip_math_ml(src).should == "<a>b</a><c>d</c>"
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#parse" do
|
31
|
+
it "should return math element" do
|
32
|
+
ns = "http://www.w3.org/1998/Math/MathML"
|
33
|
+
|
34
|
+
e = new_parser.parse("")
|
35
|
+
e.should match(EimXML::Element.new(:math, :display=>"inline", "xmlns"=>ns))
|
36
|
+
e.attributes.keys.size.should == 2
|
37
|
+
e.contents.should be_empty
|
38
|
+
|
39
|
+
e = new_parser.parse("", true)
|
40
|
+
e.should match(EimXML::Element.new(:math, :display=>"block", "xmlns"=>ns))
|
41
|
+
e.attributes.keys.size.should == 2
|
42
|
+
e.contents.should be_empty
|
43
|
+
|
44
|
+
e = new_parser.parse("", false)
|
45
|
+
e.should match(EimXML::Element.new(:math, :display=>"inline", "xmlns"=>ns))
|
46
|
+
e.attributes.keys.size.should == 2
|
47
|
+
e.contents.should be_empty
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should ignore space" do
|
51
|
+
smml("{ a }").should == "<mrow><mi>a</mi></mrow>"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should process latex block" do
|
55
|
+
lambda{smml("test {test} {test")}.should raise_parse_error("Block not closed.", "test {test} ", "{test")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should raise error when error happened" do
|
59
|
+
src = 'a\hoge c'
|
60
|
+
lambda{smml(src)}.should raise_parse_error("Undefined command.", "a", '\hoge c')
|
61
|
+
|
62
|
+
src = '\sqrt\sqrt1'
|
63
|
+
lambda{smml(src)}.should raise_parse_error("Syntax error.", '\sqrt\sqrt', "1")
|
64
|
+
|
65
|
+
src = "a{b"
|
66
|
+
lambda{smml(src)}.should raise_parse_error("Block not closed.", "a", "{b")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should process numerics" do
|
70
|
+
smml('1234567890').should == "<mn>1234567890</mn>"
|
71
|
+
smml('1.2').should == "<mn>1.2</mn>"
|
72
|
+
smml('1.').should == "<mn>1</mn><mo>.</mo>"
|
73
|
+
smml('.2').should == "<mn>.2</mn>"
|
74
|
+
smml('1.2.3').should == "<mn>1.2</mn><mn>.3</mn>"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should process alphabets" do
|
78
|
+
smml("abc").should == "<mi>a</mi><mi>b</mi><mi>c</mi>"
|
79
|
+
check_chr("mi", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should process non alphabet command" do
|
83
|
+
smml('\|').should == "<mo>∥</mo>"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should process space commands" do
|
87
|
+
smml('\ ').should == "<mspace width='1em' />"
|
88
|
+
smml('\quad').should == "<mspace width='1em' />"
|
89
|
+
smml('\qquad').should == "<mspace width='2em' />"
|
90
|
+
smml('\,').should == "<mspace width='0.167em' />"
|
91
|
+
smml('\:').should == "<mspace width='0.222em' />"
|
92
|
+
smml('\;').should == "<mspace width='0.278em' />"
|
93
|
+
smml('\!').should == "<mspace width='-0.167em' />"
|
94
|
+
smml('~').should == "<mspace width='1em' />"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should process operators" do
|
98
|
+
check_chr("mo", ",.+-*=/()[]|;:!")
|
99
|
+
check_entity("mo", {"<"=>"lt", ">"=>"gt", '"'=>"quot"})
|
100
|
+
check_hash("mo", {'\backslash'=>'\\', '\%'=>'%', '\{'=>'{', '\}'=>'}', '\$'=>'$', '\#'=>'#'})
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should process prime" do
|
104
|
+
smml("a'").should == "<msup><mi>a</mi><mo>′</mo></msup>"
|
105
|
+
smml("a''").should == "<msup><mi>a</mi><mo>′′</mo></msup>"
|
106
|
+
smml("a'''").should == "<msup><mi>a</mi><mo>′′′</mo></msup>"
|
107
|
+
smml("'").should == "<msup><none /><mo>′</mo></msup>"
|
108
|
+
|
109
|
+
lambda{smml("a^b'")}.should raise_parse_error("Double superscript.", "a^b", "'")
|
110
|
+
|
111
|
+
smml("a'^b").should == "<msup><mi>a</mi><mrow><mo>′</mo><mi>b</mi></mrow></msup>"
|
112
|
+
smml("a'''^b").should == "<msup><mi>a</mi><mrow><mo>′′′</mo><mi>b</mi></mrow></msup>"
|
113
|
+
smml("a'b").should == "<msup><mi>a</mi><mo>′</mo></msup><mi>b</mi>"
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should process sqrt" do
|
117
|
+
smml('\sqrt a').should == "<msqrt><mi>a</mi></msqrt>"
|
118
|
+
smml('\sqrt[2]3').should == "<mroot><mn>3</mn><mn>2</mn></mroot>"
|
119
|
+
smml('\sqrt[2a]3').should == "<mroot><mn>3</mn><mrow><mn>2</mn><mi>a</mi></mrow></mroot>"
|
120
|
+
lambda{smml('\sqrt[12')}.should raise_parse_error("Option not closed.", '\sqrt', "[12")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should process subsup" do
|
124
|
+
smml("a_b^c").should == "<msubsup><mi>a</mi><mi>b</mi><mi>c</mi></msubsup>"
|
125
|
+
smml("a_b").should == "<msub><mi>a</mi><mi>b</mi></msub>"
|
126
|
+
smml("a^b").should == "<msup><mi>a</mi><mi>b</mi></msup>"
|
127
|
+
smml("_a^b").should == "<msubsup><none /><mi>a</mi><mi>b</mi></msubsup>"
|
128
|
+
|
129
|
+
lambda{smml("a_b_c")}.should raise_parse_error("Double subscript.", "a_b", "_c")
|
130
|
+
lambda{smml("a^b^c")}.should raise_parse_error("Double superscript.", "a^b", "^c")
|
131
|
+
lambda{smml("a_")}.should raise_parse_error("Subscript not exist.", "a_", "")
|
132
|
+
lambda{smml("a^")}.should raise_parse_error("Superscript not exist.", "a^", "")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should process underover" do
|
136
|
+
smml('\sum_a^b', true).should == "<munderover><mo>∑</mo><mi>a</mi><mi>b</mi></munderover>"
|
137
|
+
smml('\sum_a^b').should == "<msubsup><mo>∑</mo><mi>a</mi><mi>b</mi></msubsup>"
|
138
|
+
smml('\sum_a', true).should == "<munder><mo>∑</mo><mi>a</mi></munder>"
|
139
|
+
smml('\sum^a', true).should == "<mover><mo>∑</mo><mi>a</mi></mover>"
|
140
|
+
smml('\sum_a').should == "<msub><mo>∑</mo><mi>a</mi></msub>"
|
141
|
+
smml('\sum^a').should == "<msup><mo>∑</mo><mi>a</mi></msup>"
|
142
|
+
|
143
|
+
lambda{smml('\sum_b_c')}.should raise_parse_error("Double subscript.", '\sum_b', "_c")
|
144
|
+
lambda{smml('\sum^b^c')}.should raise_parse_error("Double superscript.", '\sum^b', "^c")
|
145
|
+
lambda{smml('\sum_')}.should raise_parse_error("Subscript not exist.", '\sum_', "")
|
146
|
+
lambda{smml('\sum^')}.should raise_parse_error("Superscript not exist.", '\sum^', "")
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should process font commands" do
|
150
|
+
smml('a{\bf b c}d').should == "<mi>a</mi><mrow><mi mathvariant='bold'>b</mi><mi mathvariant='bold'>c</mi></mrow><mi>d</mi>"
|
151
|
+
smml('\bf a{\it b c}d').should == "<mi mathvariant='bold'>a</mi><mrow><mi>b</mi><mi>c</mi></mrow><mi mathvariant='bold'>d</mi>"
|
152
|
+
smml('a{\rm b c}d').should == "<mi>a</mi><mrow><mi mathvariant='normal'>b</mi><mi mathvariant='normal'>c</mi></mrow><mi>d</mi>"
|
153
|
+
|
154
|
+
smml('a \mathbf{bc}d').should == "<mi>a</mi><mrow><mrow><mi mathvariant='bold'>b</mi><mi mathvariant='bold'>c</mi></mrow></mrow><mi>d</mi>"
|
155
|
+
smml('\mathbf12').should == "<mrow><mn mathvariant='bold'>1</mn></mrow><mn>2</mn>"
|
156
|
+
smml('\bf a \mathit{bc} d').should == "<mi mathvariant='bold'>a</mi><mrow><mrow><mi>b</mi><mi>c</mi></mrow></mrow><mi mathvariant='bold'>d</mi>"
|
157
|
+
smml('a\mathrm{bc}d').should == "<mi>a</mi><mrow><mrow><mi mathvariant='normal'>b</mi><mi mathvariant='normal'>c</mi></mrow></mrow><mi>d</mi>"
|
158
|
+
|
159
|
+
smml('a \mathbb{b c} d').should == "<mi>a</mi><mrow><mrow><mi>𝕓</mi><mi>𝕔</mi></mrow></mrow><mi>d</mi>"
|
160
|
+
smml('a \mathscr{b c} d').should == "<mi>a</mi><mrow><mrow><mi>𝒷</mi><mi>𝒸</mi></mrow></mrow><mi>d</mi>"
|
161
|
+
smml('a \mathfrak{b c} d').should == "<mi>a</mi><mrow><mrow><mi>𝔟</mi><mi>𝔠</mi></mrow></mrow><mi>d</mi>"
|
162
|
+
smml('a \bm{bc}d').should == "<mi>a</mi><mrow><mrow><mi mathvariant='bold-italic'>b</mi><mi mathvariant='bold-italic'>c</mi></mrow></mrow><mi>d</mi>"
|
163
|
+
smml('\bm ab').should == "<mrow><mi mathvariant='bold-italic'>a</mi></mrow><mi>b</mi>"
|
164
|
+
|
165
|
+
lambda{smml('\mathit')}.should raise_parse_error("Syntax error.", '\mathit', "")
|
166
|
+
lambda{smml('\mathrm')}.should raise_parse_error("Syntax error.", '\mathrm', "")
|
167
|
+
lambda{smml('\mathbf')}.should raise_parse_error("Syntax error.", '\mathbf', "")
|
168
|
+
lambda{smml('\mathbb')}.should raise_parse_error("Syntax error.", '\mathbb', "")
|
169
|
+
lambda{smml('\mathscr')}.should raise_parse_error("Syntax error.", '\mathscr', "")
|
170
|
+
lambda{smml('\mathfrak')}.should raise_parse_error("Syntax error.", '\mathfrak', "")
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should process mbox" do
|
174
|
+
smml('a\mbox{b c}d').should == "<mi>a</mi><mtext>b c</mtext><mi>d</mi>"
|
175
|
+
smml('\mbox{<>\'"&}').should == '<mtext><>'"&</mtext>'
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should process frac" do
|
179
|
+
smml('\frac ab').should == "<mfrac><mi>a</mi><mi>b</mi></mfrac>"
|
180
|
+
smml('\frac12').should == "<mfrac><mn>1</mn><mn>2</mn></mfrac>"
|
181
|
+
|
182
|
+
lambda{smml('\frac a')}.should raise_parse_error("Syntax error.", '\frac a', "")
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should process environment" do
|
186
|
+
lambda{smml('{\begin}rest')}.should raise_parse_error("Environment name not exist.", '{\begin', '}rest')
|
187
|
+
|
188
|
+
lambda{smml('{\begin{array}{c}dummy}rest')}.should raise_parse_error('Matching \end not exist.', '{\begin{array}{c}dummy', '}rest')
|
189
|
+
|
190
|
+
lambda{smml('\begin{array}c dummy\end{test}')}.should raise_parse_error("Environment mismatched.", '\begin{array}c dummy\end', "{test}")
|
191
|
+
|
192
|
+
lambda{smml('\left(\begin{array}\right)')}.should raise_parse_error("Syntax error.", '\left(\begin{array}', '\right)')
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should process array" do
|
196
|
+
smml('\begin{array}{lrc} a & b & c \\\\ d & e & f \\\\ \end{array}').should == "<mtable columnalign='left right center'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd><mi>d</mi></mtd><mtd><mi>e</mi></mtd><mtd><mi>f</mi></mtd></mtr></mtable>"
|
197
|
+
|
198
|
+
smml('\begin{array}{lrc}a&b&c\\\\d&e&f \end{array}').should == "<mtable columnalign='left right center'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd><mi>d</mi></mtd><mtd><mi>e</mi></mtd><mtd><mi>f</mi></mtd></mtr></mtable>"
|
199
|
+
|
200
|
+
smml('\begin{array}{c}\end{array}').should == "<mtable />"
|
201
|
+
|
202
|
+
lambda{smml('\begin{array}\end{array}')}.should raise_parse_error('Syntax error.', '\begin{array}', '\end{array}')
|
203
|
+
|
204
|
+
lambda{smml('\begin{array}{a}\end{array}')}.should raise_parse_error("Syntax error.", '\begin{array}{', 'a}\end{array}')
|
205
|
+
|
206
|
+
lambda{smml('\begin{array}{cc}a\\\\b&c\end{array}')}.should raise_parse_error("Need more column.", '\begin{array}{cc}a', '\\\\b&c\end{array}')
|
207
|
+
|
208
|
+
lambda{smml('\begin{array}{cc}a\end{array}')}.should raise_parse_error("Need more column.", '\begin{array}{cc}a', '\end{array}')
|
209
|
+
|
210
|
+
lambda{smml('\begin{array}{c}a&\end{array}')}.should raise_parse_error("Too many column.", '\begin{array}{c}a', '&\end{array}')
|
211
|
+
|
212
|
+
smml('\begin{array}{cc}&\end{array}').should == "<mtable><mtr><mtd /><mtd /></mtr></mtable>"
|
213
|
+
|
214
|
+
math_ml('\left\{\begin{array}ca_b\end{array}\right\}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
|
215
|
+
element :mrow do
|
216
|
+
element :mtable do
|
217
|
+
element :mtr do
|
218
|
+
element :mtd do
|
219
|
+
element :msub do
|
220
|
+
element(:mi).add("a")
|
221
|
+
element(:mi).add("b")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
}
|
228
|
+
|
229
|
+
smml('\begin{array}{@{a_1}l@bc@cr@d}A&B&C\end{array}').should == "<mtable columnalign='center left center center center right center'><mtr><mtd><mrow><msub><mi>a</mi><mn>1</mn></msub></mrow></mtd><mtd><mi>A</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>B</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>C</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable>"
|
230
|
+
|
231
|
+
math_ml('\left\{\begin{array}ca_b\end{array}\right\}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
|
232
|
+
element :mrow do
|
233
|
+
element :mtable do
|
234
|
+
element :mtr do
|
235
|
+
element :mtd do
|
236
|
+
element :msub do
|
237
|
+
element(:mi).add("a")
|
238
|
+
element(:mi).add("b")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
}
|
245
|
+
|
246
|
+
smml('\begin{array}{c|c}a&b\\\\c&d\end{array}').should == "<mtable columnlines='solid'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr><mtr><mtd><mi>c</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable>"
|
247
|
+
smml('\begin{array}{|c|}a\\\\c\end{array}').should == "<mtable columnlines='solid solid'><mtr><mtd /><mtd><mi>a</mi></mtd><mtd /></mtr><mtr><mtd /><mtd><mi>c</mi></mtd><mtd /></mtr></mtable>"
|
248
|
+
smml('\begin{array}{c}\hline c\end{array}').should == "<mtable rowlines='solid'><mtr /><mtr><mtd><mi>c</mi></mtd></mtr></mtable>"
|
249
|
+
smml('\begin{array}{c@acc}c&c&c\\\\\hline\end{array}').should == "<mtable rowlines='solid'><mtr><mtd><mi>c</mi></mtd><mtd><mi>a</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd /><mtd /><mtd /><mtd /></mtr></mtable>"
|
250
|
+
smml('\begin{array}{c}\hline a\\\\b\\\\\hline\end{array}').should == "<mtable rowlines='solid none solid'><mtr /><mtr><mtd><mi>a</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd></mtr><mtr><mtd /></mtr></mtable>"
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should parse \\left and \\right" do
|
254
|
+
math_ml('\left(\frac12\right)')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
|
255
|
+
element :mrow do
|
256
|
+
element :mfrac do
|
257
|
+
element(:mn).add("1")
|
258
|
+
element(:mn).add("2")
|
259
|
+
end
|
260
|
+
end
|
261
|
+
}
|
262
|
+
|
263
|
+
math_ml('\left \lfloor a\right \rfloor')[0].should =~ EimXML::DSL.element(:mfenced, :open=>EimXML::PCString.new("⌊", true), :close=>EimXML::PCString.new("⌋", true)){
|
264
|
+
element :mrow do
|
265
|
+
element(:mi).add("a")
|
266
|
+
end
|
267
|
+
}
|
268
|
+
|
269
|
+
math_ml('\left \{ a \right \}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
|
270
|
+
element :mrow do
|
271
|
+
element(:mi).add("a")
|
272
|
+
end
|
273
|
+
}
|
274
|
+
|
275
|
+
math_ml('\left\{\begin{array}c\begin{array}ca\end{array}\end{array}\right\}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
|
276
|
+
element :mrow do
|
277
|
+
element :mtable do
|
278
|
+
element :mtr do
|
279
|
+
element :mtd do
|
280
|
+
element :mtable do
|
281
|
+
element :mtr do
|
282
|
+
element :mtd do
|
283
|
+
element(:mi).add("a")
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
}
|
292
|
+
|
293
|
+
math_ml('\left(\sum_a\right)')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
|
294
|
+
element :mrow do
|
295
|
+
element :msub do
|
296
|
+
element(:mo).add(EimXML::PCString.new("∑", true))
|
297
|
+
element(:mi).add("a")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
}
|
301
|
+
|
302
|
+
math_ml('\left(\sum_a\right)', true)[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
|
303
|
+
element :mrow do
|
304
|
+
element :munder do
|
305
|
+
element(:mo).add(EimXML::PCString.new("∑", true))
|
306
|
+
element(:mi).add("a")
|
307
|
+
end
|
308
|
+
end
|
309
|
+
}
|
310
|
+
|
311
|
+
lambda{smml('\left(test')}.should raise_parse_error("Brace not closed.", '\left', '(test')
|
312
|
+
|
313
|
+
math_ml('\left\|a\right\|')[0].should =~ EimXML::DSL.element(:mfenced, :open=>EimXML::PCString.new("∥", true), :close=>EimXML::PCString.new("∥", true)){
|
314
|
+
element :mrow do
|
315
|
+
element(:mi).add("a")
|
316
|
+
end
|
317
|
+
}
|
318
|
+
|
319
|
+
lambda{smml('\left')}.should raise_parse_error("Need brace here.", '\left', "")
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should parse overs" do
|
323
|
+
smml('\hat a').should == "<mover><mi>a</mi><mo>ˆ</mo></mover>"
|
324
|
+
smml('\hat12').should == "<mover><mn>1</mn><mo>ˆ</mo></mover><mn>2</mn>"
|
325
|
+
lambda{smml('{\hat}a')}.should raise_parse_error("Syntax error.", '{\hat', '}a')
|
326
|
+
end
|
327
|
+
|
328
|
+
it "should parse unders" do
|
329
|
+
smml('\underline a').should == "<munder><mi>a</mi><mo>¯</mo></munder>"
|
330
|
+
smml('\underline12').should == "<munder><mn>1</mn><mo>¯</mo></munder><mn>2</mn>"
|
331
|
+
lambda{smml('{\underline}a')}.should raise_parse_error("Syntax error.", '{\underline', '}a')
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should parse stackrel" do
|
335
|
+
smml('\stackrel\to=').should == "<mover><mo>=</mo><mo>→</mo></mover>"
|
336
|
+
smml('\stackrel12').should == "<mover><mn>2</mn><mn>1</mn></mover>"
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should parse comment" do
|
340
|
+
smml('a%b').should == "<mi>a</mi>"
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should parse entity" do
|
344
|
+
p = new_parser
|
345
|
+
lambda{smml('\entity{therefore}', false, p)}.should raise_parse_error("Unregistered entity.", '\entity{', "therefore}")
|
346
|
+
|
347
|
+
p.unsecure_entity = true
|
348
|
+
smml('\entity{therefore}', false, p).should == "<mo>∴</mo>"
|
349
|
+
|
350
|
+
p.unsecure_entity = false
|
351
|
+
lambda{smml('\entity{therefore}', false, p)}.should raise_parse_error("Unregistered entity.", '\entity{', "therefore}")
|
352
|
+
|
353
|
+
p.add_entity(['therefore'])
|
354
|
+
smml('\entity{therefore}', false, p).should == "<mo>∴</mo>"
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should parse backslash" do
|
358
|
+
smml('\\\\').should == "<br xmlns='http://www.w3.org/1999/xhtml' />"
|
359
|
+
end
|
360
|
+
|
361
|
+
it "can be used with macro" do
|
362
|
+
macro = <<'EOS'
|
363
|
+
\newcommand{\root}[2]{\sqrt[#1]{#2}}
|
364
|
+
\newcommand{\ROOT}[2]{\sqrt[#1]#2}
|
365
|
+
\newenvironment{braced}[2]{\left#1}{\right#2}
|
366
|
+
\newenvironment{sq}[2]{\sqrt[#2]{#1}}{\sqrt#2}
|
367
|
+
\newcommand{\R}{\mathbb R}
|
368
|
+
\newenvironment{BB}{\mathbb A}{\mathbb B}
|
369
|
+
EOS
|
370
|
+
p = new_parser
|
371
|
+
p.macro.parse(macro)
|
372
|
+
|
373
|
+
smml('\root12', false, p).should == "<mroot><mrow><mn>2</mn></mrow><mn>1</mn></mroot>"
|
374
|
+
smml('\root{12}{34}', false, p).should == "<mroot><mrow><mn>34</mn></mrow><mn>12</mn></mroot>"
|
375
|
+
smml('\ROOT{12}{34}', false, p).should == "<mroot><mn>3</mn><mn>12</mn></mroot><mn>4</mn>"
|
376
|
+
lambda{smml('\root', false, p)}.should raise_parse_error('Error in macro(Need more parameter. "").', '', '\root')
|
377
|
+
|
378
|
+
|
379
|
+
math_ml('\begin{braced}{|}{)}\frac12\end{braced}', false, p)[0].should =~ EimXML::DSL.element(:mfenced, :open=>"|", :close=>")"){
|
380
|
+
element(:mrow) do
|
381
|
+
element(:mfrac) do
|
382
|
+
element(:mn).add("1")
|
383
|
+
element(:mn).add("2")
|
384
|
+
end
|
385
|
+
end
|
386
|
+
}
|
387
|
+
|
388
|
+
smml('\begin{sq}{12}{34}a\end{sq}', false, p).should == "<mroot><mrow><mn>12</mn></mrow><mn>34</mn></mroot><mi>a</mi><msqrt><mn>3</mn></msqrt><mn>4</mn>"
|
389
|
+
lambda{smml('\begin{braced}', false, p)}.should raise_parse_error("Need more parameter.", '\begin{braced}', "")
|
390
|
+
lambda{smml('\begin{braced}123', false, p)}.should raise_parse_error('Matching \end not exist.', '\begin{braced}', "123")
|
391
|
+
lambda{smml('\begin{braced}123\end{brace}', false, p)}.should raise_parse_error("Environment mismatched.", '\begin{braced}123\end', '{brace}')
|
392
|
+
smml('\R', false, p).should == "<mrow><mi>ℝ</mi></mrow>"
|
393
|
+
smml('\begin{BB}\end{BB}', false, p).should == "<mrow><mi>𝔸</mi></mrow><mrow><mi>𝔹</mi></mrow>"
|
394
|
+
end
|
395
|
+
|
396
|
+
it "should raise error when macro define circular reference" do
|
397
|
+
macro = <<'EOT'
|
398
|
+
\newcommand{\C}{\C}
|
399
|
+
\newenvironment{E}{\begin{E}}{\end{E}}
|
400
|
+
\newcommand{\D}{\begin{F}\end{F}}
|
401
|
+
\newenvironment{F}{\D}{}
|
402
|
+
EOT
|
403
|
+
ps = new_parser
|
404
|
+
ps.macro.parse(macro)
|
405
|
+
|
406
|
+
lambda{smml('\C', false, ps)}.should raise_parse_error("Circular reference.", "", '\C')
|
407
|
+
lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error("Circular reference.", "", '\begin{E}\end{E}')
|
408
|
+
lambda{smml('\D', false, ps)}.should raise_parse_error("Circular reference.", "", '\D')
|
409
|
+
lambda{smml('\begin{F}\end{F}', false, ps)}.should raise_parse_error("Circular reference.", "", '\begin{F}\end{F}')
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should raise error when macro uses undefined command" do
|
413
|
+
macro = <<'EOT'
|
414
|
+
\newcommand{\C}{\dummy}
|
415
|
+
\newenvironment{E}{\dummy}{}
|
416
|
+
EOT
|
417
|
+
ps = new_parser
|
418
|
+
ps.macro.parse(macro)
|
419
|
+
|
420
|
+
lambda{smml('\C', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\C')
|
421
|
+
lambda{smml('\C', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\C')
|
422
|
+
|
423
|
+
lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', '', '\begin{E}\end{E}')
|
424
|
+
lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\begin{E}\end{E}')
|
425
|
+
end
|
426
|
+
|
427
|
+
it "can be used with macro with option" do
|
428
|
+
macro = <<'EOS'
|
429
|
+
\newcommand{\opt}[1][x]{#1}
|
430
|
+
\newcommand{\optparam}[2][]{#1#2}
|
431
|
+
\newenvironment{newenv}[1][x]{#1}{#1}
|
432
|
+
\newenvironment{optenv}[2][]{#1}{#2}
|
433
|
+
EOS
|
434
|
+
|
435
|
+
p = new_parser
|
436
|
+
p.macro.parse(macro)
|
437
|
+
|
438
|
+
smml('\opt a', false, p).should == "<mi>x</mi><mi>a</mi>"
|
439
|
+
smml('\opt[0] a', false, p).should == "<mn>0</mn><mi>a</mi>"
|
440
|
+
smml('\optparam a', false, p).should == "<mi>a</mi>"
|
441
|
+
smml('\optparam[0] a', false, p).should == "<mn>0</mn><mi>a</mi>"
|
442
|
+
|
443
|
+
smml('\begin{newenv}a\end{newenv}', false, p).should == "<mi>x</mi><mi>a</mi><mi>x</mi>"
|
444
|
+
smml('\begin{newenv}[0]a\end{newenv}', false, p).should == "<mn>0</mn><mi>a</mi><mn>0</mn>"
|
445
|
+
smml('\begin{optenv}0a\end{optenv}', false, p).should == "<mi>a</mi><mn>0</mn>"
|
446
|
+
smml('\begin{optenv}[0]1a\end{optenv}', false, p).should == "<mn>0</mn><mi>a</mi><mn>1</mn>"
|
447
|
+
end
|
448
|
+
|
449
|
+
it "should parse matrix environment" do
|
450
|
+
smml('\begin{matrix}&&\\\\&\end{matrix}').should == "<mtable><mtr><mtd /><mtd /><mtd /></mtr><mtr><mtd /><mtd /></mtr></mtable>"
|
451
|
+
lambda{smml('\begin{matrix}&&\\\\&\end{mat}')}.should raise_parse_error("Environment mismatched.", '\begin{matrix}&&\\\\&\end', "{mat}")
|
452
|
+
lambda{smml('\begin{matrix}&&\\\\&')}.should raise_parse_error("Matching \\end not exist.", '\begin{matrix}&&\\\\&', '')
|
453
|
+
smml('\begin{matrix}\begin{matrix}a&b\\\\c&d\end{matrix}&1\\\\0&1\\\\\end{matrix}').should == "<mtable><mtr><mtd><mtable><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr><mtr><mtd><mi>c</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable></mtd><mtd><mn>1</mn></mtd></mtr><mtr><mtd><mn>0</mn></mtd><mtd><mn>1</mn></mtd></mtr></mtable>"
|
454
|
+
smml('\begin{matrix}\end{matrix}').should == "<mtable />"
|
455
|
+
smml('\begin{matrix}\hline a\\\\b\\\\\hline\end{matrix}').should == "<mtable rowlines='solid none solid'><mtr /><mtr><mtd><mi>a</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd></mtr><mtr /></mtable>"
|
456
|
+
|
457
|
+
smml('\begin{smallmatrix}\end{smallmatrix}').should == "<mtable />"
|
458
|
+
math_ml('\begin{pmatrix}\end{pmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"(", :close=>")")
|
459
|
+
math_ml('\begin{bmatrix}\end{bmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"[", :close=>"]")
|
460
|
+
math_ml('\begin{Bmatrix}\end{Bmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"{", :close=>"}")
|
461
|
+
math_ml('\begin{vmatrix}\end{vmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"|", :close=>"|")
|
462
|
+
math_ml('\begin{Vmatrix}\end{Vmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>EimXML::PCString.new("∥", true), :close=>EimXML::PCString.new("∥", true))
|
463
|
+
end
|
464
|
+
|
465
|
+
it "can be used in safe mode" do
|
466
|
+
Thread.start do
|
467
|
+
$SAFE=1
|
468
|
+
$SAFE.should == 1
|
469
|
+
lambda{smml('\alpha'.taint)}.should_not raise_error
|
470
|
+
end.join
|
471
|
+
|
472
|
+
$SAFE.should == 0
|
473
|
+
end
|
474
|
+
|
475
|
+
it "should parse symbols" do
|
476
|
+
smml('\precneqq').should == "<mo><mfrac linethickness='0' mathsize='1%'><mo>≺</mo><mo>≠</mo></mfrac></mo>"
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|