lib/asciimath/mathml.rb in asciimath-1.0.9 vs lib/asciimath/mathml.rb in asciimath-2.0.0
- old
+ new
@@ -1,142 +1,244 @@
+require_relative 'markup'
+require_relative 'symbol_table'
+
module AsciiMath
- class MathMLBuilder
- def initialize(prefix)
- @prefix = prefix
+ class MathMLBuilder < ::AsciiMath::MarkupBuilder
+
+ def initialize(opts = {})
+ super(opts[:symbol_table] || DEFAULT_DISPLAY_SYMBOL_TABLE)
+ @prefix = opts[:prefix] || ''
@mathml = ''
+ if opts[:msword]
+ @row_mode = :force
+ @fence_mode = :fenced
+ else
+ @row_mode = :avoid
+ @fence_mode = :row
+ end
end
def to_s
@mathml
end
def append_expression(expression, attrs = {})
math('', attrs) do
- append(expression, :single_child => true)
+ append(expression, :row => :omit)
end
end
private
- def append(expression, opts = {})
- case expression
- when Array
- if expression.length <= 1 || opts[:single_child]
- expression.each { |e| append(e) }
- else
- mrow do
- expression.each { |e| append(e) }
- end
- end
- when Hash
- case expression[:type]
- when :operator
- mo(expression[:c])
- when :identifier
- mi(expression[:c])
- when :number
- mn(expression[:c])
- when :text
- mtext(expression[:c])
- when :paren
- if !opts[:strip_paren]
- fenced(expression[:lparen], expression[:rparen]) do
- append(expression[:e])
+ def append_row(expressions)
+ mrow do
+ expressions.each { |e| append(e) }
+ end
+ end
+
+ def append_operator(operator)
+ mo(operator)
+ end
+
+ def append_identifier(identifier)
+ mi(identifier)
+ end
+
+ def append_text(text)
+ mtext(text)
+ end
+
+ def append_number(number)
+ mn(number)
+ end
+
+ def append_sqrt(expression)
+ tag("m#{"sqrt"}") do
+ append(expression, :row => @row_mode)
+ end
+ end
+
+ def append_cancel(expression)
+ tag("menclose", :notation => "updiagonalstrike") do
+ append(expression, :row => :omit)
+ end
+ end
+
+ def append_root(base, index)
+ tag("m#{"root"}") do
+ append(base, :row => @row_mode)
+ append(index, :row => @row_mode)
+ end
+ end
+
+ def append_fraction(numerator, denominator)
+ tag("m#{"frac"}") do
+ append(numerator, :row => @row_mode)
+ append(denominator, :row => @row_mode)
+ end
+ end
+
+
+ def append_font(style, e)
+ tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
+ append(e)
+ end
+ end
+
+ def append_color(color, e)
+ tag("mstyle", :mathcolor => color) do
+ append(e)
+ end
+ end
+
+ def append_matrix(lparen, rows, rparen)
+ fenced(lparen, rparen) do
+ mtable do
+ rows.each do |row|
+ mtr do
+ row.each do |col|
+ mtd do
+ append(col)
end
- else
- append(expression[:e])
end
- when :font
- style = expression[:operator]
- tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
- append(expression[:s], :single_child => true, :strip_paren => true)
- end
- when :unary
- operator = expression[:operator]
- tag("m#{operator}") do
- append(expression[:s], :single_child => true, :strip_paren => true)
- end
- when :binary
- operator = expression[:operator]
- tag("m#{operator}") do
- append(expression[:s1], :strip_paren => (operator != :sub && operator != :sup))
- append(expression[:s2], :strip_paren => true)
- end
- when :ternary
- operator = expression[:operator]
- tag("m#{operator}") do
- append(expression[:s1])
- append(expression[:s2], :strip_paren => true)
- append(expression[:s3], :strip_paren => true)
- end
- when :matrix
- fenced(expression[:lparen], expression[:rparen]) do
- mtable do
- expression[:rows].each do |row|
- mtr do
- row.each do |col|
- mtd do
- append(col)
- end
- end
- end
- end
- end
- end
+ end
end
+ end
end
end
+ def append_operator_unary(operator, expression)
+ mrow do
+ mo(operator)
+ append(expression, :row => @row_mode)
+ end
+ end
+
+ def append_identifier_unary(identifier, expression)
+ mrow do
+ mi(identifier)
+ append(expression, :row => @row_mode)
+ end
+ end
+
+ def append_paren(lparen, e, rparen, opts = {})
+ fenced(lparen, rparen) do
+ append(e, :row => @row_mode)
+ end
+ end
+
+ def append_subsup(base, sub, sup)
+ if sub && sup
+ msubsup do
+ append(base, :row => @row_mode)
+ append(sub, :row => @row_mode)
+ append(sup, :row => @row_mode)
+ end
+ elsif sub
+ msub do
+ append(base, :row => @row_mode)
+ append(sub, :row => @row_mode)
+ end
+ elsif sup
+ msup do
+ append(base, :row => @row_mode)
+ append(sup, :row => @row_mode)
+ end
+ else
+ append(base)
+ end
+ end
+
+ def append_underover(base, sub, sup)
+ if sub && sup
+ munderover do
+ append(base, :row => @row_mode)
+ append(sub, :row => @row_mode)
+ append(sup, :row => @row_mode)
+ end
+ elsif sub
+ munder do
+ append(base, :row => @row_mode)
+ append(sub, :row => @row_mode)
+ end
+ elsif sup
+ mover do
+ append(base, :row => @row_mode)
+ append(sup, :row => @row_mode)
+ end
+ else
+ append(base)
+ end
+ end
+
def method_missing(meth, *args, &block)
tag(meth, *args, &block)
end
- def fenced(lparen, rparen, &block)
+ def fenced(lparen, rparen)
if lparen || rparen
- mfenced(:open => lparen || '', :close => rparen || '') do
- yield self
+ if @fence_mode == :fenced
+ mfenced(:open => lparen || '', :close => rparen || '') do
+ yield self
+ end
+ else
+ mrow do
+ mo(lparen) if lparen
+ yield self
+ mo(rparen) if rparen
+ end
end
else
yield self
end
end
def tag(tag, *args)
attrs = args.last.is_a?(Hash) ? args.pop : {}
- text = args.last.is_a?(String) ? args.pop : ''
+ text = args.last.is_a?(String) || args.last.is_a?(Symbol) ? args.pop.to_s : ''
@mathml << '<' << @prefix << tag.to_s
attrs.each_pair do |key, value|
- @mathml << ' ' << key.to_s << '="' << value.to_s << '"'
+ @mathml << ' ' << key.to_s << '="'
+ append_escaped(value.to_s)
+ @mathml << '"'
end
if block_given? || text
@mathml << '>'
- text.each_codepoint do |cp|
- if cp == 38
- @mathml << "&"
- elsif cp == 60
- @mathml << "<"
- elsif cp == 62
- @mathml << ">"
- elsif cp > 127
- @mathml << "&#x#{cp.to_s(16).upcase};"
- else
- @mathml << cp
- end
- end
+ append_escaped(text)
yield self if block_given?
@mathml << '</' << @prefix << tag.to_s << '>'
else
@mathml << '/>'
end
end
+
+ def append_escaped(text)
+ text.each_codepoint do |cp|
+ if cp == 38
+ @mathml << "&"
+ elsif cp == 60
+ @mathml << "<"
+ elsif cp == 62
+ @mathml << ">"
+ elsif cp > 127
+ @mathml << "&#x#{cp.to_s(16).upcase};"
+ else
+ @mathml << cp
+ end
+ end
+ end
end
class Expression
def to_mathml(prefix = "", attrs = {})
- MathMLBuilder.new(prefix).append_expression(@parsed_expression, attrs).to_s
+ if prefix.is_a? Hash
+ attrs = prefix
+ prefix = ""
+ end
+ MathMLBuilder.new(:prefix => prefix).append_expression(ast, attrs).to_s
end
end
-end
\ No newline at end of file
+end