mathemagical 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ Mathemagical
2
+ ============
3
+
4
+ ## Usage and such
5
+
6
+ Things will go here. Oh, yes. They will.
7
+
8
+ ## Origins
9
+
10
+ The `math_ml` gem is a perfectly fine MathML parser, but for my needs, it had a few issues:
11
+
12
+ * It requires `eim_xml`. I'd prefer not to introduce an XML generation library into production if I don't have to. This library uses a simple homegrown XML generation system that covers all our needs without an extra, unverified gem floating about.
13
+ * It lacks a binscript. Not a huge deal, but I'd have to write one anyhow since it's GPL2.
14
+ * It's crufty and had a few bugs. I'll continually be improving the quality of the code as I work on this.
15
+ * There was no place to contribute to the code that I could find.
16
+
17
+ So I decided to fork it. Since most interpretations of the GPL say that if you fork, you must rename, I decided to rename my fork to Mathemagical.
18
+
19
+ ## License
20
+
21
+ The original `math_ml` gem is license under the GPL Version 2. My modifications are licensed under the BSD License or whatever is most liberal, but since the original code is all GPL2, it doesn't really matter much.
@@ -0,0 +1,136 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ require 'rdoc/task'
47
+ Rake::RDocTask.new do |rdoc|
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "#{name} #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
53
+
54
+ desc "Open an irb session preloaded with this library"
55
+ task :console do
56
+ sh "irb -rubygems -r ./lib/#{name}.rb"
57
+ end
58
+
59
+ #############################################################################
60
+ #
61
+ # Custom tasks (add your own tasks here)
62
+ #
63
+ #############################################################################
64
+
65
+ require 'rspec/core/rake_task'
66
+ RSpec::Core::RakeTask.new(:spec)
67
+
68
+ task :default => :spec
69
+
70
+ #############################################################################
71
+ #
72
+ # Packaging tasks
73
+ #
74
+ #############################################################################
75
+
76
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
77
+ task :release => :build do
78
+ unless `git branch` =~ /^\* master$/
79
+ puts "You must be on the master branch to release!"
80
+ exit!
81
+ end
82
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
83
+ sh "git tag v#{version}"
84
+ sh "git push origin master"
85
+ sh "git push origin v#{version}"
86
+ sh "gem push pkg/#{name}-#{version}.gem"
87
+ end
88
+
89
+ desc "Build #{gem_file} into the pkg directory"
90
+ task :build => :gemspec do
91
+ sh "mkdir -p pkg"
92
+ sh "gem build #{gemspec_file}"
93
+ sh "mv #{gem_file} pkg"
94
+ end
95
+
96
+ desc "Generate #{gemspec_file}"
97
+ task :gemspec => :validate do
98
+ # read spec file and split out manifest section
99
+ spec = File.read(gemspec_file)
100
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
101
+
102
+ # replace name version and date
103
+ replace_header(head, :name)
104
+ replace_header(head, :version)
105
+ replace_header(head, :date)
106
+ #comment this out if your rubyforge_project has a different name
107
+ replace_header(head, :rubyforge_project)
108
+
109
+ # determine file list from git ls-files
110
+ files = `git ls-files`.
111
+ split("\n").
112
+ sort.
113
+ reject { |file| file =~ /^\./ }.
114
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
115
+ map { |file| " #{file}" }.
116
+ join("\n")
117
+
118
+ # piece file back together and write
119
+ manifest = " s.files = %w[\n#{files}\n ]\n"
120
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
121
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
122
+ puts "Updated #{gemspec_file}"
123
+ end
124
+
125
+ desc "Validate #{gemspec_file}"
126
+ task :validate do
127
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
128
+ unless libfiles.empty?
129
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
130
+ exit!
131
+ end
132
+ unless Dir['VERSION*'].empty?
133
+ puts "A `VERSION` file at root level violates Gem best practices."
134
+ exit!
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'rubygems'
6
+ require 'mathemagical'
7
+ require 'mathemagical/string'
8
+
9
+ puts STDIN.read.to_mathml
@@ -0,0 +1,24 @@
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
+ require "htmlentities"
8
+
9
+ module Mathemagical
10
+ VERSION = '0.0.1' unless defined?(:VERSION)
11
+
12
+ class Error < StandardError; end
13
+
14
+ def self.encode(s)
15
+ @entities ||= HTMLEntities.new
16
+
17
+ # TODO: HTMLEntities Y U DOUBLE ENCODE??
18
+ @entities.encode(s).gsub(/&amp;([#a-zA-Z0-9]{2,24});/, '&\1;')
19
+ end
20
+ end
21
+
22
+ require "mathemagical/element"
23
+ require "mathemagical/symbol/entity_reference"
24
+ require "mathemagical/latex"
@@ -0,0 +1,304 @@
1
+ module Mathemagical
2
+ class Element
3
+ attr_reader :display_style, :attributes, :children
4
+ attr_accessor :name
5
+
6
+ def initialize(name, options = {})
7
+ @name = name
8
+ @attributes = options
9
+ @children = []
10
+ end
11
+
12
+ def as_display_style
13
+ @display_style = true
14
+ self
15
+ end
16
+
17
+ def []=(key, value)
18
+ @attributes[key.to_sym] = value
19
+ end
20
+
21
+ def [](key)
22
+ @attributes[key.to_sym]
23
+ end
24
+
25
+ def <<(*obj)
26
+ @children += obj.flatten.map {|o| o.is_a?(String) ? Mathemagical.encode(o) : o }
27
+
28
+ self
29
+ end
30
+
31
+ def to_s
32
+ children.empty? ? self_closing_xml : xml
33
+ end
34
+
35
+ def self_closing_xml
36
+ "<#{@name}#{build_attributes_string} />"
37
+ end
38
+
39
+ def xml
40
+ "<#{@name}#{build_attributes_string}>
41
+ #{child_ml}
42
+ </#{@name}>".gsub(/[\n\t]/, '')
43
+ end
44
+
45
+ def child_ml
46
+ @children.map(&:to_s).join("\n")
47
+ end
48
+
49
+ def build_attributes_string
50
+ return if @attributes.empty?
51
+
52
+ " " + @attributes.map do |key, value|
53
+ "#{key}='#{value}'"
54
+ end.join(" ")
55
+ end
56
+
57
+ def pop
58
+ @children.pop
59
+ end
60
+ end
61
+
62
+ module Variant
63
+ NORMAL = "normal"
64
+ BOLD = "bold"
65
+ BOLD_ITALIC = "bold-italic"
66
+ def variant=(v)
67
+ self["mathvariant"] = v
68
+ end
69
+ end
70
+
71
+ module Align
72
+ CENTER = "center"
73
+ LEFT = "left"
74
+ RIGHT = "right"
75
+ end
76
+
77
+ module Line
78
+ SOLID = "solid"
79
+ NONE = "none"
80
+ end
81
+
82
+ class Math < Element
83
+ def initialize(display_style)
84
+ super("math", "xmlns"=>"http://www.w3.org/1998/Math/MathML")
85
+ self[:display] = display_style ? "block" : "inline"
86
+ end
87
+ end
88
+
89
+ class Row < Element
90
+ def initialize
91
+ super("mrow")
92
+ end
93
+ end
94
+
95
+ class Break < Element
96
+ def initialize
97
+ super("br", :xmlns => 'http://www.w3.org/1999/xhtml')
98
+ end
99
+ end
100
+
101
+ class None < Element
102
+ def initialize
103
+ super("none")
104
+ end
105
+ end
106
+
107
+ class Space < Element
108
+ def initialize(width)
109
+ super("mspace", "width"=>width)
110
+ end
111
+ end
112
+
113
+ class Fenced < Element
114
+ attr_reader :open, :close
115
+
116
+ def initialize
117
+ super("mfenced")
118
+ end
119
+
120
+ def open=(o)
121
+ o = "" if o.to_s=="." || !o
122
+ o = "{" if o.to_s=="\\{"
123
+ self[:open] = Mathemagical.encode(o)
124
+ end
125
+
126
+ def close=(c)
127
+ c = "" if c.to_s=="." || !c
128
+ c = "}" if c.to_s=="\\}"
129
+ self[:close] = Mathemagical.encode(c)
130
+ end
131
+ end
132
+
133
+ class Frac < Element
134
+ def initialize(numerator, denominator)
135
+ super("mfrac")
136
+ self << numerator
137
+ self << denominator
138
+ end
139
+ end
140
+
141
+ class SubSup < Element
142
+ attr_reader :sub, :sup, :body
143
+
144
+ def initialize(display_style, body)
145
+ super("mrow")
146
+ as_display_style if display_style
147
+ @body = body
148
+ end
149
+
150
+ def update_name
151
+ if @sub || @sup
152
+ name = "m"
153
+ name << (@sub ? (@display_style ? "under" : "sub") : "")
154
+ name << (@sup ? (@display_style ? "over" : "sup") : "")
155
+ else
156
+ name = "mrow"
157
+ end
158
+ self.name = name
159
+ end
160
+ private :update_name
161
+
162
+ def update_contents
163
+ children.clear
164
+ children << @body
165
+ children << @sub if @sub
166
+ children << @sup if @sup
167
+ end
168
+ private :update_contents
169
+
170
+ def update
171
+ update_name
172
+ update_contents
173
+ end
174
+ private :update
175
+
176
+ def sub=(sub)
177
+ @sub = sub
178
+ update
179
+ end
180
+
181
+ def sup=(sup)
182
+ @sup = sup
183
+ update
184
+ end
185
+ end
186
+
187
+ class Over < Element
188
+ def initialize(base, over)
189
+ super("mover")
190
+ self << base << over
191
+ end
192
+ end
193
+
194
+ class Under < Element
195
+ def initialize(base, under)
196
+ super("munder")
197
+ self << base << under
198
+ end
199
+ end
200
+
201
+ class Number < Element
202
+ def initialize
203
+ super("mn")
204
+ end
205
+
206
+ def <<(o)
207
+ @children << o
208
+ self
209
+ end
210
+ end
211
+
212
+ class Identifier < Element
213
+ def initialize
214
+ super("mi")
215
+ end
216
+
217
+ def <<(o)
218
+ @children << Mathemagical.encode(o)
219
+ self
220
+ end
221
+ end
222
+
223
+ class Operator < Element
224
+ def initialize
225
+ super("mo")
226
+ end
227
+
228
+ def <<(o)
229
+ @children << Mathemagical.encode(o)
230
+ self
231
+ end
232
+ end
233
+
234
+ class Text < Element
235
+ def initialize
236
+ super("mtext")
237
+ end
238
+
239
+ def <<(o)
240
+ @children << Mathemagical.encode(o)
241
+ self
242
+ end
243
+ end
244
+
245
+ class Sqrt < Element
246
+ def initialize
247
+ super("msqrt")
248
+ end
249
+ end
250
+
251
+ class Root < Element
252
+ def initialize(index, base)
253
+ super("mroot")
254
+ self << base
255
+ self << index
256
+ end
257
+ end
258
+
259
+ class Table < Element
260
+ def initialize
261
+ super("mtable")
262
+ end
263
+
264
+ def set_align_attribute(name, a, default)
265
+ if a.is_a?(Array) && a.size>0
266
+ value = ""
267
+ a.each do |i|
268
+ value << " "+i
269
+ end
270
+ if value =~ /^( #{default})*$/
271
+ @attributes.delete(name)
272
+ else
273
+ @attributes[name] = value.strip
274
+ end
275
+ else
276
+ @attributes.delete(name)
277
+ end
278
+ end
279
+
280
+ def aligns=(a)
281
+ set_align_attribute("columnalign", a, Align::CENTER)
282
+ end
283
+
284
+ def vlines=(a)
285
+ set_align_attribute("columnlines", a, Line::NONE)
286
+ end
287
+
288
+ def hlines=(a)
289
+ set_align_attribute("rowlines", a, Line::NONE)
290
+ end
291
+ end
292
+
293
+ class Tr < Element
294
+ def initialize
295
+ super("mtr")
296
+ end
297
+ end
298
+
299
+ class Td < Element
300
+ def initialize
301
+ super("mtd")
302
+ end
303
+ end
304
+ end