[ruby-oci8-commit] [363] trunk/ruby-oci8: * ext/oci8/ocinumber.c: Add a global function OraNumber(obj) as a

nobody at rubyforge.org nobody at rubyforge.org
Tue Oct 6 09:46:41 EDT 2009


Revision: 363
Author:   kubo
Date:     2009-10-06 09:46:41 -0400 (Tue, 06 Oct 2009)

Log Message:
-----------
* ext/oci8/ocinumber.c: Add a global function OraNumber(obj) as a
    shortcut of OraNumber.new(obj) as Rational and BigDecimal do.
    Changes the return type of the four rules of arithmetic;
    addition, subtraction, multiplication and division. It was
    OraNumber, but now it depends on the operand.
* lib/oci8/bindtype.rb: Add OCI8::BindType::BigDecimal and
    OCI8::BindType::Rational. Change the default data type for
    number column which fit neither Integer nor Float from
    OraNumber to BigDecimal.
* lib/oci8/oci8.rb: Fix for OCI8::BindType::Mapping to accept
    a class name instead of the class object to support
    OCI8::BindType::BigDecimal and OCI8::BindType::Rational without
    requiring 'bigdecimal' and 'rational'.
* spec/oranumber_spec.rb: Add a spec file for OraNumber arithmetic.
* test/test_oci8.rb: Add tests for OCI8::BindType::BigDecimal and
    OCI8::BindType::Rational.

Modified Paths:
--------------
    trunk/ruby-oci8/ChangeLog
    trunk/ruby-oci8/ext/oci8/ocinumber.c
    trunk/ruby-oci8/lib/oci8/bindtype.rb
    trunk/ruby-oci8/lib/oci8/oci8.rb
    trunk/ruby-oci8/test/test_oci8.rb

Added Paths:
-----------
    trunk/ruby-oci8/spec/oranumber_spec.rb

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2009-10-04 14:04:01 UTC (rev 362)
+++ trunk/ruby-oci8/ChangeLog	2009-10-06 13:46:41 UTC (rev 363)
@@ -1,3 +1,21 @@
+2009-10-06  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/ocinumber.c: Add a global function OraNumber(obj) as a
+	    shortcut of OraNumber.new(obj) as Rational and BigDecimal do.
+	    Changes the return type of the four rules of arithmetic;
+	    addition, subtraction, multiplication and division. It was
+	    OraNumber, but now it depends on the operand.
+	* lib/oci8/bindtype.rb: Add OCI8::BindType::BigDecimal and
+	    OCI8::BindType::Rational. Change the default data type for
+	    number column which fit neither Integer nor Float from
+	    OraNumber to BigDecimal.
+	* lib/oci8/oci8.rb: Fix for OCI8::BindType::Mapping to accept
+	    a class name instead of the class object to support
+	    OCI8::BindType::BigDecimal and OCI8::BindType::Rational without
+	    requiring 'bigdecimal' and 'rational'.
+	* spec/oranumber_spec.rb: Add a spec file for OraNumber arithmetic.
+	* test/test_oci8.rb: Add tests for OCI8::BindType::BigDecimal and
+	    OCI8::BindType::Rational.
+
 2009-10-04  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/oci8.c: Add constants missing in Oracle client prior to 10g.
 	* ext/oci8/oraconf.rb:

Modified: trunk/ruby-oci8/ext/oci8/ocinumber.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/ocinumber.c	2009-10-04 14:04:01 UTC (rev 362)
+++ trunk/ruby-oci8/ext/oci8/ocinumber.c	2009-10-06 13:46:41 UTC (rev 363)
@@ -21,7 +21,14 @@
 static ID id_split;
 static ID id_numerator;
 static ID id_denominator;
+static ID id_Rational;
+static ID id_BigDecimal;
 
+#ifndef T_RATIONAL
+static VALUE cRational;
+#endif
+static VALUE cBigDecimal;
+
 static VALUE cOCINumber;
 static OCINumber const_p1;   /*  +1 */
 static OCINumber const_p10;  /* +10 */
@@ -51,6 +58,58 @@
 
 #define _NUMBER(val) ((OCINumber *)DATA_PTR(val)) /* dangerous macro */
 
