class Numeric include Comparable `def._isNumber = true` class << self undef_method :new end def coerce(other, type = :operation) %x{ if (other._isNumber) { return [self, other]; } else { return #{other.coerce(self)}; } } rescue case type when :operation raise TypeError, "#{other.class} can't be coerce into Numeric" when :comparison raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" end end def send_coerced(method, other) type = case method when :+, :-, :*, :/, :%, :&, :|, :^, :** :operation when :>, :>=, :<, :<=, :<=> :comparison end a, b = coerce(other, type) a.__send__ method, b end def +(other) %x{ if (other._isNumber) { return self + other; } else { return #{send_coerced :+, other}; } } end def -(other) %x{ if (other._isNumber) { return self - other; } else { return #{send_coerced :-, other}; } } end def *(other) %x{ if (other._isNumber) { return self * other; } else { return #{send_coerced :*, other}; } } end def /(other) %x{ if (other._isNumber) { return self / other; } else { return #{send_coerced :/, other}; } } end def %(other) %x{ if (other._isNumber) { if (other < 0 || self < 0) { return (self % other + other) % other; } else { return self % other; } } else { return #{send_coerced :%, other}; } } end def &(other) %x{ if (other._isNumber) { return self & other; } else { return #{send_coerced :&, other}; } } end def |(other) %x{ if (other._isNumber) { return self | other; } else { return #{send_coerced :|, other}; } } end def ^(other) %x{ if (other._isNumber) { return self ^ other; } else { return #{send_coerced :^, other}; } } end def <(other) %x{ if (other._isNumber) { return self < other; } else { return #{send_coerced :<, other}; } } end def <=(other) %x{ if (other._isNumber) { return self <= other; } else { return #{send_coerced :<=, other}; } } end def >(other) %x{ if (other._isNumber) { return self > other; } else { return #{send_coerced :>, other}; } } end def >=(other) %x{ if (other._isNumber) { return self >= other; } else { return #{send_coerced :>=, other}; } } end def <=>(other) %x{ if (other._isNumber) { return self > other ? 1 : (self < other ? -1 : 0); } else { return #{send_coerced :<=>, other}; } } rescue ArgumentError nil end def <<(count) `self << #{count.to_int}` end def >>(count) `self >> #{count.to_int}` end def +@ `+self` end def -@ `-self` end def ~ `~self` end def **(other) %x{ if (other._isNumber) { return Math.pow(self, other); } else { return #{send_coerced :**, other}; } } end def ==(other) %x{ if (other._isNumber) { return self == Number(other); } else if (#{other.respond_to? :==}) { return #{other == self}; } else { return false; } } end def abs `Math.abs(self)` end def ceil `Math.ceil(self)` end def chr `String.fromCharCode(self)` end def conj self end alias conjugate conj def downto(finish, &block) return enum_for :downto, finish unless block %x{ for (var i = self; i >= finish; i--) { if (block(i) === $breaker) { return $breaker.$v; } } } self end alias eql? == alias equal? == def even? `self % 2 === 0` end def floor `Math.floor(self)` end def hash `self.toString()` end def integer? `self % 1 === 0` end def is_a?(klass) return true if klass == Float && Float === self return true if klass == Integer && Integer === self super end alias magnitude abs alias modulo % def next `self + 1` end def nonzero? `self == 0 ? nil : self` end def odd? `self % 2 !== 0` end def ord self end def pred `self - 1` end def step(limit, step = 1, &block) return enum_for :step, limit, step unless block raise ArgumentError, 'step cannot be 0' if `step == 0` %x{ var value = self; if (step > 0) { while (value <= limit) { block(value); value += step; } } else { while (value >= limit) { block(value); value += step; } } } self end alias succ next def times(&block) return enum_for :times unless block %x{ for (var i = 0; i < self; i++) { if (block(i) === $breaker) { return $breaker.$v; } } } self end def to_f `parseFloat(#{self})` end def to_i `parseInt(#{self})` end alias to_int to_i def to_s(base = 10) if base < 2 || base > 36 raise ArgumentError, 'base must be between 2 and 36' end `self.toString(base)` end alias inspect to_s def divmod(rhs) q = (self / rhs).floor r = self % rhs [q, r] end def to_n `self.valueOf()` end def upto(finish, &block) return enum_for :upto, finish unless block %x{ for (var i = self; i <= finish; i++) { if (block(i) === $breaker) { return $breaker.$v; } } } self end def zero? `self == 0` end def size # Just a stub, JS is 32bit for bitwise ops though 4 end def nan? `isNaN(self)` end def finite? `self == Infinity || self == -Infinity` end def infinite? if `self == Infinity` `+1` elsif `self == -Infinity` `-1` end end end Fixnum = Numeric class Integer < Numeric def self.===(other) `!!(other._isNumber && (other % 1) == 0)` end end class Float < Numeric def self.===(other) `!!(other._isNumber && (other % 1) != 0)` end end