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.
@@ -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
@@ -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&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