+#define RBOCI8_T_ORANUMBER (T_MASK + 1)
+#define RBOCI8_T_BIGDECIMAL (T_MASK + 2)
+#ifdef T_RATIONAL
+#define RBOCI8_T_RATIONAL T_RATIONAL
+#else
+#define RBOCI8_T_RATIONAL (T_MASK + 3)
+#endif
+
+static int rboci8_type(VALUE obj)
+{
+    int type = TYPE(obj);
+    VALUE klass;
+
+    switch (type) {
+#ifndef T_RATIONAL
+    case T_OBJECT:
+        klass = CLASS_OF(obj);
+        if (cRational != 0) {
+            if (klass == cRational) {
+                return RBOCI8_T_RATIONAL;
+            }
+        } else {
+            if (strcmp(rb_class2name(klass), "Rational") == 0) {
+                cRational = rb_const_get(rb_cObject, id_Rational);
+                return RBOCI8_T_RATIONAL;
+            }
+        }
+        break;
+#endif
+    case T_DATA:
+        klass = CLASS_OF(obj);
+        if (klass == cOCINumber) {
+            return RBOCI8_T_ORANUMBER;
+        }
+        if (cBigDecimal != 0) {
+            if (klass == cBigDecimal) {
+                return RBOCI8_T_BIGDECIMAL;
+            }
+        } else {
+            if (strcmp(rb_class2name(klass), "BigDecimal") == 0) {
+                cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
+                return RBOCI8_T_BIGDECIMAL;
+            }
+        }
+    }
+    return type;
+}
+
+static VALUE onum_to_f(VALUE self);
+static VALUE onum_to_r(VALUE self);
+static VALUE onum_to_d(VALUE self);
+
 static VALUE onum_s_alloc(VALUE klass)
 {
     VALUE obj;
@@ -573,6 +632,20 @@
     return oci8_make_ocinumber(&r, errhp);
 }
 
+
+/*
+ *  call-seq:
+ *     OraNumber(obj)   -> oranumber
+ *
+ *  Returns a new <code>OraNumber</code>.
+ */
+static VALUE onum_f_new(int argc, VALUE *argv, VALUE self)
+{
+    VALUE obj = rb_obj_alloc(cOCINumber);
+    rb_obj_call_init(obj, argc, argv);
+    return obj;
+}
+
 static VALUE onum_initialize(int argc, VALUE *argv, VALUE self)
 {
     OCIError *errhp = oci8_errhp;
@@ -602,12 +675,26 @@
 
 static VALUE onum_coerce(VALUE self, VALUE other)
 {
-    OCIError *errhp = oci8_errhp;
+    signed long sl;
     OCINumber n;
 
-    if (RTEST(rb_obj_is_kind_of(other, rb_cNumeric)))
-        if (set_oci_number_from_num(&n, other, 0, errhp))
-            return rb_assoc_new(oci8_make_ocinumber(&n, errhp), self);
+    switch(rboci8_type(other)) {
+    case T_FIXNUM:
+        sl = NUM2LONG(other);
+        oci_lc(OCINumberFromInt(oci8_errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &n));
+        return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self);
+    case T_BIGNUM:
+        /* change via string. */
+        other = rb_big2str(other, 10);
+        set_oci_number_from_str(&n, other, Qnil, Qnil, oci8_errhp);
+        return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self);
+    case T_FLOAT:
+        return rb_assoc_new(other, onum_to_f(self));
+    case RBOCI8_T_RATIONAL:
+        return rb_assoc_new(other, onum_to_r(self));
+    case RBOCI8_T_BIGDECIMAL:
+        return rb_assoc_new(other, onum_to_d(self));
+    }
     rb_raise(rb_eTypeError, "Can't coerce %s to %s",
              rb_class2name(CLASS_OF(other)), rb_class2name(cOCINumber));
 }
@@ -616,7 +703,7 @@
  *  call-seq:
  *     -onum   -> oranumber
  *
- *  Returns an <code>OraNumber</code>, negated.
+ *  Returns a negated <code>OraNumber</code>.
  */
 static VALUE onum_neg(VALUE self)
 {
@@ -627,12 +714,12 @@
     return oci8_make_ocinumber(&r, errhp);
 }
 
