class Array include Enumerable # Mark all javascript arrays as being valid ruby arrays `def._isArray = true` def self.[](*objects) objects end def initialize(*args) self.class.new(*args) end def self.new(size = undefined, obj = nil, &block) %x{ if (arguments.length > 2) #{raise ArgumentError.new("wrong number of arguments. Array#new")}; if (arguments.length == 0) return []; var size, obj = arguments[1], arr = []; if (!obj) { if (#{size.respond_to? :to_ary}) { if (size['$is_a?'](Array)) return size; return size['$to_ary'](); } } if (typeof(arguments[0]) == 'number') size = arguments[0]; else { if (#{`arguments[0]`.respond_to? :to_int}) { size = arguments[0]['$to_int'](); if (typeof(size) == 'number') { if (size % 1 !== 0) { #{raise TypeError.new("can't convert to Integer. Array#new")}; } } else { #{raise TypeError.new("can't convert to Integer. Array#new")}; } } else { #{raise TypeError.new("can't convert to Integer. Array#new")}; } } if (size < 0) { #{raise ArgumentError.new("negative array size")}; } if (obj == undefined) { obj = nil; } if (block === nil) for (var i = 0; i < size; i++) { arr.push(obj); } else { for (var i = 0, value; i < size; i++) { value = block(i); if (value === $breaker) { return $breaker.$v; } arr[i] = block(i); } } return arr; } end def self.try_convert(obj) %x{ if (obj._isArray) { return obj; } return nil; } end def &(other) %x{ var result = [], seen = {}; for (var i = 0, length = #{self}.length; i < length; i++) { var item = #{self}[i]; if (item._isString) { item = item.toString(); } if (!seen[item]) { for (var j = 0, length2 = other.length; j < length2; j++) { var item2 = other[j]; if (item2._isString) { item2 = item2.toString(); } if (item === item2 && !seen[item]) { seen[item] = true; result.push(item); } } } } return result; } end def *(other) %x{ if (typeof(other) === 'string') { return #{self}.join(other); } var result = []; for (var i = 0; i < other; i++) { result = result.concat(#{self}); } return result; } end def +(other) %x{ var arr = other; if (!other._isArray){ if (#{other.respond_to?(:to_ary)}) { arr = other['$to_ary'](); } else { #{raise TypeError.new("can't convert to Array. Array#+") }; } } return #{self}.concat(arr); } end def -(other) %x{ var a = #{self}, b = #{other}, tmp = [], result = []; if (typeof(b) == "object" && !(b._isArray)) { if (#{other.respond_to? :to_ary}) { b = b['$to_ary'](); } else { #{raise TypeError.new("can't convert to Array. Array#-") }; } }else if ((typeof(b) != "object")) { #{raise TypeError.new("can't convert to Array. Array#-") }; } if (a.length == 0) return []; if (b.length == 0) return a; for(var i = 0, length = b.length; i < length; i++) { tmp[b[i]] = true; } for(var i = 0, length = a.length; i < length; i++) { if (!tmp[a[i]]) { result.push(a[i]); } } return result; } end def <<(object) `#{self}.push(object);` self end def <=>(other) %x{ if (#{self.hash} === #{other.hash}) { return 0; } if (#{self}.length != other.length) { return (#{self}.length > other.length) ? 1 : -1; } for (var i = 0, length = #{self}.length, tmp; i < length; i++) { if ((tmp = #{`#{self}[i]` <=> `other[i]`}) !== 0) { return tmp; } } return 0; } end def ==(other) %x{ if (!other || (#{self}.length !== other.length)) { return false; } for (var i = 0, length = #{self}.length, tmp1, tmp2; i < length; i++) { tmp1 = #{self}[i]; tmp2 = #{other}[i]; if (tmp1._isArray && tmp2._isArray && (tmp1 === #{self})) { continue; } if (!(#{`tmp1` == `tmp2`})) { return false; } } return true; } end def [](index, length = undefined) %x{ var size = #{self}.length; if (typeof index !== 'number' && !index._isNumber) { if (index._isRange) { var exclude = index.exclude; length = index.end; index = index.begin; if (index > size) { return nil; } if (length < 0) { length += size; } if (!exclude) length += 1; return #{self}.slice(index, length); } else { #{ raise "bad arg for Array#[]" }; } } if (index < 0) { index += size; } if (length !== undefined) { if (length < 0 || index > size || index < 0) { return nil; } return #{self}.slice(index, index + length); } else { if (index >= size || index < 0) { return nil; } return #{self}[index]; } } end def []=(index, value) %x{ var size = #{self}.length; if (index < 0) { index += size; } return #{self}[index] = value; } end def assoc(object) %x{ for (var i = 0, length = #{self}.length, item; i < length; i++) { if (item = #{self}[i], item.length && #{`item[0]` == object}) { return item; } } return nil; } end def at(index) %x{ if (index < 0) { index += #{self}.length; } if (index < 0 || index >= #{self}.length) { return nil; } return #{self}[index]; } end def clear `#{self}.splice(0, #{self}.length)` self end def clone `#{self}.slice()` end def collect(&block) %x{ var result = []; for (var i = 0, length = #{self}.length, value; i < length; i++) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } result.push(value); } return result; } end def collect!(&block) %x{ for (var i = 0, length = #{self}.length, val; i < length; i++) { if ((val = block(#{self}[i])) === $breaker) { return $breaker.$v; } #{self}[i] = val; } } self end def compact %x{ var result = []; for (var i = 0, length = #{self}.length, item; i < length; i++) { if ((item = #{self}[i]) !== nil) { result.push(item); } } return result; } end def compact! %x{ var original = #{self}.length; for (var i = 0, length = #{self}.length; i < length; i++) { if (#{self}[i] === nil) { #{self}.splice(i, 1); length--; i--; } } return #{self}.length === original ? nil : #{self}; } end def concat(other) %x{ for (var i = 0, length = other.length; i < length; i++) { #{self}.push(other[i]); } } self end def count(object = undefined) %x{ if (object == null) { return #{self}.length; } var result = 0; for (var i = 0, length = #{self}.length; i < length; i++) { if (#{`#{self}[i]` == object}) { result++; } } return result; } end def delete(object) %x{ var original = #{self}.length; for (var i = 0, length = original; i < length; i++) { if (#{`#{self}[i]` == object}) { #{self}.splice(i, 1); length--; i--; } } return #{self}.length === original ? nil : object; } end def delete_at(index) %x{ if (index < 0) { index += #{self}.length; } if (index < 0 || index >= #{self}.length) { return nil; } var result = #{self}[index]; #{self}.splice(index, 1); return result; } end def delete_if(&block) %x{ for (var i = 0, length = #{self}.length, value; i < length; i++) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } if (value !== false && value !== nil) { #{self}.splice(i, 1); length--; i--; } } } self end def drop(number) `#{self}.slice(number)` end alias dup clone def each(&block) return enum_for :each unless block_given? %x{ if (block.length > 1) { for (var i = 0, length = #{self}.length, el; i < length; i++) { el = #{self}[i]; if (!el._isArray) el = [el]; if (block.apply(null, el) === $breaker) return $breaker.$v; } } else { for (var i = 0, length = #{self}.length; i < length; i++) { if (block(#{self}[i]) === $breaker) return $breaker.$v; } } } self end def each_index(&block) `for (var i = 0, length = #{self}.length; i < length; i++) {` yield `i` `}` self end def empty? `!#{self}.length` end def fetch(index, defaults = undefined, &block) %x{ var original = index; if (index < 0) { index += #{self}.length; } if (index >= 0 && index < #{self}.length) { return #{self}[index]; } if (defaults != null) { return defaults; } if (block !== nil) { return block(original); } #{ raise IndexError, "Array#fetch" }; } end def fill(obj = undefined, &block) %x{ if (block !== nil) { for (var i = 0, length = #{self}.length; i < length; i++) { #{self}[i] = block(i); } } else { for (var i = 0, length = #{self}.length; i < length; i++) { #{self}[i] = obj; } } } self end def first(count = undefined) %x{ if (count != null) { return #{self}.slice(0, count); } return #{self}.length === 0 ? nil : #{self}[0]; } end def flatten(level = undefined) %x{ var result = []; for (var i = 0, length = #{self}.length, item; i < length; i++) { item = #{self}[i]; if (item._isArray) { if (level == null) { result = result.concat(#{`item`.flatten}); } else if (level === 0) { result.push(item); } else { result = result.concat(#{`item`.flatten(`level - 1`)}); } } else { result.push(item); } } return result; } end def flatten!(level = undefined) %x{ var size = #{self}.length; #{replace flatten level}; return size === #{self}.length ? nil : #{self}; } end def hash `#{self}._id || (#{self}._id = Opal.uid())` end def include?(member) %x{ for (var i = 0, length = #{self}.length; i < length; i++) { if (#{`#{self}[i]` == member}) { return true; } } return false; } end def index(object=undefined, &block) %x{ if (object != null) { for (var i = 0, length = #{self}.length; i < length; i++) { if (#{`#{self}[i]` == object}) { return i; } } } else if (block !== nil) { for (var i = 0, length = #{self}.length, value; i < length; i++) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } if (value !== false && value !== nil) { return i; } } } return nil; } end def insert(index, *objects) %x{ if (objects.length > 0) { if (index < 0) { index += #{self}.length + 1; if (index < 0) { #{ raise IndexError, "#{index} is out of bounds" }; } } if (index > #{self}.length) { for (var i = #{self}.length; i < index; i++) { #{self}.push(nil); } } #{self}.splice.apply(#{self}, [index, 0].concat(objects)); } } self end def inspect %x{ var i, inspect, el, el_insp, length, object_id; inspect = []; object_id = #{object_id}; length = #{self}.length; for (i = 0; i < length; i++) { el = #{self[`i`]}; // Check object_id to ensure it's not the same array get into an infinite loop el_insp = #{`el`.object_id} === object_id ? '[...]' : #{`el`.inspect}; inspect.push(el_insp); } return '[' + inspect.join(', ') + ']'; } end def join(sep = '') %x{ var result = []; for (var i = 0, length = #{self}.length; i < length; i++) { result.push(#{`#{self}[i]`.to_s}); } return result.join(sep); } end def keep_if(&block) %x{ for (var i = 0, length = #{self}.length, value; i < length; i++) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } if (value === false || value === nil) { #{self}.splice(i, 1); length--; i--; } } } self end def last(count = undefined) %x{ var length = #{self}.length; if (count === nil || typeof(count) == 'string') { #{ raise TypeError, "no implicit conversion to integer" }; } if (typeof(count) == 'object') { if (#{count.respond_to? :to_int}) { count = count['$to_int'](); } else { #{ raise TypeError, "no implicit conversion to integer" }; } } if (count == null) { return length === 0 ? nil : #{self}[length - 1]; } else if (count < 0) { #{ raise ArgumentError, "negative count given" }; } if (count > length) { count = length; } return #{self}.slice(length - count, length); } end def length `#{self}.length` end alias map collect alias map! collect! def pop(count = undefined) %x{ var length = #{self}.length; if (count == null) { return length === 0 ? nil : #{self}.pop(); } if (count < 0) { #{ raise "negative count given" }; } return count > length ? #{self}.splice(0, #{self}.length) : #{self}.splice(length - count, length); } end def push(*objects) %x{ for (var i = 0, length = objects.length; i < length; i++) { #{self}.push(objects[i]); } } self end def rassoc(object) %x{ for (var i = 0, length = #{self}.length, item; i < length; i++) { item = #{self}[i]; if (item.length && item[1] !== undefined) { if (#{`item[1]` == object}) { return item; } } } return nil; } end def reject(&block) %x{ var result = []; for (var i = 0, length = #{self}.length, value; i < length; i++) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } if (value === false || value === nil) { result.push(#{self}[i]); } } return result; } end def reject!(&block) %x{ var original = #{self}.length; #{ delete_if &block }; return #{self}.length === original ? nil : #{self}; } end def replace(other) %x{ #{self}.splice(0, #{self}.length); #{self}.push.apply(#{self}, other); return #{self}; } end def reverse `#{self}.slice(0).reverse()` end def reverse! `#{self}.reverse()` end def reverse_each(&block) reverse.each &block self end def rindex(object = undefined, &block) %x{ if (block !== nil) { for (var i = #{self}.length - 1, value; i >= 0; i--) { if ((value = block(#{self}[i])) === $breaker) { return $breaker.$v; } if (value !== false && value !== nil) { return i; } } } else { for (var i = #{self}.length - 1; i >= 0; i--) { if (#{`#{self}[i]` == `object`}) { return i; } } } return nil; } end def select(&block) %x{ var result = []; for (var i = 0, length = #{self}.length, item, value; i < length; i++) { item = #{self}[i]; if ((value = block(item)) === $breaker) { return $breaker.$v; } if (value !== false && value !== nil) { result.push(item); } } return result; } end def select!(&block) %x{ var original = #{self}.length; #{ keep_if &block }; return #{self}.length === original ? nil : #{self}; } end def shift(count = undefined) %x{ if (#{self}.length === 0) { return nil; } return count == null ? #{self}.shift() : #{self}.splice(0, count) } end alias size length def shuffle %x{ for (var i = #{self}.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var tmp = #{self}[i]; #{self}[i] = #{self}[j]; #{self}[j] = tmp; } return #{self}; } end alias slice :[] def slice!(index, length = undefined) %x{ if (index < 0) { index += #{self}.length; } if (length != null) { return #{self}.splice(index, length); } if (index < 0 || index >= #{self}.length) { return nil; } return #{self}.splice(index, 1)[0]; } end def sort(&block) %x{ var copy = #{self}.slice(); var t_arg_error = false; var t_break = []; if (block !== nil) { var result = copy.sort(function(x, y) { var result = block(x, y); if (result === $breaker) { t_break.push($breaker.$v); } if (result === nil) { t_arg_error = true; } if ((result != null) && #{ `result`.respond_to? :<=> }) { result = result['$<=>'](0); } if (result !== -1 && result !== 0 && result !== 1) { t_arg_error = true; } return result; }); if (t_break.length > 0) return t_break[0]; if (t_arg_error) #{raise ArgumentError, "Array#sort"}; return result; } var result = copy.sort(function(a, b){ if (typeof(a) !== typeof(b)) { t_arg_error = true; } if (a['$<=>'] && typeof(a['$<=>']) == "function") { var result = a['$<=>'](b); if (result === nil) { t_arg_error = true; } return result; } if (a > b) return 1; if (a < b) return -1; return 0; }); if (t_arg_error) #{raise ArgumentError, "Array#sort"}; return result; } end def sort!(&block) %x{ var result; if (block !== nil) { //strangely result = #{self}.slice().sort(block); } else { result = #{self}.slice()['$sort'](); } #{self}.length = 0; for(var i = 0; i < result.length; i++) { #{self}.push(result[i]); } return #{self}; } end def take(count) `#{self}.slice(0, count)` end def take_while(&block) %x{ var result = []; for (var i = 0, length = #{self}.length, item, value; i < length; i++) { item = #{self}[i]; if ((value = block(item)) === $breaker) { return $breaker.$v; } if (value === false || value === nil) { return result; } result.push(item); } return result; } end def to_a self end alias to_ary to_a def to_n %x{ var result = [], obj for (var i = 0, len = #{self}.length; i < len; i++) { obj = #{self}[i]; if (obj.$to_n) { result.push(#{ `obj`.to_n }); } else { result.push(obj); } } return result; } end alias to_s inspect def uniq %x{ var result = [], seen = {}; for (var i = 0, length = #{self}.length, item, hash; i < length; i++) { item = #{self}[i]; hash = item; if (!seen[hash]) { seen[hash] = true; result.push(item); } } return result; } end def uniq! %x{ var original = #{self}.length, seen = {}; for (var i = 0, length = original, item, hash; i < length; i++) { item = #{self}[i]; hash = item; if (!seen[hash]) { seen[hash] = true; } else { #{self}.splice(i, 1); length--; i--; } } return #{self}.length === original ? nil : #{self}; } end def unshift(*objects) %x{ for (var i = objects.length - 1; i >= 0; i--) { #{self}.unshift(objects[i]); } return #{self}; } end def zip(*others, &block) %x{ var result = [], size = #{self}.length, part, o; for (var i = 0; i < size; i++) { part = [#{self}[i]]; for (var j = 0, jj = others.length; j < jj; j++) { o = others[j][i]; if (o == null) { o = nil; } part[j + 1] = o; } result[i] = part; } if (block !== nil) { for (var i = 0; i < size; i++) { block(result[i]); } return nil; } return result; } end end