summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--appveyor_config.rb2
-rw-r--r--include/mrbconf.h3
-rw-r--r--mrbgems/mruby-compiler/core/parse.y143
-rw-r--r--mrbgems/mruby-complex/mrbgem.rake10
-rw-r--r--mrbgems/mruby-complex/mrblib/complex.rb168
-rw-r--r--mrbgems/mruby-complex/test/complex.rb130
-rw-r--r--mrbgems/mruby-rational/mrbgem.rake9
-rw-r--r--mrbgems/mruby-rational/mrblib/rational.rb102
-rw-r--r--mrbgems/mruby-rational/test/rational.rb57
-rw-r--r--travis_config.rb2
10 files changed, 611 insertions, 15 deletions
diff --git a/appveyor_config.rb b/appveyor_config.rb
index 2555b2f62..b50a9e4ef 100644
--- a/appveyor_config.rb
+++ b/appveyor_config.rb
@@ -17,7 +17,7 @@ MRuby::Build.new('full-debug') do |conf|
# include all core GEMs
conf.gembox 'full-core'
- conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK)
+ conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK)
conf.enable_test
end
diff --git a/include/mrbconf.h b/include/mrbconf.h
index 6b0b9e37e..ee816e322 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -63,6 +63,9 @@
# endif
#endif
+#define MRB_COMPLEX_NUMBERS
+#define MRB_RATIONAL_NUMBERS
+
/* define on big endian machines; used by MRB_NAN_BOXING, etc. */
#ifndef MRB_ENDIAN_BIG
# if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index b7d47118f..3ad11f406 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -76,6 +76,24 @@ typedef unsigned int stack_type;
#define nint(x) ((node*)(intptr_t)(x))
#define intn(x) ((int)(intptr_t)(x))
+#if defined(MRB_COMPLEX_NUMBERS) || defined(MRB_RATIONAL_NUMBERS)
+ #define MRB_SUFFIX_SUPPORT
+
+ #ifdef MRB_RATIONAL_NUMBERS
+ #define NUM_SUFFIX_R (1<<0)
+ #else
+ #define NUM_SUFFIX_R 0
+ #endif
+
+ #ifdef MRB_COMPLEX_NUMBERS
+ #define NUM_SUFFIX_I (1<<1)
+ #else
+ #define NUM_SUFFIX_I 0
+ #endif
+
+ #define NUM_SUFFIX_ALL (NUM_SUFFIX_R | NUM_SUFFIX_I)
+#endif
+
static inline mrb_sym
intern_cstr_gen(parser_state *p, const char *s)
{
@@ -842,19 +860,57 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
}
+#ifdef MRB_COMPLEX_NUMBERS
+static node*
+new_imaginary(parser_state *p, node *imaginary)
+{
+ return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Complex"), list1(list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary)), 1);
+}
+#endif
+
+#ifdef MRB_RATIONAL_NUMBERS
+static node*
+new_rational(parser_state *p, node *rational)
+{
+ return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Rational"), list1(list1(rational)), 1);
+}
+#endif
+
/* (:int . i) */
static node*
-new_int(parser_state *p, const char *s, int base)
+new_int(parser_state *p, const char *s, int base, int suffix)
{
- return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
+ node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base));
+#ifdef MRB_RATIONAL_NUMBERS
+ if (suffix & NUM_SUFFIX_R) {
+ result = new_rational(p, result);
+ }
+#endif
+#ifdef MRB_COMPLEX_NUMBERS
+ if (suffix & NUM_SUFFIX_I) {
+ result = new_imaginary(p, result);
+ }
+#endif
+ return result;
}
#ifndef MRB_WITHOUT_FLOAT
/* (:float . i) */
static node*
-new_float(parser_state *p, const char *s)
+new_float(parser_state *p, const char *s, int suffix)
{
- return cons((node*)NODE_FLOAT, (node*)strdup(s));
+ node* result = cons((node*)NODE_FLOAT, (node*)strdup(s));
+#ifdef MRB_RATIONAL_NUMBERS
+ if (suffix & NUM_SUFFIX_R) {
+ result = new_rational(p, result);
+ }
+#endif
+#ifdef MRB_COMPLEX_NUMBERS
+ if (suffix & NUM_SUFFIX_I) {
+ result = new_imaginary(p, result);
+ }
+#endif
+ return result;
}
#endif
@@ -3192,7 +3248,7 @@ var_ref : variable
char buf[16];
dump_int(p->lineno, buf);
- $$ = new_int(p, buf, 10);
+ $$ = new_int(p, buf, 10, 0);
}
| keyword__ENCODING__
{
@@ -4520,6 +4576,45 @@ parse_string(parser_state *p)
return tSTRING;
}
+#ifdef MRB_SUFFIX_SUPPORT
+static int
+number_literal_suffix(parser_state *p, int mask)
+{
+ int c, result = 0;
+ node *list = 0;
+ int column = p->column;
+
+ while ((c = nextc(p)) != -1) {
+ list = push(list, (node*)(intptr_t)c);
+
+ if ((mask & NUM_SUFFIX_I) && c == 'i') {
+ result |= (mask & NUM_SUFFIX_I);
+ mask &= ~NUM_SUFFIX_I;
+ /* r after i, rational of complex is disallowed */
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if ((mask & NUM_SUFFIX_R) && c == 'r') {
+ result |= (mask & NUM_SUFFIX_R);
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+ p->column = column;
+ if (p->pb) {
+ p->pb = append((node*)list, p->pb);
+ }
+ else {
+ p->pb = list;
+ }
+ return 0;
+ }
+ pushback(p, c);
+ break;
+ }
+ return result;
+}
+#endif
static int
heredoc_identifier(parser_state *p)
@@ -5094,6 +5189,7 @@ parser_yylex(parser_state *p)
case '5': case '6': case '7': case '8': case '9':
{
int is_float, seen_point, seen_e, nondigit;
+ int suffix = 0;
is_float = seen_point = seen_e = nondigit = 0;
p->lstate = EXPR_ENDARG;
@@ -5127,7 +5223,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
- pylval.nd = new_int(p, tok(p), 16);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, tok(p), 16, suffix);
return tINTEGER;
}
if (c == 'b' || c == 'B') {
@@ -5151,7 +5250,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
- pylval.nd = new_int(p, tok(p), 2);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, tok(p), 2, suffix);
return tINTEGER;
}
if (c == 'd' || c == 'D') {
@@ -5175,7 +5277,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
- pylval.nd = new_int(p, tok(p), 10);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, tok(p), 10, suffix);
return tINTEGER;
}
if (c == '_') {
@@ -5208,7 +5313,10 @@ parser_yylex(parser_state *p)
pushback(p, c);
tokfix(p);
if (nondigit) goto trailing_uc;
- pylval.nd = new_int(p, tok(p), 8);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, tok(p), 8, suffix);
return tINTEGER;
}
if (nondigit) {
@@ -5225,7 +5333,10 @@ parser_yylex(parser_state *p)
}
else {
pushback(p, c);
- pylval.nd = new_int(p, "0", 10);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, "0", 10, suffix);
return tINTEGER;
}
}
@@ -5299,7 +5410,7 @@ parser_yylex(parser_state *p)
if (is_float) {
#ifdef MRB_WITHOUT_FLOAT
yywarning(p, "floating point numbers are not supported");
- pylval.nd = new_int(p, "0", 10);
+ pylval.nd = new_int(p, "0", 10, 0);
return tINTEGER;
#else
double d;
@@ -5314,11 +5425,17 @@ parser_yylex(parser_state *p)
yywarning_s(p, "float out of range", tok(p));
errno = 0;
}
- pylval.nd = new_float(p, tok(p));
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_float(p, tok(p), suffix);
return tFLOAT;
#endif
}
- pylval.nd = new_int(p, tok(p), 10);
+ #ifdef MRB_SUFFIX_SUPPORT
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ #endif
+ pylval.nd = new_int(p, tok(p), 10, suffix);
return tINTEGER;
}
diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake
new file mode 100644
index 000000000..19612e74d
--- /dev/null
+++ b/mrbgems/mruby-complex/mrbgem.rake
@@ -0,0 +1,10 @@
+MRuby::Gem::Specification.new('mruby-complex') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = 'Complex class'
+
+ spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog'
+ spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext'
+ spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext'
+ spec.add_dependency 'mruby-math', core: 'mruby-math'
+end
diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb
new file mode 100644
index 000000000..266c00c36
--- /dev/null
+++ b/mrbgems/mruby-complex/mrblib/complex.rb
@@ -0,0 +1,168 @@
+class Complex < Numeric
+ def initialize(real, imaginary)
+ real = real.to_f unless real.is_a? Numeric
+ imaginary = imaginary.to_f unless imaginary.is_a? Numeric
+ @real = real
+ @imaginary = imaginary
+ end
+
+ def self.polar(abs, arg = 0)
+ Complex(abs * Math.cos(arg), abs * Math.sin(arg))
+ end
+
+ def self.rectangular(real, imaginary = 0)
+ _new(real, imaginary)
+ end
+
+ def inspect
+ "(#{to_s})"
+ end
+
+ def to_s
+ "#{real}#{'+' unless imaginary.negative?}#{imaginary}i"
+ end
+
+ def +@
+ Complex(real, imaginary)
+ end
+
+ def -@
+ Complex(-real, -imaginary)
+ end
+
+ def +(rhs)
+ if rhs.is_a? Complex
+ Complex(real + rhs.real, imaginary + rhs.imaginary)
+ elsif rhs.is_a? Numeric
+ Complex(real + rhs, imaginary)
+ end
+ end
+
+ def -(rhs)
+ if rhs.is_a? Complex
+ Complex(real - rhs.real, imaginary - rhs.imaginary)
+ elsif rhs.is_a? Numeric
+ Complex(real - rhs, imaginary)
+ end
+ end
+
+ def *(rhs)
+ if rhs.is_a? Complex
+ Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary)
+ elsif rhs.is_a? Numeric
+ Complex(real * rhs, imaginary * rhs)
+ end
+ end
+
+ def /(rhs)
+ if rhs.is_a? Complex
+ div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary
+ Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div)
+ elsif rhs.is_a? Numeric
+ Complex(real / rhs, imaginary / rhs)
+ end
+ end
+ alias_method :quo, :/
+
+ def ==(rhs)
+ if rhs.is_a? Complex
+ real == rhs.real && imaginary == rhs.imaginary
+ elsif rhs.is_a? Numeric
+ imaginary.zero? && real == rhs
+ end
+ end
+
+ def abs
+ Math.sqrt(abs2)
+ end
+ alias_method :magnitude, :abs
+
+ def abs2
+ real * real + imaginary * imaginary
+ end
+
+ def arg
+ Math.atan2 imaginary, real
+ end
+ alias_method :angle, :arg
+ alias_method :phase, :arg
+
+ def conjugate
+ Complex(real, -imaginary)
+ end
+ alias_method :conj, :conjugate
+
+ def numerator
+ self
+ end
+
+ def denominator
+ 1
+ end
+
+ def fdiv(numeric)
+ Complex(real.to_f / numeric, imaginary.to_f / numeric)
+ end
+
+ def polar
+ [abs, arg]
+ end
+
+ def real?
+ false
+ end
+
+ def rectangular
+ [real, imaginary]
+ end
+ alias_method :rect, :rectangular
+
+ def to_c
+ self
+ end
+
+ def to_f
+ raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero?
+ real.to_f
+ end
+
+ def to_i
+ raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero?
+ real.to_i
+ end
+
+ def to_r
+ raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero?
+ Rational(real, 1)
+ end
+
+ attr_reader :real, :imaginary
+ alias_method :imag, :imaginary
+end
+
+class << Complex
+ alias_method :_new, :new
+ undef_method :new
+
+ alias_method :rect, :rectangular
+end
+
+def Complex(real, imaginary = 0)
+ Complex.rectangular(real, imaginary)
+end
+
+[Fixnum, Float].each do |cls|
+ [:+, :-, :*, :/, :==].each do |op|
+ cls.instance_exec do
+ original_operator_name = "__original_operator_#{op}_complex"
+ alias_method original_operator_name, op
+ define_method op do |rhs|
+ if rhs.is_a? Complex
+ Complex(self).send(op, rhs)
+ else
+ send(original_operator_name, rhs)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb
new file mode 100644
index 000000000..ca58202c2
--- /dev/null
+++ b/mrbgems/mruby-complex/test/complex.rb
@@ -0,0 +1,130 @@
+def assert_complex(real, exp)
+ assert_float real.real, exp.real
+ assert_float real.imaginary, exp.imaginary
+end
+
+assert 'Complex' do
+ c = 123i
+ assert_equal Complex, c.class
+ assert_equal [c.real, c.imaginary], [0, 123]
+ c = 123 + -1.23i
+ assert_equal Complex, c.class
+ assert_equal [c.real, c.imaginary], [123, -1.23]
+end
+
+assert 'Complex::polar' do
+ assert_complex Complex.polar(3, 0), (3 + 0i)
+ assert_complex Complex.polar(3, Math::PI/2), (0 + 3i)
+ assert_complex Complex.polar(3, Math::PI), (-3 + 0i)
+ assert_complex Complex.polar(3, -Math::PI/2), (0 + -3i)
+end
+
+assert 'Complex::rectangular' do
+ assert_complex Complex.rectangular(1, 2), (1 + 2i)
+end
+
+assert 'Complex#*' do
+ assert_complex Complex(2, 3) * Complex(2, 3), (-5 + 12i)
+ assert_complex Complex(900) * Complex(1), (900 + 0i)
+ assert_complex Complex(-2, 9) * Complex(-9, 2), (0 - 85i)
+ assert_complex Complex(9, 8) * 4, (36 + 32i)
+ assert_complex Complex(20, 9) * 9.8, (196.0 + 88.2i)
+end
+
+assert 'Complex#+' do
+ assert_complex Complex(2, 3) + Complex(2, 3) , (4 + 6i)
+ assert_complex Complex(900) + Complex(1) , (901 + 0i)
+ assert_complex Complex(-2, 9) + Complex(-9, 2), (-11 + 11i)
+ assert_complex Complex(9, 8) + 4 , (13 + 8i)
+ assert_complex Complex(20, 9) + 9.8 , (29.8 + 9i)
+end
+
+assert 'Complex#-' do
+ assert_complex Complex(2, 3) - Complex(2, 3) , (0 + 0i)
+ assert_complex Complex(900) - Complex(1) , (899 + 0i)
+ assert_complex Complex(-2, 9) - Complex(-9, 2), (7 + 7i)
+ assert_complex Complex(9, 8) - 4 , (5 + 8i)
+ assert_complex Complex(20, 9) - 9.8 , (10.2 + 9i)
+end
+
+assert 'Complex#-@' do
+ assert_complex -Complex(1, 2), (-1 - 2i)
+end
+
+assert 'Complex#/' do
+ assert_complex Complex(2, 3) / Complex(2, 3) , (1 + 0i)
+ assert_complex Complex(900) / Complex(1) , (900 + 0i)
+ assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85) - (77i / 85))
+ assert_complex Complex(9, 8) / 4 , ((9 / 4) + 2i)
+ assert_complex Complex(20, 9) / 9.8 , (2.0408163265306123 + 0.9183673469387754i)
+end
+
+assert 'Complex#==' do
+ assert_true Complex(2, 3) == Complex(2, 3)
+ assert_true Complex(5) == 5
+ assert_true Complex(0) == 0.0
+ assert_false Complex('1/3') == 0.33
+ assert_false Complex('1/2') == '1/2'
+end
+
+assert 'Complex#abs' do
+ assert_float Complex(-1).abs, 1
+ assert_float Complex(3.0, -4.0).abs, 5.0
+end
+
+assert 'Complex#abs2' do
+ assert_float Complex(-1).abs2, 1
+ assert_float Complex(3.0, -4.0).abs2, 25.0
+end
+
+assert 'Complex#arg' do
+ assert_float Complex.polar(3, Math::PI/2).arg, 1.5707963267948966
+end
+
+assert 'Complex#conjugate' do
+ assert_complex Complex(1, 2).conjugate, (1 - 2i)
+end
+
+assert 'Complex#fdiv' do
+ assert_complex Complex(11, 22).fdiv(3), (3.6666666666666665 + 7.333333333333333i)
+end
+
+assert 'Complex#imaginary' do
+ assert_float Complex(7).imaginary , 0
+ assert_float Complex(9, -4).imaginary, -4
+end
+
+assert 'Complex#polar' do
+ assert_equal Complex(1, 2).polar, [2.23606797749979, 1.1071487177940904]
+end
+
+assert 'Complex#real' do
+ assert_float Complex(7).real, 7
+ assert_float Complex(9, -4).real, 9
+end
+
+assert 'Complex#real?' do
+ assert_false Complex(1).real?
+end
+
+assert 'Complex::rectangular' do
+ assert_equal Complex(1, 2).rectangular, [1, 2]
+end
+
+assert 'Complex::to_c' do
+ assert_equal Complex(1, 2).to_c, Complex(1, 2)
+end
+
+assert 'Complex::to_f' do
+ assert_float Complex(1, 0).to_f, 1.0
+ assert_raise(RangeError) do
+ Complex(1, 2).to_f
+ end
+end
+
+assert 'Complex::to_i' do
+ assert_equal Complex(1, 0).to_i, 1
+ assert_raise(RangeError) do
+ Complex(1, 2).to_i
+ end
+end \ No newline at end of file
diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake
new file mode 100644
index 000000000..93f5b601c
--- /dev/null
+++ b/mrbgems/mruby-rational/mrbgem.rake
@@ -0,0 +1,9 @@
+MRuby::Gem::Specification.new('mruby-rational') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = 'Rational class'
+
+ spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog'
+ spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext'
+ spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext'
+end
diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb
new file mode 100644
index 000000000..7d5b87362
--- /dev/null
+++ b/mrbgems/mruby-rational/mrblib/rational.rb
@@ -0,0 +1,102 @@
+class Rational < Numeric
+ def initialize(numerator = 0, denominator = 1)
+ @numerator = numerator
+ @denominator = denominator
+
+ _simplify
+ end
+
+ def inspect
+ "(#{to_s})"
+ end
+
+ def to_f
+ @numerator.to_f / @denominator.to_f
+ end
+
+ def to_i
+ to_f.to_i
+ end
+
+ def to_r
+ self
+ end
+
+ def to_s
+ "#{numerator}/#{denominator}"
+ end
+
+ def *(rhs)
+ if rhs.is_a? Rational
+ Rational(numerator * rhs.numerator, denominator * rhs.denominator)
+ elsif rhs.is_a? Integer
+ Rational(numerator * rhs, denominator)
+ elsif rhs.is_a? Numeric
+ numerator * rhs / denominator
+ end
+ end
+
+ def +(rhs)
+ if rhs.is_a? Rational
+ Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator)
+ elsif rhs.is_a? Integer
+ Rational(numerator + rhs * denominator, denominator)
+ elsif rhs.is_a? Numeric
+ (numerator + rhs * denominator) / denominator
+ end
+ end
+
+ def -(rhs)
+ if rhs.is_a? Rational
+ Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator)
+ elsif rhs.is_a? Integer
+ Rational(numerator - rhs * denominator, denominator)
+ elsif rhs.is_a? Numeric
+ (numerator - rhs * denominator) / denominator
+ end
+ end
+
+ def /(rhs)
+ if rhs.is_a? Rational
+ Rational(numerator * rhs.denominator, denominator * rhs.numerator)
+ elsif rhs.is_a? Integer
+ Rational(numerator, denominator * rhs)
+ elsif rhs.is_a? Numeric
+ numerator / rhs / denominator
+ end
+ end
+
+ def negative?
+ numerator.negative?
+ end
+
+ def _simplify
+ a = numerator
+ b = denominator
+ a, b = b, a % b while !b.zero?
+ @numerator /= a
+ @denominator /= a
+ end
+
+ attr_reader :numerator, :denominator
+end
+
+def Rational(numerator = 0, denominator = 1)
+ Rational.new(numerator, denominator)
+end
+
+[Fixnum, Float].each do |cls|
+ [:+, :-, :*, :/, :==].each do |op|
+ cls.instance_exec do
+ original_operator_name = "__original_operator_#{op}_rational"
+ alias_method original_operator_name, op
+ define_method op do |rhs|
+ if rhs.is_a? Rational
+ Rational(self).send(op, rhs)
+ else
+ send(original_operator_name, rhs)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb
new file mode 100644
index 000000000..85cebc316
--- /dev/null
+++ b/mrbgems/mruby-rational/test/rational.rb
@@ -0,0 +1,57 @@
+def assert_rational(real, exp)
+ assert_float real.numerator, exp.numerator
+ assert_float real.denominator, exp.denominator
+end
+
+assert 'Rational' do
+ r = 5r
+ assert_equal Rational, r.class
+ assert_equal [r.numerator, r.denominator], [5, 1]
+end
+
+assert 'Rational#to_f' do
+ assert_float Rational(2).to_f, 2.0
+ assert_float Rational(9, 4).to_f, 2.25
+ assert_float Rational(-3, 4).to_f, -0.75
+ assert_float Rational(20, 3).to_f, 6.666666666666667
+end
+
+assert 'Rational#to_i' do
+ assert_equal Rational(2, 3).to_i, 0
+ assert_equal Rational(3).to_i, 3
+ assert_equal Rational(300.6).to_i, 300
+ assert_equal Rational(98, 71).to_i, 1
+ assert_equal Rational(-30, 2).to_i, -15
+end
+
+assert 'Rational#*' do
+ assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9)
+ assert_rational Rational(900) * Rational(1), Rational(900, 1)
+ assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1)
+ assert_rational Rational(9, 8) * 4, Rational(9, 2)
+ assert_float Rational(20, 9) * 9.8, 21.77777777777778
+end
+
+assert 'Rational#+' do
+ assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3)
+ assert_rational Rational(900) + Rational(1), Rational(901, 1)
+ assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18)
+ assert_rational Rational(9, 8) + 4, Rational(41, 8)
+ assert_float Rational(20, 9) + 9.8, 12.022222222222222
+end
+
+assert 'Rational#-' do
+ assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1)
+ assert_rational Rational(900) - Rational(1), Rational(899, 1)
+ assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18)
+ assert_rational Rational(9, 8) - 4, Rational(-23, 8)
+ assert_float Rational(20, 9) - 9.8, -7.577777777777778
+end
+
+assert 'Rational#/' do
+ assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1)
+ assert_rational Rational(900) / Rational(1), Rational(900, 1)
+ assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81)
+ assert_rational Rational(9, 8) / 4, Rational(9, 32)
+ assert_float Rational(20, 9) / 9.8, 0.22675736961451246
+end \ No newline at end of file
diff --git a/travis_config.rb b/travis_config.rb
index e12bae648..7a13ced72 100644
--- a/travis_config.rb
+++ b/travis_config.rb
@@ -18,7 +18,7 @@ MRuby::Build.new('full-debug') do |conf|
# include all core GEMs
conf.gembox 'full-core'
- conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK)
+ conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK)
conf.enable_test
end