+
 /*
  *  call-seq:
- *    onum + other   -> oranumber
+ *    onum + other    -> number
  *
- *  Returns a new <code>OraNumber</code> which is the sum of <i>onum</i>
- *  and <i>other</i>.
+ *  Returns the sum of <i>onum</i> and <i>other</i>.
  */
 static VALUE onum_add(VALUE lhs, VALUE rhs)
 {
@@ -640,20 +727,33 @@
     OCINumber n;
     OCINumber r;
 
-    /* change to OCINumber */
-    if (!set_oci_number_from_num(&n, rhs, 0, errhp))
-        return rb_num_coerce_bin(lhs, rhs, '+');
-    /* add */
-    oci_lc(OCINumberAdd(errhp, _NUMBER(lhs), &n, &r));
-    return oci8_make_ocinumber(&r, errhp);
+    switch (rboci8_type(rhs)) {
+    case T_FIXNUM:
+    case T_BIGNUM:
+        if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
+            oci_lc(OCINumberAdd(errhp, _NUMBER(lhs), &n, &r));
+            return oci8_make_ocinumber(&r, errhp);
+        }
+        break;
+    case RBOCI8_T_ORANUMBER:
+        oci_lc(OCINumberAdd(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
+        return oci8_make_ocinumber(&r, errhp);
+    case T_FLOAT:
+        return rb_funcall(onum_to_f(lhs), '+', 1, rhs);
+    case RBOCI8_T_RATIONAL:
+        return rb_funcall(onum_to_r(lhs), '+', 1, rhs);
+    case RBOCI8_T_BIGDECIMAL:
+        return rb_funcall(onum_to_d(lhs), '+', 1, rhs);
+    }
+    return rb_num_coerce_bin(lhs, rhs, '+');
 }
 
 /*
  *  call-seq:
- *    onum - other   -> oranumber
+ *    onum - integer   -> oranumber
+ *    onum - numeric   -> numeric
  *
- *  Returns a new <code>OraNumber</code> which is the difference of <i>onum</i>
- *  and <i>other</i>.
+ *  Returns the difference of <i>onum</i> and <i>other</i>.
  */
 static VALUE onum_sub(VALUE lhs, VALUE rhs)
 {
@@ -661,20 +761,32 @@
     OCINumber n;
     OCINumber r;
 
-    /* change to OCINumber */
-    if (!set_oci_number_from_num(&n, rhs, 0, errhp))
-        return rb_num_coerce_bin(lhs, rhs, '-');
-    /* subtracting */
-    oci_lc(OCINumberSub(errhp, _NUMBER(lhs), &n, &r));
-    return oci8_make_ocinumber(&r, errhp);
+    switch (rboci8_type(rhs)) {
+    case T_FIXNUM:
+    case T_BIGNUM:
+        if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
+            oci_lc(OCINumberSub(errhp, _NUMBER(lhs), &n, &r));
+            return oci8_make_ocinumber(&r, errhp);
+        }
+        break;
+    case RBOCI8_T_ORANUMBER:
+        oci_lc(OCINumberSub(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
+        return oci8_make_ocinumber(&r, errhp);
+    case T_FLOAT:
+        return rb_funcall(onum_to_f(lhs), '-', 1, rhs);
+    case RBOCI8_T_RATIONAL:
+        return rb_funcall(onum_to_r(lhs), '-', 1, rhs);
+    case RBOCI8_T_BIGDECIMAL:
+        return rb_funcall(onum_to_d(lhs), '-', 1, rhs);
+    }
+    return rb_num_coerce_bin(lhs, rhs, '-');
 }
 
 /*
  *  call-seq:
- *    onum * other   -> oranumber
+ *    onum * other   -> number
  *
- *  Returns a new <code>OraNumber</code> which is the product of <i>onum</i>
- *  and <i>other</i>.
+ *  Returns the product of <i>onum</i> and <i>other</i>.
  */
 static VALUE onum_mul(VALUE lhs, VALUE rhs)
 {
@@ -682,20 +794,33 @@
     OCINumber n;
     OCINumber r;
 
-    /* change to OCINumber */
-    if (!set_oci_number_from_num(&n, rhs, 0, errhp))
-        return rb_num_coerce_bin(lhs, rhs, '*');
-    /* multiply */
-    oci_lc(OCINumberMul(errhp, _NUMBER(lhs), &n, &r));
-    return oci8_make_ocinumber(&r, errhp);
+    switch (rboci8_type(rhs)) {
+    case T_FIXNUM:
+    case T_BIGNUM:
+        if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
+            oci_lc(OCINumberMul(errhp, _NUMBER(lhs), &n, &r));
+            return oci8_make_ocinumber(&r, errhp);
+        }
+        break;
+    case RBOCI8_T_ORANUMBER:
+        oci_lc(OCINumberMul(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
+        return oci8_make_ocinumber(&r, errhp);
+    case T_FLOAT:
+        return rb_funcall(onum_to_f(lhs), '*', 1, rhs);
+    case RBOCI8_T_RATIONAL:
+        return rb_funcall(onum_to_r(lhs), '*', 1, rhs);
+    case RBOCI8_T_BIGDECIMAL:
+        return rb_funcall(onum_to_d(lhs), '*', 1, rhs);
+    }
+    return rb_num_coerce_bin(lhs, rhs, '*');
 }
 
 /*
  *  call-seq:
- *    onum / other   -> oranumber
+ *    onum / integer   -> oranumber
+ *    onum / numeric   -> numeric
  *
- *  Returns a new <code>OraNumber</code> which is the result of dividing
- *  <i>onum</i> by <i>other</i>.
+ *  Returns the result of dividing <i>onum</i> by <i>other</i>.
  */
 static VALUE onum_div(VALUE lhs, VALUE rhs)
 {
@@ -704,16 +829,32 @@
     OCINumber r;
     boolean is_zero;
 
-    /* change to OCINumber */
-    if (!set_oci_number_from_num(&n, rhs, 0, errhp))
-        return rb_num_coerce_bin(lhs, rhs, '/');
-    /* check whether argument is not zero. */
-    oci_lc(OCINumberIsZero(errhp, &n, &is_zero));
-    if (is_zero)
-        rb_num_zerodiv();
-    /* division */
-    oci_lc(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r));
-    return oci8_make_ocinumber(&r, errhp);
+    switch (rboci8_type(rhs)) {
+    case T_FIXNUM:
+        if (rhs == INT2FIX(0)) {
+            rb_num_zerodiv();
+        }
+    case T_BIGNUM:
+        if (set_oci_number_from_num(&n, rhs, 0, errhp)) {
+            oci_lc(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r));
+            return oci8_make_ocinumber(&r, errhp);
+        }
+        break;
+    case RBOCI8_T_ORANUMBER:
+        oci_lc(OCINumberIsZero(errhp, _NUMBER(rhs), &is_zero));
+        if (is_zero) {
+            rb_num_zerodiv();
+        }
+        oci_lc(OCINumberDiv(errhp, _NUMBER(lhs), _NUMBER(rhs), &r));
+        return oci8_make_ocinumber(&r, errhp);
+    case T_FLOAT:
+        return rb_funcall(onum_to_f(lhs), '/', 1, rhs);
+    case RBOCI8_T_RATIONAL:
+        return rb_funcall(onum_to_r(lhs), '/', 1, rhs);
+    case RBOCI8_T_BIGDECIMAL:
+        return rb_funcall(onum_to_d(lhs), '/', 1, rhs);
+    }
+    return rb_num_coerce_bin(lhs, rhs, '/');
 }
 
 /*
@@ -975,7 +1116,7 @@
  *  call-seq:
  *     onum.to_i       -> integer
  *
- *  Returns <i>onm</i> truncated to an <code>Integer</code>.
+ *  Returns <i>onum</i> truncated to an <code>Integer</code>.
  */
 static VALUE onum_to_i(VALUE self)
 {
@@ -990,7 +1131,7 @@
  *  call-seq:
  *     onum.to_f -> float
  *
- *  Converts <i>onum</i> to a <code>Float</code>.
+ *  Return the value as a <code>Float</code>.
  *
  */
 static VALUE onum_to_f(VALUE self)
@@ -1004,8 +1145,69 @@
 
 /*
  *  call-seq:
+ *     onum.to_r -> rational
+ *
+ *  Return the value as a <code>Rational</code>.
+ *
+ */
+static VALUE onum_to_r(VALUE self)
+{
+    VALUE x, y;
+    int nshift = 0;
+    OCINumber onum[2];
+    int current = 0;
+    boolean is_int;
+
+    oci_lc(OCINumberAssign(oci8_errhp, _NUMBER(self), &onum[0]));
+
+    for (;;) {
+        oci_lc(OCINumberIsInt(oci8_errhp, &onum[current], &is_int));
+        if (is_int) {
+            break;
+        }
+        nshift++;
+        oci_lc(OCINumberShift(oci8_errhp, &onum[current], 1, &onum[1 - current]));
+        current = 1 - current;
+    }
+    x = oci8_make_integer(&onum[current], oci8_errhp);
+    if (nshift == 0) {
+        y = INT2FIX(1);
+    } else {
+        y = rb_funcall(INT2FIX(10), rb_intern("**"), 1, INT2FIX(nshift));
+    }
+#ifdef T_RATIONAL
+    return rb_Rational(x, y);
+#else
+    if (!cRational) {
+        rb_require("rational");
+        cRational = rb_const_get(rb_cObject, id_Rational);
+    }
+    return rb_funcall(rb_cObject, id_Rational, 2, x, y);
+#endif
+}
+
+/*
+ *  call-seq:
+ *     onum.to_d -> bigdecimal
+ *
+ *  Return the value as a <code>BigDecimal</code>.
+ *
+ */
+static VALUE onum_to_d(VALUE self)
+{
+    if (!cBigDecimal) {
+        rb_require("bigdecimal");
+        cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
+    }
+    return rb_funcall(rb_cObject, id_BigDecimal, 1, onum_to_s(self));
+}
+
+/*
+ *  call-seq:
  *     onum.to_onum -> oranumber
  *
+ *  Returns self.
+ *
  */
 static VALUE onum_to_onum(VALUE self)
 {
@@ -1218,6 +1420,8 @@
     id_split = rb_intern("split");
     id_numerator = rb_intern("numerator");
     id_denominator = rb_intern("denominator");
+    id_Rational = rb_intern("Rational");
+    id_BigDecimal = rb_intern("BigDecimal");
 
     cOCINumber = rb_define_class("OraNumber", rb_cNumeric);
     mMath = rb_define_module_under(cOCI8, "Math");
@@ -1275,6 +1479,7 @@
     rb_define_alloc_func(cOCINumber, onum_s_alloc);
 
     /* methods of OCI::Number */
+    rb_define_method(rb_cObject, "OraNumber", onum_f_new, -1);
     rb_define_method_nodoc(cOCINumber, "initialize", onum_initialize, -1);
     rb_define_method_nodoc(cOCINumber, "initialize_copy", onum_initialize_copy, 1);
     rb_define_method_nodoc(cOCINumber, "coerce", onum_coerce, 1);
@@ -1302,6 +1507,8 @@
     rb_define_method(cOCINumber, "to_char", onum_to_char, -1);
     rb_define_method(cOCINumber, "to_i", onum_to_i, 0);
     rb_define_method(cOCINumber, "to_f", onum_to_f, 0);
+    rb_define_method(cOCINumber, "to_r", onum_to_r, 0);
+    rb_define_method(cOCINumber, "to_d", onum_to_d, 0);
     rb_define_method_nodoc(cOCINumber, "to_onum", onum_to_onum, 0);
 
     rb_define_method(cOCINumber, "zero?", onum_zero_p, 0);

Modified: trunk/ruby-oci8/lib/oci8/bindtype.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/bindtype.rb	2009-10-04 14:04:01 UTC (rev 362)
+++ trunk/ruby-oci8/lib/oci8/bindtype.rb	2009-10-06 13:46:41 UTC (rev 363)
@@ -24,6 +24,28 @@
       end
     end
 
+    class BigDecimal < OCI8::BindType::OraNumber
+      @@bigdecimal_is_required = false
+      def get()
+        unless @@bigdecimal_is_required
+          require 'bigdecimal'
+          @@bigdecimal_is_required = true
+        end
+        (val = super()) && val.to_d
+      end
+    end
+
+    class Rational < OCI8::BindType::OraNumber
+      @@rational_is_required = false
+      def get()
+        unless @@rational_is_required
+          require 'rational'
+          @@rational_is_required = true
+        end
+        (val = super()) && val.to_r
+      end
+    end
+
     # get/set Number (for OCI8::SQLT_NUM)
     class Number
       def self.create(con, val, param, max_array_size)
@@ -54,8 +76,8 @@
           if precision < 15 # the precision of double.
             klass = OCI8::BindType::Float
           else
-            # use BigDecimal instead?
-            klass = OCI8::BindType::OraNumber
+            # use BigDecimal instead
+            klass = OCI8::BindType::BigDecimal
           end
         end
         klass.new(con, val, nil, max_array_size)
@@ -156,6 +178,8 @@
 # bind or explicitly define
 OCI8::BindType::Mapping[String]       = OCI8::BindType::String
 OCI8::BindType::Mapping[OraNumber]    = OCI8::BindType::OraNumber
+OCI8::BindType::Mapping['BigDecimal'] = OCI8::BindType::BigDecimal
+OCI8::BindType::Mapping['Rational']   = OCI8::BindType::Rational
 OCI8::BindType::Mapping[Fixnum]       = OCI8::BindType::Integer
 OCI8::BindType::Mapping[Float]        = OCI8::BindType::Float
 OCI8::BindType::Mapping[Integer]      = OCI8::BindType::Integer
@@ -263,9 +287,9 @@
 # datatypes that have no explicit setting of their precision
 # and scale.
 #
-# The default mapping is Float for ruby-oci8 1.0. It is OraNumber
-# for ruby-oci8 2.0.
-OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::OraNumber
+# The default mapping is Float for ruby-oci8 1.0, OraNumber for 2.0.0 ~ 2.0.2,
+# BigDecimal for 2.0.3 ~.
+OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::BigDecimal
 
 # mapping for number without precision and scale.
 #
@@ -276,9 +300,9 @@
 # note: This is available only on Oracle 9.2.0.3 or above.
 # see:  Oracle 9.2.0.x Patch Set Notes.
 #
-# The default mapping is Float for ruby-oci8 1.0. It is OraNumber
-# for ruby-oci8 2.0.
-OCI8::BindType::Mapping[:number_no_prec_setting] = OCI8::BindType::OraNumber
+# The default mapping is Float for ruby-oci8 1.0, OraNumber for 2.0.0 ~ 2.0.2,
+# BigDecimal for 2.0.3 ~.
+OCI8::BindType::Mapping[:number_no_prec_setting] = OCI8::BindType::BigDecimal
 
 if defined? OCI8::BindType::BinaryDouble
   OCI8::BindType::Mapping[:binary_float] = OCI8::BindType::BinaryDouble

Modified: trunk/ruby-oci8/lib/oci8/oci8.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/oci8.rb	2009-10-04 14:04:01 UTC (rev 362)
+++ trunk/ruby-oci8/lib/oci8/oci8.rb	2009-10-06 13:46:41 UTC (rev 363)
@@ -343,6 +343,10 @@
       end
       
       bindclass = OCI8::BindType::Mapping[type]
+      if bindclass.nil? and type.is_a? Class
+        bindclass = OCI8::BindType::Mapping[type.to_s]
+        OCI8::BindType::Mapping[type] = bindclass if bindclass
+      end
       raise "unsupported dataType: #{type}" if bindclass.nil?
       bindobj = bindclass.create(@con, var_array, param, @max_array_size)
       __bind(key, bindobj)
@@ -452,6 +456,10 @@
       end
 
       bindclass = OCI8::BindType::Mapping[key]
+      if bindclass.nil? and key.is_a? Class
+        bindclass = OCI8::BindType::Mapping[key.to_s]
+        OCI8::BindType::Mapping[key] = bindclass if bindclass
+      end
       raise "unsupported datatype: #{key}" if bindclass.nil?
       bindclass.create(@con, val, param, max_array_size)
     end

Added: trunk/ruby-oci8/spec/oranumber_spec.rb
===================================================================
--- trunk/ruby-oci8/spec/oranumber_spec.rb	                        (rev 0)
+++ trunk/ruby-oci8/spec/oranumber_spec.rb	2009-10-06 13:46:41 UTC (rev 363)
@@ -0,0 +1,167 @@
+require 'bigdecimal'
+require 'rational'
+require File.join(File.dirname(__FILE__), 'spec_helper.rb')
+
+describe OraNumber do
+
+  it "should be converted to Flaot by to_f" do
+    OraNumber("0.25").to_f.should eql(0.25)
+  end
+
+  it "should be converted to Integer by to_i" do
+    OraNumber("7.25").to_i.should eql(7)
+    OraNumber("7.75").to_i.should eql(7)
+  end
+
+  it "should be converted to Rational by to_r" do
+    OraNumber("100000000000000.1").to_r.should eql(Rational(1000000000000001, 10))
+  end
+
+  it "should be converted to BigDecimal by to_d" do
+    OraNumber("100000000000000.1").to_d.should eql(BigDecimal("100000000000000.1"))
+  end
+
+  # OraNumber bin_op OraNumber
+  it "+ OraNumber should be an OraNumber" do
+    (OraNumber(2) + OraNumber(1)).should eql(OraNumber(3))
+  end
+
+  it "- OraNumber should be an OraNumber" do
+    (OraNumber(2) - OraNumber(1)).should eql(OraNumber(1))
+  end
+
+  it "* OraNumber should be an OraNumber" do
+    (OraNumber(2) * OraNumber(1)).should eql(OraNumber(2))
+  end
+
+  it "/ OraNumber should be an OraNumber" do
+    (OraNumber(2) / OraNumber(1)).should eql(OraNumber(2))
+  end
+
+  # OraNumber bin_op Fixnum
+  it "+ Fixnum should be an OraNumber" do
+    (OraNumber(2) + 1).should eql(OraNumber(3))
+  end
+
+  it "- Fixnum should be an OraNumber" do
+    (OraNumber(2) - 1).should eql(OraNumber(1))
+  end
+
+  it "* Fixnum should be an OraNumber" do
+    (OraNumber(2) * 1).should eql(OraNumber(2))
+  end
+
+  it "/ Fixnum should be an OraNumber" do
+    (OraNumber(2) / 1).should eql(OraNumber(2))
+  end
+
+  # OraNumber bin_op Bignum
+  it "+ Bignum should be an OraNumber" do
+    (OraNumber(2) + 100000000000000000000).should eql(OraNumber(100000000000000000002))
+  end
+
+  it "- Bignum should be an OraNumber" do
+    (OraNumber(2) - 100000000000000000000).should eql(OraNumber(-99999999999999999998))
+  end
+
+  it "* Bignum should be an OraNumber" do
+    (OraNumber(2) * 100000000000000000000).should eql(OraNumber(200000000000000000000))
+  end
+
+  it "/ Bignum should be an OraNumber" do
+    (OraNumber(2) / 100000000000000000000).should eql(OraNumber("0.00000000000000000002"))
+  end
+
+  # OraNumber bin_op Float
+  it "+ Float should be a Float" do
+    (OraNumber(2) + 1.0).should eql(3.0)
+  end
+
+  it "- Float should be a Float" do
+    (OraNumber(2) - 1.0).should eql(1.0)
+  end
+
+  it "* Float should be a Float" do
+    (OraNumber(2) * 1.0).should eql(2.0)
+  end
+
+  it "/ Float should be a Float" do
+    (OraNumber(2) / 1.0).should eql(2.0)
+  end
+
+  # OraNumber bin_op BigDecimal
+  it "+ BigDecimal should be a BigDecimal" do
+    (OraNumber(2) + BigDecimal("1")).should eql(BigDecimal("3"))
+  end
+
+  it "- BigDecimal should be a BigDecimal" do
+    (OraNumber(2) - BigDecimal("1")).should eql(BigDecimal("1"))
+  end
+
+  it "* BigDecimal should be a BigDecimal" do
+    (OraNumber(2) * BigDecimal("1")).should eql(BigDecimal("2"))
+  end
+
+  it "/ BigDecimal should be a BigDecimal" do
+    (OraNumber(2) / BigDecimal("1")).should eql(BigDecimal("2"))
+  end
+
+  # OraNumber bin_op Rational
+  it "+ Rational should be a Rational" do
+    (OraNumber(2) + Rational(1)).should eql(Rational(3))
+  end
+
+  it "- Rational should be a Rational" do
+    (OraNumber(2) - Rational(1)).should eql(Rational(1))
+  end
+
+  it "* Rational should be a Rational" do
+    (OraNumber(2) * Rational(1)).should eql(Rational(2))
+  end
+
+  it "/ Rational should be a Rational" do
+    (OraNumber(2) / Rational(1)).should eql(Rational(2))
+  end
+end
+
+describe Fixnum do
+  it "+ OraNumber should be an OraNumber" do
+    (2 + OraNumber(1)).should eql(OraNumber(3))
+  end
+
+  it "- OraNumber should be an OraNumber" do
+    (2 - OraNumber(1)).should eql(OraNumber(1))
+  end
+
+  it "* OraNumber should be an OraNumber" do
+    (2 * OraNumber(1)).should eql(OraNumber(2))
+  end
+
+  it "/ OraNumber should be an OraNumber" do
+    (2 / OraNumber(1)).should eql(OraNumber(2))
+  end
+end
+
+describe Bignum do
+  it "+ OraNumber should be an OraNumber" do
+    (100000000000000000000 + OraNumber(1)).should eql(OraNumber(100000000000000000001))
+  end
+end
+
+describe Float do
+  it "+ OraNumber should be a Float" do
+    (1.0 + OraNumber(1)).should eql(2.0)
+  end
+end
+
+describe BigDecimal do
+  it "+ OraNumber should be a BigDecimal" do
+    (BigDecimal("1") + OraNumber(1)).should eql(BigDecimal("2"))
+  end
+end
+
+describe Rational do
+  it "+ OraNumber should be a Rational" do
+    (Rational(1) + OraNumber(1)).should eql(Rational(2))
+  end
+end

Modified: trunk/ruby-oci8/test/test_oci8.rb
===================================================================
--- trunk/ruby-oci8/test/test_oci8.rb	2009-10-04 14:04:01 UTC (rev 362)
+++ trunk/ruby-oci8/test/test_oci8.rb	2009-10-06 13:46:41 UTC (rev 363)
@@ -359,10 +359,10 @@
       assert_equal(row[2], 123456789012.34)
       assert_equal(row[3], 1234567890123.45)
       assert_equal(row[4], 1234.5)
-      assert_instance_of(OraNumber, row[0])
+      assert_instance_of(BigDecimal, row[0])
       assert_instance_of(Bignum, row[1])
       assert_instance_of(Float, row[2])
-      assert_instance_of(OraNumber, row[3])
+      assert_instance_of(BigDecimal, row[3])
       assert_instance_of(Float, row[4])
     end
     drop_table('test_table')
@@ -372,6 +372,8 @@
     src = [1, 1.2, BigDecimal("1.2"), Rational(12, 10)]
     int = [1, 1, 1, 1]
     flt = [1, 1.2, 1.2, 1.2]
+    dec = [BigDecimal("1"), BigDecimal("1.2"), BigDecimal("1.2"), BigDecimal("1.2")]
+    rat = [Rational(1), Rational(12, 10), Rational(12, 10), Rational(12, 10)]
 
     cursor = @conn.parse("begin :1 := :2; end;")
 
@@ -382,6 +384,7 @@
       cursor[2] = s
       cursor.exec
       assert_equal(cursor[1], flt[idx])
+      assert_kind_of(Float, cursor[1])
     end
 
     # Fixnum
@@ -391,6 +394,7 @@
       cursor[2] = s
       cursor.exec
       assert_equal(cursor[1], int[idx])
+      assert_kind_of(Fixnum, cursor[1])
     end
 
     # Integer
@@ -400,7 +404,28 @@
       cursor[2] = s
       cursor.exec
       assert_equal(cursor[1], int[idx])
+      assert_kind_of(Integer, cursor[1])
     end
+
+    # BigDecimal
+    cursor.bind_param(1, nil, BigDecimal)
+    cursor.bind_param(2, nil, BigDecimal)
+    src.each_with_index do |s, idx|
+      cursor[2] = s
+      cursor.exec
+      assert_equal(cursor[1], dec[idx])
+      assert_kind_of(BigDecimal, cursor[1])
+    end
+
+    # Rational
+    cursor.bind_param(1, nil, Rational)
+    cursor.bind_param(2, nil, Rational)
+    src.each_with_index do |s, idx|
+      cursor[2] = s
+      cursor.exec
+      assert_equal(cursor[1], rat[idx])
+      assert_kind_of(Rational, cursor[1])
+    end
   end
 
 end # TestOCI8




More information about the ruby-oci8-commit mailing list