On Sep 22, 2006, at 5:13 PM, Ruby Quiz wrote:

> If your code evaluates (rather than parsing) purely numerical  
> expressions that don't contain functions or field names  
> (represented by Symbols here), then this is satisfactory behavior  
> since it shouldn't matter whether Ruby evaluates them or the SQL  
> database evaluates them. This means, for example, that sxp{3+5} can  
> give you 8 as an s-expression

I wanted to see how far I could get if I let Ruby do the math.   
Answer:  Not too far.  Without hacking Ruby core methods I could only  
get these quiz tests to pass:

#!/usr/bin/env ruby -w

require "test/unit"

require "sxp"

class TestSXP < Test::Unit::TestCase
   def test_quiz_examples
     assert_equal([:max, [:count, :name]], sxp { max(count(:name)) })
     assert_equal([:count, 10], sxp { count(3 + 7) })
     assert_equal(8, sxp { 8 })
   end

   def test_normal_ruby_operations
     assert_raise(TypeError) { 7 / :field }
     assert_raise(NoMethodError) { 7 + count(:field) }
     assert_equal(11, 5 + 6)
     assert_raise(NoMethodError) { :field > 5 }
   end
end

Here's the solution used to get that far:

#!/usr/bin/env ruby -w

class SXP
   instance_methods.each do |meth|
     undef_method(meth) unless meth =~ /\A__/ or meth == "instance_eval"
   end

   def initialize(&block)
     @code = block
   end

   def method_missing(meth, *args, &block)
     if args.any? { |e| e.is_a? Array }
       [meth, args.inject(Array.new) { |arr, a| arr.push(*a) }]
     else
       [meth, *args]
     end
   end

   def result
     instance_eval(&@code)
   end
end

def sxp(&block)
   SXP.new(&block).result
end

James Edward Gray II