From: Robin Stocker Date: 2006-09-26T05:49:48+09:00 Subject: Re: [QUIZ] Code to S-Exp (#95) Hi all, Here's my solution which uses Ruby only and modifies core classes and restores them at the end of the function. I wouldn't trust it ;). Maybe this would be a task for Why's Sandbox library? Create a sandbox, modify the core classes there and evaluate the blocks there. It's just an idea, I don't know if it's possible. Robin Stocker class SxpGenerator def method_missing(meth, *args) [meth, *args] end BINARY_METHODS = [:+, :-, :*, :/, :%, :**, :^, :<, :>, :<=, :>=, :==] def self.overwrite_methods(mod) BINARY_METHODS.each do |method| mod.module_eval do if method_defined? method alias_method "__orig_#{method}__", method end define_method method do |arg| [method, self, arg] end end end end def self.restore_methods(mod) BINARY_METHODS.each do |method| mod.module_eval do orig_method = "__orig_#{method}__" if method_defined? orig_method alias_method method, orig_method remove_method orig_method else remove_method method end end end end end def sxp(&block) klasses = [Fixnum, Bignum, Symbol, Array, Float, String] klasses.each do |klass| SxpGenerator.overwrite_methods(klass) end begin result = SxpGenerator.new.instance_eval &block rescue Exception result = nil end klasses.each do |klass| SxpGenerator.restore_methods(klass) end result end require 'test/unit' class TestSxp < Test::Unit::TestCase def test_function assert_equal [:max, [:count, :name]], sxp { max(count(:name)) } end def test_number assert_equal 8, sxp { 8 } assert_equal [:+, 3, 4], sxp { 3 + 4 } assert_equal [:+, 3, :symbol], sxp { 3 + :symbol } assert_equal [:/, 7, :field], sxp { 7 / :field } end def test_symbol assert_equal [:>, :field, 5], sxp { :field > 5 } assert_equal [:==, :field1, :field2], sxp { :field1 == :field2 } end def test_mixed assert_equal [:count, [:+, 3, 7]], sxp { count(3+7) } assert_equal [:+, 3, [:count, :field]], sxp { 3 + count(:field) } end def test_environment assert_equal [:-, 10, [:count, [:*, :field, 4]]], sxp { 10 - count(:field * 4) } assert_raise(TypeError) { 7 / :field } assert_raise(NoMethodError) { 7 + count(:field) } assert_equal 11, 5 + 6 assert_raise(NoMethodError) { :field > 5 } end end