#include "mruby.h"
#include "mruby/value.h"
#include "mruby/array.h"
#include "mruby/range.h"
#include "mruby/hash.h"
/*
* 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 Array#rassoc
.
*
* 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
* ==
. Returns the first contained array that matches. See
* also Array#assoc
.
*
* 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 Array#[]
.
*
* 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);
}
static mrb_value
mrb_ary_values_at(mrb_state *mrb, mrb_value self)
{
mrb_int argc;
mrb_value *argv;
mrb_get_args(mrb, "*", &argv, &argc);
return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref);
}
/*
* call-seq:
* ary.to_h -> Hash
*
* Returns the result of interpreting aray as an array of
* [key, value] paris.
*
* [[:foo, :bar], [1, 2]].to_h
* # => {:foo => :bar, 1 => 2}
*
*/
static mrb_value
mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
{
mrb_int i;
mrb_value v, hash;
hash = mrb_hash_new_capa(mrb, 0);
for (i = 0; i < RARRAY_LEN(ary); ++i) {
v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
if (mrb_nil_p(v)) {
mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])),
mrb_fixnum_value(i)
);
}
if (RARRAY_LEN(v) != 2) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
mrb_fixnum_value(i),
mrb_fixnum_value(RARRAY_LEN(v))
);
}
mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
}
return hash;
}
void
mrb_mruby_array_ext_gem_init(mrb_state* mrb)
{
struct RClass * a = mrb->array_class;
mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0));
}
void
mrb_mruby_array_ext_gem_final(mrb_state* mrb)
{
}