mathml 0.8.1 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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&lt;</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
@@ -0,0 +1,578 @@
1
+ # coding: utf-8
2
+ require "eim_xml/parser"
3
+ require "eim_xml/dsl"
4
+ require "math_ml"
5
+ require "spec/util"
6
+ require "math_ml/symbol/character_reference"
7
+ require "math_ml/symbol/utf8"
8
+
9
+ describe MathML::LaTeX::Parser do
10
+ include MathML::Spec::Util
11
+
12
+ def check_chr(tag, src)
13
+ src.scan(/./) do |c|
14
+ smml(c).should == "<#{tag}>#{c}</#{tag}>"
15
+ end
16
+ end
17
+
18
+ def check_hash(tag, hash)
19
+ hash.each do |k, v|
20
+ smml(k).should == "<#{tag}>#{v}</#{tag}>"
21
+ end
22
+ end
23
+
24
+ def check_entity(tag, hash)
25
+ check_hash(tag, hash.inject({}){|r, i| r[i[0]]="&#{i[1]};"; r})
26
+ end
27
+
28
+ it "Spec#strip_math_ml" do
29
+ src = "<math test='dummy'> <a> b </a> <c> d </c></math>"
30
+ strip_math_ml(src).should == "<a>b</a><c>d</c>"
31
+ end
32
+
33
+ describe "#parse" do
34
+ it "should return math element" do
35
+ ns = "http://www.w3.org/1998/Math/MathML"
36
+
37
+ e = new_parser.parse("")
38
+ e.should match(EimXML::Element.new(:math, :display=>"inline", "xmlns"=>ns))
39
+ e.attributes.keys.size.should == 2
40
+ e.contents.should be_empty
41
+
42
+ e = new_parser.parse("", true)
43
+ e.should match(EimXML::Element.new(:math, :display=>"block", "xmlns"=>ns))
44
+ e.attributes.keys.size.should == 2
45
+ e.contents.should be_empty
46
+
47
+ e = new_parser.parse("", false)
48
+ e.should match(EimXML::Element.new(:math, :display=>"inline", "xmlns"=>ns))
49
+ e.attributes.keys.size.should == 2
50
+ e.contents.should be_empty
51
+ end
52
+
53
+ it "should ignore space" do
54
+ smml("{ a }").should == "<mrow><mi>a</mi></mrow>"
55
+ end
56
+
57
+ it "should process latex block" do
58
+ lambda{smml("test {test} {test")}.should raise_parse_error("Block not closed.", "test {test} ", "{test")
59
+ end
60
+
61
+ it "should raise error when error happened" do
62
+ src = 'a\hoge c'
63
+ lambda{smml(src)}.should raise_parse_error("Undefined command.", "a", '\hoge c')
64
+
65
+ src = '\sqrt\sqrt1'
66
+ lambda{smml(src)}.should raise_parse_error("Syntax error.", '\sqrt\sqrt', "1")
67
+
68
+ src = "a{b"
69
+ lambda{smml(src)}.should raise_parse_error("Block not closed.", "a", "{b")
70
+ end
71
+
72
+ it "should process numerics" do
73
+ smml('1234567890').should == "<mn>1234567890</mn>"
74
+ smml('1.2').should == "<mn>1.2</mn>"
75
+ smml('1.').should == "<mn>1</mn><mo>.</mo>"
76
+ smml('.2').should == "<mn>.2</mn>"
77
+ smml('1.2.3').should == "<mn>1.2</mn><mn>.3</mn>"
78
+ end
79
+
80
+ it "should process alphabets" do
81
+ smml("abc").should == "<mi>a</mi><mi>b</mi><mi>c</mi>"
82
+ check_chr("mi", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
83
+ end
84
+
85
+ it "should process non alphabet command" do
86
+ smml('\|').should == "<mo>&DoubleVerticalBar;</mo>"
87
+ end
88
+
89
+ it "should process space commands" do
90
+ smml('\ ').should == "<mspace width='1em' />"
91
+ smml('\quad').should == "<mspace width='1em' />"
92
+ smml('\qquad').should == "<mspace width='2em' />"
93
+ smml('\,').should == "<mspace width='0.167em' />"
94
+ smml('\:').should == "<mspace width='0.222em' />"
95
+ smml('\;').should == "<mspace width='0.278em' />"
96
+ smml('\!').should == "<mspace width='-0.167em' />"
97
+ smml('~').should == "<mspace width='1em' />"
98
+ end
99
+
100
+ it "should process operators" do
101
+ check_chr("mo", ",.+-*=/()[]|;:!")
102
+ check_entity("mo", {"<"=>"lt", ">"=>"gt", '"'=>"quot"})
103
+ check_hash("mo", {'\backslash'=>'\\', '\%'=>'%', '\{'=>'{', '\}'=>'}', '\$'=>'$', '\#'=>'#'})
104
+ end
105
+
106
+ describe "should process prime" do
107
+ it "entity reference" do
108
+ smml("a'").should == "<msup><mi>a</mi><mo>&prime;</mo></msup>"
109
+ smml("a''").should == "<msup><mi>a</mi><mo>&prime;&prime;</mo></msup>"
110
+ smml("a'''").should == "<msup><mi>a</mi><mo>&prime;&prime;&prime;</mo></msup>"
111
+ smml("'").should == "<msup><none /><mo>&prime;</mo></msup>"
112
+
113
+ lambda{smml("a^b'")}.should raise_parse_error("Double superscript.", "a^b", "'")
114
+
115
+ smml("a'^b").should == "<msup><mi>a</mi><mrow><mo>&prime;</mo><mi>b</mi></mrow></msup>"
116
+ smml("a'''^b").should == "<msup><mi>a</mi><mrow><mo>&prime;&prime;&prime;</mo><mi>b</mi></mrow></msup>"
117
+ smml("a'b").should == "<msup><mi>a</mi><mo>&prime;</mo></msup><mi>b</mi>"
118
+ end
119
+
120
+ it "utf8" do
121
+ @parser = MathML::LaTeX::Parser.new(:symbol=>MathML::Symbol::UTF8)
122
+ smml("a'").should == "<msup><mi>a</mi><mo>′</mo></msup>"
123
+ smml("a'''").should == "<msup><mi>a</mi><mo>′′′</mo></msup>"
124
+ end
125
+
126
+ it "character reference" do
127
+ @parser = MathML::LaTeX::Parser.new(:symbol=>MathML::Symbol::CharacterReference)
128
+ smml("a'").should == "<msup><mi>a</mi><mo>&#x2032;</mo></msup>"
129
+ smml("a'''").should == "<msup><mi>a</mi><mo>&#x2032;&#x2032;&#x2032;</mo></msup>"
130
+ end
131
+ end
132
+
133
+ it "should process sqrt" do
134
+ smml('\sqrt a').should == "<msqrt><mi>a</mi></msqrt>"
135
+ smml('\sqrt[2]3').should == "<mroot><mn>3</mn><mn>2</mn></mroot>"
136
+ smml('\sqrt[2a]3').should == "<mroot><mn>3</mn><mrow><mn>2</mn><mi>a</mi></mrow></mroot>"
137
+ lambda{smml('\sqrt[12')}.should raise_parse_error("Option not closed.", '\sqrt', "[12")
138
+ end
139
+
140
+ it "should process subsup" do
141
+ smml("a_b^c").should == "<msubsup><mi>a</mi><mi>b</mi><mi>c</mi></msubsup>"
142
+ smml("a_b").should == "<msub><mi>a</mi><mi>b</mi></msub>"
143
+ smml("a^b").should == "<msup><mi>a</mi><mi>b</mi></msup>"
144
+ smml("_a^b").should == "<msubsup><none /><mi>a</mi><mi>b</mi></msubsup>"
145
+
146
+ lambda{smml("a_b_c")}.should raise_parse_error("Double subscript.", "a_b", "_c")
147
+ lambda{smml("a^b^c")}.should raise_parse_error("Double superscript.", "a^b", "^c")
148
+ lambda{smml("a_")}.should raise_parse_error("Subscript not exist.", "a_", "")
149
+ lambda{smml("a^")}.should raise_parse_error("Superscript not exist.", "a^", "")
150
+ end
151
+
152
+ it "should process underover" do
153
+ smml('\sum_a^b', true).should == "<munderover><mo>&sum;</mo><mi>a</mi><mi>b</mi></munderover>"
154
+ smml('\sum_a^b').should == "<msubsup><mo>&sum;</mo><mi>a</mi><mi>b</mi></msubsup>"
155
+ smml('\sum_a', true).should == "<munder><mo>&sum;</mo><mi>a</mi></munder>"
156
+ smml('\sum^a', true).should == "<mover><mo>&sum;</mo><mi>a</mi></mover>"
157
+ smml('\sum_a').should == "<msub><mo>&sum;</mo><mi>a</mi></msub>"
158
+ smml('\sum^a').should == "<msup><mo>&sum;</mo><mi>a</mi></msup>"
159
+
160
+ lambda{smml('\sum_b_c')}.should raise_parse_error("Double subscript.", '\sum_b', "_c")
161
+ lambda{smml('\sum^b^c')}.should raise_parse_error("Double superscript.", '\sum^b', "^c")
162
+ lambda{smml('\sum_')}.should raise_parse_error("Subscript not exist.", '\sum_', "")
163
+ lambda{smml('\sum^')}.should raise_parse_error("Superscript not exist.", '\sum^', "")
164
+ end
165
+
166
+ it "should process font commands" do
167
+ 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>"
168
+ 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>"
169
+ 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>"
170
+
171
+ 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>"
172
+ smml('\mathbf12').should == "<mrow><mn mathvariant='bold'>1</mn></mrow><mn>2</mn>"
173
+ 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>"
174
+ 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>"
175
+
176
+ smml('a \mathbb{b c} d').should == "<mi>a</mi><mrow><mrow><mi>&bopf;</mi><mi>&copf;</mi></mrow></mrow><mi>d</mi>"
177
+ smml('a \mathscr{b c} d').should == "<mi>a</mi><mrow><mrow><mi>&bscr;</mi><mi>&cscr;</mi></mrow></mrow><mi>d</mi>"
178
+ smml('a \mathfrak{b c} d').should == "<mi>a</mi><mrow><mrow><mi>&bfr;</mi><mi>&cfr;</mi></mrow></mrow><mi>d</mi>"
179
+ 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>"
180
+ smml('\bm ab').should == "<mrow><mi mathvariant='bold-italic'>a</mi></mrow><mi>b</mi>"
181
+
182
+ lambda{smml('\mathit')}.should raise_parse_error("Syntax error.", '\mathit', "")
183
+ lambda{smml('\mathrm')}.should raise_parse_error("Syntax error.", '\mathrm', "")
184
+ lambda{smml('\mathbf')}.should raise_parse_error("Syntax error.", '\mathbf', "")
185
+ lambda{smml('\mathbb')}.should raise_parse_error("Syntax error.", '\mathbb', "")
186
+ lambda{smml('\mathscr')}.should raise_parse_error("Syntax error.", '\mathscr', "")
187
+ lambda{smml('\mathfrak')}.should raise_parse_error("Syntax error.", '\mathfrak', "")
188
+ end
189
+
190
+ it "should process mbox" do
191
+ smml('a\mbox{b c}d').should == "<mi>a</mi><mtext>b c</mtext><mi>d</mi>"
192
+ smml('\mbox{<>\'"&}').should == '<mtext>&lt;&gt;&apos;&quot;&amp;</mtext>'
193
+ end
194
+
195
+ it "should process frac" do
196
+ smml('\frac ab').should == "<mfrac><mi>a</mi><mi>b</mi></mfrac>"
197
+ smml('\frac12').should == "<mfrac><mn>1</mn><mn>2</mn></mfrac>"
198
+
199
+ lambda{smml('\frac a')}.should raise_parse_error("Syntax error.", '\frac a', "")
200
+ end
201
+
202
+ it "should process environment" do
203
+ lambda{smml('{\begin}rest')}.should raise_parse_error("Environment name not exist.", '{\begin', '}rest')
204
+
205
+ lambda{smml('{\begin{array}{c}dummy}rest')}.should raise_parse_error('Matching \end not exist.', '{\begin{array}{c}dummy', '}rest')
206
+
207
+ lambda{smml('\begin{array}c dummy\end{test}')}.should raise_parse_error("Environment mismatched.", '\begin{array}c dummy\end', "{test}")
208
+
209
+ lambda{smml('\left(\begin{array}\right)')}.should raise_parse_error("Syntax error.", '\left(\begin{array}', '\right)')
210
+ end
211
+
212
+ it "should process array" do
213
+ 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>"
214
+
215
+ 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>"
216
+
217
+ smml('\begin{array}{c}\end{array}').should == "<mtable />"
218
+
219
+ lambda{smml('\begin{array}\end{array}')}.should raise_parse_error('Syntax error.', '\begin{array}', '\end{array}')
220
+
221
+ lambda{smml('\begin{array}{a}\end{array}')}.should raise_parse_error("Syntax error.", '\begin{array}{', 'a}\end{array}')
222
+
223
+ 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}')
224
+
225
+ lambda{smml('\begin{array}{cc}a\end{array}')}.should raise_parse_error("Need more column.", '\begin{array}{cc}a', '\end{array}')
226
+
227
+ lambda{smml('\begin{array}{c}a&\end{array}')}.should raise_parse_error("Too many column.", '\begin{array}{c}a', '&\end{array}')
228
+
229
+ smml('\begin{array}{cc}&\end{array}').should == "<mtable><mtr><mtd /><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}{@{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>"
247
+
248
+ math_ml('\left\{\begin{array}ca_b\end{array}\right\}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
249
+ element :mrow do
250
+ element :mtable do
251
+ element :mtr do
252
+ element :mtd do
253
+ element :msub do
254
+ element(:mi).add("a")
255
+ element(:mi).add("b")
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
261
+ }
262
+
263
+ 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>"
264
+ 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>"
265
+ smml('\begin{array}{c}\hline c\end{array}').should == "<mtable rowlines='solid'><mtr /><mtr><mtd><mi>c</mi></mtd></mtr></mtable>"
266
+ 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>"
267
+ 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>"
268
+ end
269
+
270
+ it "should parse \\left and \\right" do
271
+ math_ml('\left(\frac12\right)')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
272
+ element :mrow do
273
+ element :mfrac do
274
+ element(:mn).add("1")
275
+ element(:mn).add("2")
276
+ end
277
+ end
278
+ }
279
+
280
+ math_ml('\left \lfloor a\right \rfloor')[0].should =~ EimXML::DSL.element(:mfenced, :open=>EimXML::PCString.new("&lfloor;", true), :close=>EimXML::PCString.new("&rfloor;", true)){
281
+ element :mrow do
282
+ element(:mi).add("a")
283
+ end
284
+ }
285
+
286
+ math_ml('\left \{ a \right \}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
287
+ element :mrow do
288
+ element(:mi).add("a")
289
+ end
290
+ }
291
+
292
+ math_ml('\left\{\begin{array}c\begin{array}ca\end{array}\end{array}\right\}')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"{", :close=>"}"){
293
+ element :mrow do
294
+ element :mtable do
295
+ element :mtr do
296
+ element :mtd do
297
+ element :mtable do
298
+ element :mtr do
299
+ element :mtd do
300
+ element(:mi).add("a")
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+ }
309
+
310
+ math_ml('\left(\sum_a\right)')[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
311
+ element :mrow do
312
+ element :msub do
313
+ element(:mo).add(EimXML::PCString.new("&sum;", true))
314
+ element(:mi).add("a")
315
+ end
316
+ end
317
+ }
318
+
319
+ math_ml('\left(\sum_a\right)', true)[0].should =~ EimXML::DSL.element(:mfenced, :open=>"(", :close=>")"){
320
+ element :mrow do
321
+ element :munder do
322
+ element(:mo).add(EimXML::PCString.new("&sum;", true))
323
+ element(:mi).add("a")
324
+ end
325
+ end
326
+ }
327
+
328
+ lambda{smml('\left(test')}.should raise_parse_error("Brace not closed.", '\left', '(test')
329
+
330
+ math_ml('\left\|a\right\|')[0].should =~ EimXML::DSL.element(:mfenced, :open=>EimXML::PCString.new("&DoubleVerticalBar;", true), :close=>EimXML::PCString.new("&DoubleVerticalBar;", true)){
331
+ element :mrow do
332
+ element(:mi).add("a")
333
+ end
334
+ }
335
+
336
+ lambda{smml('\left')}.should raise_parse_error("Need brace here.", '\left', "")
337
+ end
338
+
339
+ it "should parse overs" do
340
+ smml('\hat a').should == "<mover><mi>a</mi><mo>&circ;</mo></mover>"
341
+ smml('\hat12').should == "<mover><mn>1</mn><mo>&circ;</mo></mover><mn>2</mn>"
342
+ lambda{smml('{\hat}a')}.should raise_parse_error("Syntax error.", '{\hat', '}a')
343
+ end
344
+
345
+ it "should parse unders" do
346
+ smml('\underline a').should == "<munder><mi>a</mi><mo>&macr;</mo></munder>"
347
+ smml('\underline12').should == "<munder><mn>1</mn><mo>&macr;</mo></munder><mn>2</mn>"
348
+ lambda{smml('{\underline}a')}.should raise_parse_error("Syntax error.", '{\underline', '}a')
349
+ end
350
+
351
+ it "should parse stackrel" do
352
+ smml('\stackrel\to=').should == "<mover><mo>=</mo><mo>&rightarrow;</mo></mover>"
353
+ smml('\stackrel12').should == "<mover><mn>2</mn><mn>1</mn></mover>"
354
+ end
355
+
356
+ it "should parse comment" do
357
+ smml('a%b').should == "<mi>a</mi>"
358
+ end
359
+
360
+ it "should parse entity" do
361
+ p = new_parser
362
+ lambda{smml('\entity{therefore}', false, p)}.should raise_parse_error("Unregistered entity.", '\entity{', "therefore}")
363
+
364
+ p.unsecure_entity = true
365
+ smml('\entity{therefore}', false, p).should == "<mo>&therefore;</mo>"
366
+
367
+ p.unsecure_entity = false
368
+ lambda{smml('\entity{therefore}', false, p)}.should raise_parse_error("Unregistered entity.", '\entity{', "therefore}")
369
+
370
+ p.add_entity(['therefore'])
371
+ smml('\entity{therefore}', false, p).should == "<mo>&therefore;</mo>"
372
+ end
373
+
374
+ it "should parse backslash" do
375
+ smml('\\\\').should == "<br xmlns='http://www.w3.org/1999/xhtml' />"
376
+ end
377
+
378
+ it "can be used with macro" do
379
+ macro = <<'EOS'
380
+ \newcommand{\root}[2]{\sqrt[#1]{#2}}
381
+ \newcommand{\ROOT}[2]{\sqrt[#1]#2}
382
+ \newenvironment{braced}[2]{\left#1}{\right#2}
383
+ \newenvironment{sq}[2]{\sqrt[#2]{#1}}{\sqrt#2}
384
+ \newcommand{\R}{\mathbb R}
385
+ \newenvironment{BB}{\mathbb A}{\mathbb B}
386
+ EOS
387
+ p = new_parser
388
+ p.macro.parse(macro)
389
+
390
+ smml('\root12', false, p).should == "<mroot><mrow><mn>2</mn></mrow><mn>1</mn></mroot>"
391
+ smml('\root{12}{34}', false, p).should == "<mroot><mrow><mn>34</mn></mrow><mn>12</mn></mroot>"
392
+ smml('\ROOT{12}{34}', false, p).should == "<mroot><mn>3</mn><mn>12</mn></mroot><mn>4</mn>"
393
+ lambda{smml('\root', false, p)}.should raise_parse_error('Error in macro(Need more parameter. "").', '', '\root')
394
+
395
+
396
+ math_ml('\begin{braced}{|}{)}\frac12\end{braced}', false, p)[0].should =~ EimXML::DSL.element(:mfenced, :open=>"|", :close=>")"){
397
+ element(:mrow) do
398
+ element(:mfrac) do
399
+ element(:mn).add("1")
400
+ element(:mn).add("2")
401
+ end
402
+ end
403
+ }
404
+
405
+ 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>"
406
+ lambda{smml('\begin{braced}', false, p)}.should raise_parse_error("Need more parameter.", '\begin{braced}', "")
407
+ lambda{smml('\begin{braced}123', false, p)}.should raise_parse_error('Matching \end not exist.', '\begin{braced}', "123")
408
+ lambda{smml('\begin{braced}123\end{brace}', false, p)}.should raise_parse_error("Environment mismatched.", '\begin{braced}123\end', '{brace}')
409
+ smml('\R', false, p).should == "<mrow><mi>&Ropf;</mi></mrow>"
410
+ smml('\begin{BB}\end{BB}', false, p).should == "<mrow><mi>&Aopf;</mi></mrow><mrow><mi>&Bopf;</mi></mrow>"
411
+ end
412
+
413
+ it "should raise error when macro define circular reference" do
414
+ macro = <<'EOT'
415
+ \newcommand{\C}{\C}
416
+ \newenvironment{E}{\begin{E}}{\end{E}}
417
+ \newcommand{\D}{\begin{F}\end{F}}
418
+ \newenvironment{F}{\D}{}
419
+ EOT
420
+ ps = new_parser
421
+ ps.macro.parse(macro)
422
+
423
+ lambda{smml('\C', false, ps)}.should raise_parse_error("Circular reference.", "", '\C')
424
+ lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error("Circular reference.", "", '\begin{E}\end{E}')
425
+ lambda{smml('\D', false, ps)}.should raise_parse_error("Circular reference.", "", '\D')
426
+ lambda{smml('\begin{F}\end{F}', false, ps)}.should raise_parse_error("Circular reference.", "", '\begin{F}\end{F}')
427
+ end
428
+
429
+ it "should raise error when macro uses undefined command" do
430
+ macro = <<'EOT'
431
+ \newcommand{\C}{\dummy}
432
+ \newenvironment{E}{\dummy}{}
433
+ EOT
434
+ ps = new_parser
435
+ ps.macro.parse(macro)
436
+
437
+ lambda{smml('\C', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\C')
438
+ lambda{smml('\C', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\C')
439
+
440
+ lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', '', '\begin{E}\end{E}')
441
+ lambda{smml('\begin{E}\end{E}', false, ps)}.should raise_parse_error('Error in macro(Undefined command. "\dummy").', "", '\begin{E}\end{E}')
442
+ end
443
+
444
+ it "can be used with macro with option" do
445
+ macro = <<'EOS'
446
+ \newcommand{\opt}[1][x]{#1}
447
+ \newcommand{\optparam}[2][]{#1#2}
448
+ \newenvironment{newenv}[1][x]{#1}{#1}
449
+ \newenvironment{optenv}[2][]{#1}{#2}
450
+ EOS
451
+
452
+ p = new_parser
453
+ p.macro.parse(macro)
454
+
455
+ smml('\opt a', false, p).should == "<mi>x</mi><mi>a</mi>"
456
+ smml('\opt[0] a', false, p).should == "<mn>0</mn><mi>a</mi>"
457
+ smml('\optparam a', false, p).should == "<mi>a</mi>"
458
+ smml('\optparam[0] a', false, p).should == "<mn>0</mn><mi>a</mi>"
459
+
460
+ smml('\begin{newenv}a\end{newenv}', false, p).should == "<mi>x</mi><mi>a</mi><mi>x</mi>"
461
+ smml('\begin{newenv}[0]a\end{newenv}', false, p).should == "<mn>0</mn><mi>a</mi><mn>0</mn>"
462
+ smml('\begin{optenv}0a\end{optenv}', false, p).should == "<mi>a</mi><mn>0</mn>"
463
+ smml('\begin{optenv}[0]1a\end{optenv}', false, p).should == "<mn>0</mn><mi>a</mi><mn>1</mn>"
464
+ end
465
+
466
+ it "should parse matrix environment" do
467
+ smml('\begin{matrix}&&\\\\&\end{matrix}').should == "<mtable><mtr><mtd /><mtd /><mtd /></mtr><mtr><mtd /><mtd /></mtr></mtable>"
468
+ lambda{smml('\begin{matrix}&&\\\\&\end{mat}')}.should raise_parse_error("Environment mismatched.", '\begin{matrix}&&\\\\&\end', "{mat}")
469
+ lambda{smml('\begin{matrix}&&\\\\&')}.should raise_parse_error("Matching \\end not exist.", '\begin{matrix}&&\\\\&', '')
470
+ 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>"
471
+ smml('\begin{matrix}\end{matrix}').should == "<mtable />"
472
+ 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>"
473
+
474
+ smml('\begin{smallmatrix}\end{smallmatrix}').should == "<mtable />"
475
+ math_ml('\begin{pmatrix}\end{pmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"(", :close=>")")
476
+ math_ml('\begin{bmatrix}\end{bmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"[", :close=>"]")
477
+ math_ml('\begin{Bmatrix}\end{Bmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"{", :close=>"}")
478
+ math_ml('\begin{vmatrix}\end{vmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>"|", :close=>"|")
479
+ math_ml('\begin{Vmatrix}\end{Vmatrix}')[0].should =~ EimXML::Element.new(:mfenced, :open=>EimXML::PCString.new("&DoubleVerticalBar;", true), :close=>EimXML::PCString.new("&DoubleVerticalBar;", true))
480
+ end
481
+
482
+ it "can be used in safe mode" do
483
+ Thread.start do
484
+ $SAFE=1
485
+ $SAFE.should == 1
486
+ lambda{smml('\alpha'.taint)}.should_not raise_error
487
+ end.join
488
+
489
+ $SAFE.should == 0
490
+ end
491
+
492
+ it "should parse symbols" do
493
+ smml('\precneqq').should == "<mo>&#x2ab5;</mo>"
494
+ end
495
+ end
496
+
497
+ context ".new should accept symbol table" do
498
+ it "character reference" do
499
+ @parser = MathML::LaTeX::Parser.new(:symbol=>MathML::Symbol::CharacterReference)
500
+ smml('\alpha').should == "<mi>&#x3b1;</mi>"
501
+ smml('\mathbb{abcABC}').should == "<mrow><mrow><mi>&#x1d552;</mi><mi>&#x1d553;</mi><mi>&#x1d554;</mi><mi>&#x1d538;</mi><mi>&#x1d539;</mi><mi>&#x2102;</mi></mrow></mrow>"
502
+ smml('\mathscr{abcABC}').should == "<mrow><mrow><mi>&#x1d4b6;</mi><mi>&#x1d4b7;</mi><mi>&#x1d4b8;</mi><mi>&#x1d49c;</mi><mi>&#x212c;</mi><mi>&#x1d49e;</mi></mrow></mrow>"
503
+ smml('\mathfrak{abcABC}').should == "<mrow><mrow><mi>&#x1d51e;</mi><mi>&#x1d51f;</mi><mi>&#x1d520;</mi><mi>&#x1d504;</mi><mi>&#x1d505;</mi><mi>&#x212d;</mi></mrow></mrow>"
504
+ end
505
+
506
+ it "utf8" do
507
+ @parser = MathML::LaTeX::Parser.new(:symbol=>MathML::Symbol::UTF8)
508
+ smml('\alpha').should == "<mi>α</mi>"
509
+ smml('\mathbb{abcABC}').should == "<mrow><mrow><mi>𝕒</mi><mi>𝕓</mi><mi>𝕔</mi><mi>𝔸</mi><mi>𝔹</mi><mi>ℂ</mi></mrow></mrow>"
510
+ smml('\mathscr{abcABC}').should == "<mrow><mrow><mi>𝒶</mi><mi>𝒷</mi><mi>𝒸</mi><mi>𝒜</mi><mi>ℬ</mi><mi>𝒞</mi></mrow></mrow>"
511
+ smml('\mathfrak{abcABC}').should == "<mrow><mrow><mi>𝔞</mi><mi>𝔟</mi><mi>𝔠</mi><mi>𝔄</mi><mi>𝔅</mi><mi>ℭ</mi></mrow></mrow>"
512
+ end
513
+ end
514
+
515
+ context "#symbol_table" do
516
+ it "should return when .new was given name of symbol-module" do
517
+ ps = MathML::LaTeX::Parser
518
+ symbol = MathML::Symbol
519
+
520
+ ps.new(:symbol=>symbol::UTF8).symbol_table.should == symbol::UTF8
521
+ ps.new(:symbol=>symbol::EntityReference).symbol_table.should == symbol::EntityReference
522
+ ps.new(:symbol=>symbol::CharacterReference).symbol_table.should == symbol::CharacterReference
523
+
524
+ ps.new(:symbol=>:utf8).symbol_table.should == symbol::UTF8
525
+ ps.new(:symbol=>:entity).symbol_table.should == symbol::EntityReference
526
+ ps.new(:symbol=>:character).symbol_table.should == symbol::CharacterReference
527
+
528
+ ps.new.symbol_table.should == symbol::EntityReference
529
+ ps.new(:symbol=>nil).symbol_table.should == symbol::EntityReference
530
+ end
531
+
532
+ context "should return default symbol module" do
533
+ before do
534
+ @loaded_features = $LOADED_FEATURES.dup
535
+ $LOADED_FEATURES.delete_if{|i| i=~/math_ml/}
536
+ if ::Object.const_defined?(:MathML)
537
+ @MathML = ::Object.const_get(:MathML)
538
+ ::Object.module_eval{remove_const(:MathML)}
539
+ end
540
+ end
541
+
542
+ after do
543
+ $LOADED_FEATURES.clear
544
+ $LOADED_FEATURES.push(@loaded_features.shift) until @loaded_features.empty?
545
+ if @MathML
546
+ ::Object.module_eval{remove_const(:MathML)}
547
+ ::Object.const_set(:MathML, @MathML)
548
+ end
549
+ end
550
+
551
+ it "character entity reference version by default" do
552
+ require("math_ml").should be_true
553
+ MathML::LaTeX::Parser.new.symbol_table.should == MathML::Symbol::EntityReference
554
+ end
555
+
556
+ describe "character entity reference version when set by requiring" do
557
+ it do
558
+ require("math_ml/symbol/entity_reference").should be_true
559
+ MathML::LaTeX::Parser.new.symbol_table.should == MathML::Symbol::EntityReference
560
+ end
561
+ end
562
+
563
+ describe "utf8 version when set by requiring" do
564
+ it do
565
+ require("math_ml/symbol/utf8").should be_true
566
+ MathML::LaTeX::Parser.new.symbol_table.should == MathML::Symbol::UTF8
567
+ end
568
+ end
569
+
570
+ describe "numeric character reference version when set by requiring" do
571
+ it do
572
+ require("math_ml/symbol/character_reference").should be_true
573
+ MathML::LaTeX::Parser.new.symbol_table.should == MathML::Symbol::CharacterReference
574
+ end
575
+ end
576
+ end
577
+ end
578
+ end