summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--build_config.rb3
-rw-r--r--mrbgems/mruby-array-ext/mrbgem.rake4
-rw-r--r--mrbgems/mruby-array-ext/src/array.c140
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb30
4 files changed, 177 insertions, 0 deletions
diff --git a/build_config.rb b/build_config.rb
index 7ca020527..4ed295c38 100644
--- a/build_config.rb
+++ b/build_config.rb
@@ -29,6 +29,9 @@ MRuby::Build.new do |conf|
# Use extensional Numeric class
conf.gem "#{root}/mrbgems/mruby-numeric-ext"
+ # Use extensional Array class
+ conf.gem "#{root}/mrbgems/mruby-array-ext"
+
# Generate binaries
# conf.bins = %w(mrbc mruby mirb)
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/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..36da6bb17
--- /dev/null
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -0,0 +1,30 @@
+##
+# 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
+