summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-array-ext
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-array-ext')
-rw-r--r--mrbgems/mruby-array-ext/mrbgem.rake4
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb98
-rw-r--r--mrbgems/mruby-array-ext/src/array.c140
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb109
4 files changed, 351 insertions, 0 deletions
diff --git a/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake
new file mode 100644
index 000000000..38e0ad267
--- /dev/null
+++ b/mrbgems/mruby-array-ext/mrbgem.rake
@@ -0,0 +1,4 @@
+MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
+ spec.license = 'MIT'
+ spec.authors = 'mruby developers'
+end
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
new file mode 100644
index 000000000..b3ff9bfca
--- /dev/null
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -0,0 +1,98 @@
+class Array
+ def uniq!
+ ary = self.dup
+ result = []
+ while ary.size > 0
+ result << ary.shift
+ ary.delete(result.last)
+ end
+ if result.size == self.size
+ nil
+ else
+ self.replace(result)
+ end
+ end
+
+ def uniq
+ ary = self.dup
+ ary.uniq!
+ ary
+ end
+
+ def -(elem)
+ raise TypeError, "can't convert to Array" unless elem.class == Array
+
+ hash = {}
+ array = []
+ elem.each { |x| hash[x] = true }
+ self.each { |x| array << x unless hash[x] }
+ array
+ end
+
+ def |(elem)
+ raise TypeError, "can't convert to Array" unless elem.class == Array
+
+ ary = self + elem
+ ary.uniq! or ary
+ end
+
+ def &(elem)
+ raise TypeError, "can't convert to Array" unless elem.class == Array
+
+ hash = {}
+ array = []
+ elem.each{|v| hash[v] = true }
+ self.each do |v|
+ if hash[v]
+ array << v
+ hash.delete v
+ end
+ end
+ array
+ end
+
+ def flatten(depth=nil)
+ ar = []
+ self.each do |e|
+ if e.is_a?(Array) && (depth.nil? || depth > 0)
+ ar += e.flatten(depth.nil? ? nil : depth - 1)
+ else
+ ar << e
+ end
+ end
+ ar
+ end
+
+ def flatten!(depth=nil)
+ modified = false
+ ar = []
+ self.each do |e|
+ if e.is_a?(Array) && (depth.nil? || depth > 0)
+ ar += e.flatten(depth.nil? ? nil : depth - 1)
+ modified = true
+ else
+ ar << e
+ end
+ end
+ if modified
+ self.replace(ar)
+ else
+ nil
+ end
+ end
+
+ def compact
+ result = self.dup
+ result.compact!
+ result
+ end
+
+ def compact!
+ result = self.select { |e| e != nil }
+ if result.size == self.size
+ nil
+ else
+ self.replace(result)
+ end
+ end
+end
diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
new file mode 100644
index 000000000..7d7425efd
--- /dev/null
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -0,0 +1,140 @@
+#include "mruby.h"
+#include "mruby/value.h"
+#include "mruby/array.h"
+
+/*
+ * call-seq:
+ * Array.try_convert(obj) -> array or nil
+ *
+ * Try to convert <i>obj</i> into an array, using +to_ary+ method.
+ * Returns converted array or +nil+ if <i>obj</i> cannot be converted
+ * for any reason. This method can be used to check if an argument is an
+ * array.
+ *
+ * Array.try_convert([1]) #=> [1]
+ * Array.try_convert("1") #=> nil
+ *
+ * if tmp = Array.try_convert(arg)
+ * # the argument is an array
+ * elsif tmp = String.try_convert(arg)
+ * # the argument is a string
+ * end
+ *
+ */
+
+static mrb_value
+mrb_ary_s_try_convert(mrb_state *mrb, mrb_value self)
+{
+ mrb_value ary;
+
+ mrb_get_args(mrb, "o", &ary);
+ return mrb_check_array_type(mrb, ary);
+}
+
+/*
+ * call-seq:
+ * ary.assoc(obj) -> new_ary or nil
+ *
+ * Searches through an array whose elements are also arrays
+ * comparing _obj_ with the first element of each contained array
+ * using obj.==.
+ * Returns the first contained array that matches (that
+ * is, the first associated array),
+ * or +nil+ if no match is found.
+ * See also <code>Array#rassoc</code>.
+ *
+ * s1 = [ "colors", "red", "blue", "green" ]
+ * s2 = [ "letters", "a", "b", "c" ]
+ * s3 = "foo"
+ * a = [ s1, s2, s3 ]
+ * a.assoc("letters") #=> [ "letters", "a", "b", "c" ]
+ * a.assoc("foo") #=> nil
+ */
+
+static mrb_value
+mrb_ary_assoc(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int i;
+ mrb_value v, k;
+
+ mrb_get_args(mrb, "o", &k);
+
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
+ v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
+ if (!mrb_nil_p(v) && RARRAY_LEN(v) > 0 &&
+ mrb_equal(mrb, RARRAY_PTR(v)[0], k))
+ return v;
+ }
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * ary.rassoc(obj) -> new_ary or nil
+ *
+ * Searches through the array whose elements are also arrays. Compares
+ * _obj_ with the second element of each contained array using
+ * <code>==</code>. Returns the first contained array that matches. See
+ * also <code>Array#assoc</code>.
+ *
+ * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
+ * a.rassoc("two") #=> [2, "two"]
+ * a.rassoc("four") #=> nil
+ */
+
+static mrb_value
+mrb_ary_rassoc(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int i;
+ mrb_value v, value;
+
+ mrb_get_args(mrb, "o", &value);
+
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
+ v = RARRAY_PTR(ary)[i];
+ if (mrb_type(v) == MRB_TT_ARRAY &&
+ RARRAY_LEN(v) > 1 &&
+ mrb_equal(mrb, RARRAY_PTR(v)[1], value))
+ return v;
+ }
+ return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ * ary.at(index) -> obj or nil
+ *
+ * Returns the element at _index_. A
+ * negative index counts from the end of +self+. Returns +nil+
+ * if the index is out of range. See also <code>Array#[]</code>.
+ *
+ * a = [ "a", "b", "c", "d", "e" ]
+ * a.at(0) #=> "a"
+ * a.at(-1) #=> "e"
+ */
+
+static mrb_value
+mrb_ary_at(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int pos;
+ mrb_get_args(mrb, "i", &pos);
+
+ return mrb_ary_entry(ary, pos);
+}
+
+void
+mrb_mruby_array_ext_gem_init(mrb_state* mrb)
+{
+ struct RClass * a = mrb->array_class;
+
+ mrb_define_class_method(mrb, a, "try_convert", mrb_ary_s_try_convert, ARGS_REQ(1));
+
+ mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, ARGS_REQ(1));
+ mrb_define_method(mrb, a, "at", mrb_ary_at, ARGS_REQ(1));
+ mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, ARGS_REQ(1));
+}
+
+void
+mrb_mruby_array_ext_gem_final(mrb_state* mrb)
+{
+}
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
new file mode 100644
index 000000000..1c441cec4
--- /dev/null
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -0,0 +1,109 @@
+##
+# Array(Ext) Test
+
+assert("Array::try_convert") do
+ Array.try_convert([1]) == [1] and
+ Array.try_convert("1").nil?
+end
+
+assert("Array#assoc") do
+ s1 = [ "colors", "red", "blue", "green" ]
+ s2 = [ "letters", "a", "b", "c" ]
+ s3 = "foo"
+ a = [ s1, s2, s3 ]
+
+ a.assoc("letters") == [ "letters", "a", "b", "c" ] and
+ a.assoc("foo").nil?
+end
+
+assert("Array#at") do
+ a = [ "a", "b", "c", "d", "e" ]
+ a.at(0) == "a" and a.at(-1) == "e"
+end
+
+assert("Array#rassoc") do
+ a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
+
+ a.rassoc("two") == [2, "two"] and
+ a.rassoc("four").nil?
+end
+
+assert("Array#uniq!") do
+ a = [1, 2, 3, 1]
+ a.uniq!
+ a == [1, 2, 3]
+end
+
+assert("Array#uniq") do
+ a = [1, 2, 3, 1]
+ a.uniq == [1, 2, 3] && a == [1, 2, 3, 1]
+end
+
+assert("Array#-") do
+ a = [1, 2, 3, 1]
+ b = [1]
+ c = 1
+ e1 = nil
+
+ begin
+ a - c
+ rescue => e1
+ end
+
+ (a - b) == [2, 3] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#|") do
+ a = [1, 2, 3, 1]
+ b = [1, 4]
+ c = 1
+ e1 = nil
+
+ begin
+ a | c
+ rescue => e1
+ end
+
+ (a | b) == [1, 2, 3, 4] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#&") do
+ a = [1, 2, 3, 1]
+ b = [1, 4]
+ c = 1
+ e1 = nil
+
+ begin
+ a & c
+ rescue => e1
+ end
+
+ (a & b) == [1] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#flatten") do
+ [1, 2, "3", {4=>5}, :'6'] == [1, 2, "3", {4=>5}, :'6'].flatten and
+ [1, 2, 3, 4, 5, 6] == [1, 2, [3, 4, 5], 6].flatten and
+ [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten and
+ [1, [2, [3, [4, [5, [6]]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(0) and
+ [1, 2, [3, [4, [5, [6]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(1) and
+ [1, 2, 3, [4, [5, [6]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(2) and
+ [1, 2, 3, 4, [5, [6]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(3) and
+ [1, 2, 3, 4, 5, [6]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(4) and
+ [1, 2, 3, 4, 5, 6] == [1, [2, [3, [4, [5, [6]]]]]].flatten(5)
+end
+
+assert("Array#flatten!") do
+ [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten!
+end
+
+assert("Array#compact") do
+ a = [1, nil, "2", nil, :t, false, nil]
+ a.compact == [1, "2", :t, false] && a == [1, nil, "2", nil, :t, false, nil]
+end
+
+assert("Array#compact!") do
+ a = [1, nil, "2", nil, :t, false, nil]
+ a.compact!
+ a == [1, "2", :t, false]
+end