Fun with XEXPR

Just sharing some fun code. I think I cranked this out in 30 minutes.
Ruby is so cool.
It’s not a full specification of the XEXPR language
http://www.w3.org/TR/xexpr/, but at this point that’s just a trivial
amount of additional work.

require ‘rexml/document’
include REXML

class Element
def self.handle_expression( expr_name, &eval_code )
(@@expression_code ||= {})[ expr_name ] = eval_code
end

def run_expression
unless proc = @@expression_code[ self.name ]
raise “I don’t know how to handle ‘#{self.name}’ expressions yet”
end
proc.call( self )
end

def run_children
last_value = nil
self.elements.each{ |c|
last_value = c.run_expression
}
last_value
end
end

Element.handle_expression( ‘expr’ ){ |me|
me.run_children
}

Element.handle_expression( ‘set’ ){ |me|
name = me.attributes[ ‘name’ ]
val = me.attributes[ ‘value’ ] || me.run_children
(@@global_expression_variables ||= {})[ name ] = val
}

Element.handle_expression( ‘get’ ){ |me|
name = me.attributes[ ‘name’ ] || me.run_children
(@@global_expression_variables ||= {})[ name ]
}

Element.handle_expression( ‘print’ ){ |me|
puts name = me.attributes[ ‘string’ ] || me.run_children
name
}

Element.handle_expression( ‘if’ ){ |me|
if me.elements[ 1 ].run_expression
me.elements[ 2 ].run_expression
else
me.elements[ 3 ] && me.elements[ 3 ].run_expression
end
}

Element.handle_expression( ‘false’ ){ false }

Element.handle_expression( ‘add’ ){ |me|
case me.elements[ 1 ].run_expression
when String
me.elements.to_a.map{ |el| el.run_expression }.join
else
me.elements.to_a.inject(0){ |sum,el| sum + el.run_expression }
end
}

Element.handle_expression( ‘string’ ){ |me|
me.text.to_s
}

d = REXML::Document.new( <<ENDXML )





BAD NEWS!

Hello

location





ENDXML

d.root.run_expression
#=> Hello World