=begin
=module NumRu::Misc::EMath

To be included instead of the Math predefined module (or NMath in NArray).
Unlike Math and NMath, EMath handles unknown classes by calling its
native instance method (assuming the same name).

Therefore, if included, its function (module method) is used as:

   cos( obj )

and so on. If obj is not of a supported class, EMath calls, obj.cos in
this case.  (If cos is not a method of obj, then an exception is
raised.)  Supported classes are Numeric (by Math) and NArray (by
NMath).  EMath stands for "good Math" (for obvious reason for a
Japanese).

Note: as for atan2(a,b), a.atan2(b) will be called if a or b
is not supported. This is the case for all functions that take
two or more arguments.

=end

require "narray"

module NumRu
  module Misc
    module EMath

      E = Math::E
      PI = Math::PI

      funcs = ["acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", 
               "cos", "cosh", "erf", "erfc", "exp", "frexp", "hypot", 
               "ldexp", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"]
               # FUNCS: from ruby 1.8.0, ( Math.methods - Object.methods ).sort

      module_function
      funcs.each{|func|
	eval <<-EOS,nil,__FILE__,__LINE__+1
	def #{func}(*arg)
          case arg[0]
          when Numeric
	    Math.#{func}(*arg)
	  when NArray
	    NMath.#{func}(*arg)
	  else
	    obj = arg.shift
	    begin
	      obj.#{func}(*arg)
	    rescue NameError
	      raise TypeError,"cannot handle \#{obj.class}: \#{obj.inspect}"
	    end
	  end
	end
	EOS
      }
    end
  end
end

if __FILE__ == $0
  include NumRu::Misc::EMath
  p cos( PI )
  p cos( Complex(0, 1) )
  p cos( NArray[0,PI/3,PI/2] )
  begin
    p cos( "ggg" )
  rescue
    print "* error as expected >>: ",$!,"\n"
  end
  require 'narray_miss'
  nam = NArrayMiss.to_nam( NArray[0,PI/3,PI/2] )
  p cos(nam)
end
