mathemagical 0.0.1

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,351 @@
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 "mathemagical"
10
+
11
+ module Mathemagical::Util
12
+ ESCAPES = {"<"=>"lt",
13
+ ">"=>"gt",
14
+ "&"=>"amp",
15
+ "\""=>"quot",
16
+ "'"=>"apos"
17
+ }
18
+ INVALID_RE = /(?!)/
19
+ EQNARRAY_RE = /\\begin\s*\{eqnarray\}(#{Mathemagical::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
+ Mathemagical::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
+ Mathemagical::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 Mathemagical::Util
71
+
72
+ @@default_latex = nil
73
+ DEFAULT = {
74
+ :delimiter=>"\001",
75
+ :math_env_list=>[
76
+ /\$((?:\\.|[^\\\$])#{Mathemagical::LaTeX::MBEC}*?)\$/m,
77
+ /\\\((#{Mathemagical::LaTeX::MBEC}*?)\\\)/m
78
+ ],
79
+ :dmath_env_list=>[
80
+ /\$\$(#{Mathemagical::LaTeX::MBEC}*?)\$\$/m,
81
+ /\\\[(#{Mathemagical::LaTeX::MBEC}*?)\\\]/m
82
+ ],
83
+ :escape_list=>[
84
+ /\\(.)/m
85
+ ],
86
+ :through_list=>[
87
+ ],
88
+ :escape_any=> false,
89
+ :without_parse=>false
90
+ }
91
+
92
+ def initialize(options = {})
93
+ @params = DEFAULT.merge(options)
94
+ @params[:parser] = Mathemagical::LaTeX::Parser.new unless @params[:parser] || @params[:without_parse]
95
+
96
+ @params[:math_envs] = collect_regexp(@params[:math_env_list])
97
+ @params[:dmath_envs] = collect_regexp(@params[:dmath_env_list])
98
+ @params[:escapes] = collect_regexp(@params[:escape_list])
99
+ @params[:throughs] = collect_regexp(@params[:through_list])
100
+ reset_encode_proc
101
+ reset_rescue_proc
102
+ reset_decode_proc
103
+ reset_unencode_proc
104
+ end
105
+
106
+ def reset_encode_proc
107
+ @encode_proc_re = INVALID_RE
108
+ @encode_proc = nil
109
+ end
110
+
111
+ def set_encode_proc(*re, &proc)
112
+ @encode_proc_re = collect_regexp(re)
113
+ @encode_proc = proc
114
+ end
115
+
116
+ def reset_rescue_proc
117
+ @rescue_proc = nil
118
+ end
119
+
120
+ def set_rescue_proc(&proc)
121
+ @rescue_proc = proc
122
+ end
123
+
124
+ def reset_decode_proc
125
+ @decode_proc = nil
126
+ end
127
+
128
+ def set_decode_proc(&proc)
129
+ @decode_proc = proc
130
+ end
131
+
132
+ def set_unencode_proc(&proc)
133
+ @unencode_proc = proc
134
+ end
135
+
136
+ def reset_unencode_proc
137
+ @unencode_proc = nil
138
+ end
139
+
140
+ def encode(src, *proc_re, &proc)
141
+ if proc_re.size>0 && proc_re[0].is_a?(MathData)
142
+ data = proc_re.shift
143
+ else
144
+ data = MathData.new
145
+ end
146
+
147
+ proc_re = proc_re.size==0 ? @encode_proc_re : collect_regexp(proc_re)
148
+ proc = @encode_proc unless proc
149
+
150
+ s = StringScanner.new(src)
151
+ encoded = ""
152
+
153
+ until s.eos?
154
+ if s.scan(/(.*?)(((((#{@params[:throughs]})|#{@params[:dmath_envs]})|#{@params[:math_envs]})|#{proc_re})|#{@params[:escapes]})/m)
155
+ encoded << s[1]
156
+ case
157
+ when s[6]
158
+ encoded << s[6]
159
+ when s[5], s[4]
160
+ env_src = s[5] || s[4]
161
+ if @params[:dmath_envs]=~env_src
162
+ encoded << "#{@params[:delimiter]}d#{data.dsrc_list.size}#{@params[:delimiter]}"
163
+ data.dsrc_list << env_src
164
+ else
165
+ encoded << "#{@params[:delimiter]}m#{data.msrc_list.size}#{@params[:delimiter]}"
166
+ data.msrc_list << env_src
167
+ end
168
+ when s[3]
169
+ size = s[3].size
170
+ s.pos = left = s.pos-size
171
+ if r=proc.call(s)
172
+ right = s.pos
173
+ encoded << "#{@params[:delimiter]}u#{data.user_list.size}#{@params[:delimiter]}"
174
+ data.user_list << r
175
+ data.usrc_list << s.string[left...right]
176
+ else
177
+ encoded << s.peek(size)
178
+ s.pos = s.pos+size
179
+ end
180
+ when s[2]
181
+ encoded << "#{@params[:delimiter]}e#{data.escape_list.size}#{@params[:delimiter]}"
182
+ @params[:escapes]=~s[2]
183
+ data.esrc_list << s[2]
184
+ data.escape_list << escapeXML($+, true)
185
+ end
186
+ else
187
+ encoded << s.rest
188
+ s.terminate
189
+ end
190
+ end
191
+
192
+ parse(data, @params[:parser]) unless @params[:without_parse]
193
+
194
+ return encoded, data
195
+ end
196
+
197
+ def error_to_html(e)
198
+ "<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 />"
199
+ end
200
+
201
+ def latex_parser
202
+ @params[:parser] = Mathemagical::LaTeX::Parser.new unless @params[:parser]
203
+ @params[:parser]
204
+ end
205
+
206
+ def parse(data, parser=nil)
207
+ parser = latex_parser unless parser
208
+ (data.math_list.size...data.msrc_list.size).each do |i|
209
+ begin
210
+ @params[:math_envs]=~data.msrc_list[i]
211
+ data.math_list[i] = parser.parse($+)
212
+ rescue Mathemagical::LaTeX::ParseError => e
213
+ if @rescue_proc
214
+ data.math_list[i] = @rescue_proc.call(e)
215
+ else
216
+ data.math_list[i] = error_to_html(e)
217
+ end
218
+ end
219
+ end
220
+ (data.dmath_list.size...data.dsrc_list.size).each do |i|
221
+ begin
222
+ @params[:dmath_envs]=~data.dsrc_list[i]
223
+ data.dmath_list[i] = parser.parse($+, true)
224
+ rescue Mathemagical::LaTeX::ParseError => e
225
+ if @rescue_proc
226
+ data.dmath_list[i] = @rescue_proc.call(e)
227
+ else
228
+ data.dmath_list[i] = error_to_html(e)
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ def decode(encoded, data, without_parsed = false, &proc)
235
+ return nil if encoded==nil
236
+ proc = @decode_proc unless proc
237
+ encoded.gsub(/#{Regexp.escape(@params[:delimiter])}([demu])(\d+)#{Regexp.escape(@params[:delimiter])}/) do
238
+ i = $2.to_i
239
+ t, d, s =
240
+ case $1
241
+ when "d"
242
+ [:dmath, without_parsed ? escapeXML(data.dsrc_list[i], true) : data.dmath_list[i], data.dsrc_list[i]]
243
+ when "e"
244
+ [:escape, data.escape_list[i], data.esrc_list[i]]
245
+ when "m"
246
+ [:math, without_parsed ? escapeXML(data.msrc_list[i], true) : data.math_list[i], data.msrc_list[i]]
247
+ when "u"
248
+ [:user, data.user_list[i], data.usrc_list[i]]
249
+ end
250
+ if proc
251
+ proc.call(d, :type=>t, :index=>i, :src=>s) || d
252
+ else
253
+ d
254
+ end
255
+ end
256
+ end
257
+
258
+ def decode_partial(type, encoded, data, &proc)
259
+ return nil if encoded==nil
260
+ head =
261
+ case type
262
+ when :math
263
+ "m"
264
+ when :dmath
265
+ "d"
266
+ when :escape
267
+ "e"
268
+ when :user
269
+ "u"
270
+ else
271
+ return
272
+ end
273
+ encoded.gsub(/#{Regexp.escape(@params[:delimiter])}#{head}(\d+)#{Regexp.escape(@params[:delimiter])}/) do
274
+ i = $1.to_i
275
+ t, d, s =
276
+ case head
277
+ when "d"
278
+ [:dmath, data.dmath_list[i], data.dsrc_list[i]]
279
+ when "e"
280
+ [:escape, data.escape_list[i], data.esrc_list[i]]
281
+ when "m"
282
+ [:math, data.math_list[i], data.msrc_list[i]]
283
+ when "u"
284
+ [:user, data.user_list[i], data.usrc_list[i]]
285
+ end
286
+ if proc
287
+ proc.call(d, :type=>t, :index=>i, :src=>s) || "#{@params[:delimiter]}#{head}#{i}#{@params[:delimiter]}"
288
+ else
289
+ d
290
+ end
291
+ end
292
+ end
293
+
294
+ def unencode(encoded, data, without_escape=false, &proc)
295
+ return nil if encoded==nil
296
+ proc = @unencode_proc unless proc
297
+ encoded.gsub(/#{Regexp.escape(@params[:delimiter])}([demu])(\d+)#{Regexp.escape(@params[:delimiter])}/) do
298
+ i = $2.to_i
299
+ t, s =
300
+ case $1
301
+ when "d"
302
+ [:dmath, data.dsrc_list[i]]
303
+ when "e"
304
+ [:escape, data.esrc_list[i]]
305
+ when "m"
306
+ [:math, data.msrc_list[i]]
307
+ when "u"
308
+ [:user, data.usrc_list[i]]
309
+ end
310
+ s = escapeXML(s, true) unless without_escape
311
+ if proc
312
+ proc.call(s, :type=>t, :index=>i) || s
313
+ else
314
+ s
315
+ end
316
+ end
317
+ end
318
+
319
+ def self.encode(src)
320
+ @@default_latex = self.new unless @@default_latex
321
+ @@default_latex.encode(src)
322
+ end
323
+
324
+ def self.decode(src, data)
325
+ @@default_latex.decode(src, data)
326
+ end
327
+
328
+ def parse_eqnarray(src, parser=nil)
329
+ src = "\\begin{array}{ccc}#{src}\\end{array}"
330
+ parser = latex_parser unless parser
331
+ begin
332
+ parser.parse(src, true)
333
+ rescue Mathemagical::LaTeX::ParseError => e
334
+ e = Mathemagical::LaTeX::ParseError.new(e.message,
335
+ e.rest.sub(/\\end\{array\}\z/, '\end{eqnarray}'),
336
+ e.done.sub(/\A\\begin\{array\}\{ccc\}/, '\begin{eqnarray}'))
337
+ @rescue_proc ? @rescue_proc.call(e) : error_to_html(e)
338
+ end
339
+ end
340
+
341
+ def parse_single_command(src, parser=nil)
342
+ s = src[SINGLE_COMMAND_RE, 1]
343
+ parser = latex_parser unless parser
344
+ begin
345
+ parser.parse(s)
346
+ rescue Mathemagical::LaTeX::ParseError => e
347
+ src[SINGLE_COMMAND_RE, 2]
348
+ end
349
+ end
350
+ end
351
+ end
@@ -0,0 +1,86 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'mathemagical'
16
+ s.version = '0.0.1'
17
+ s.date = '2013-02-16'
18
+ s.rubyforge_project = 'mathemagical'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.summary = "MathML parsing library based on the math_ml gem."
23
+ s.description = "MathML parsing library based on the math_ml gem with modification."
24
+
25
+ ## List the primary authors. If there are a bunch of authors, it's probably
26
+ ## better to set the email to an email list or something. If you don't have
27
+ ## a custom homepage, consider using your GitHub URL or the like.
28
+ s.authors = ["Jeremy McAnally", "KURODA Hiraku"]
29
+ s.email = 'jeremy@github.com'
30
+ s.homepage = 'http://github.com/jm/mathmagical'
31
+
32
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
34
+ s.require_paths = %w[lib]
35
+
36
+ ## If your gem includes any executables, list them here.
37
+ s.executables = ["mathemagical"]
38
+
39
+ ## Specify any RDoc options here. You'll want to add your README and
40
+ ## LICENSE files to the extra_rdoc_files list.
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.extra_rdoc_files = %w[README.md LICENSE]
43
+
44
+ ## List your runtime dependencies here. Runtime dependencies are those
45
+ ## that are needed for an end user to actually USE your code.
46
+ s.add_dependency('htmlentities')
47
+
48
+ ## List your development dependencies here. Development dependencies are
49
+ ## those that are only needed during development
50
+ s.add_development_dependency('eim_xml')
51
+
52
+ ## Leave this section as-is. It will be automatically generated from the
53
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
54
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
55
+ # = MANIFEST =
56
+ s.files = %w[
57
+ LICENSE
58
+ README.md
59
+ Rakefile
60
+ bin/mathemagical
61
+ lib/mathemagical.rb
62
+ lib/mathemagical/element.rb
63
+ lib/mathemagical/latex.rb
64
+ lib/mathemagical/latex/builtin.rb
65
+ lib/mathemagical/latex/builtin/symbol.rb
66
+ lib/mathemagical/string.rb
67
+ lib/mathemagical/symbol/character_reference.rb
68
+ lib/mathemagical/symbol/entity_reference.rb
69
+ lib/mathemagical/symbol/utf8.rb
70
+ lib/mathemagical/util.rb
71
+ mathemagical.gemspec
72
+ spec/math_ml/element_spec.rb
73
+ spec/math_ml/latex/macro_spec.rb
74
+ spec/math_ml/latex/parser_spec.rb
75
+ spec/math_ml/latex/scanner_spec.rb
76
+ spec/math_ml/string_spec.rb
77
+ spec/math_ml/util_spec.rb
78
+ spec/math_ml_spec.rb
79
+ spec/util.rb
80
+ ]
81
+ # = MANIFEST =
82
+
83
+ ## Test files will be grabbed from the file list. Make sure the path glob
84
+ ## matches what you actually use.
85
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
86
+ end
@@ -0,0 +1,32 @@
1
+ require "mathemagical"
2
+
3
+ describe Mathemagical::Element do
4
+ it "#display_style and #as_display_style" do
5
+ Mathemagical::Element.new("test").display_style.should == nil
6
+ e = Mathemagical::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 = Mathemagical::Element.new("super")
14
+ s = Mathemagical::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 = Mathemagical::Element.new("e")
29
+ e << "test<"
30
+ e.to_s.should == "<e>test&lt;</e>"
31
+ end
32
+ end