diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-09 12:27:26 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-09 12:27:26 +0000 |
commit | 29862685c0acf3a40c6b1f9e8780cbbd86cba658 (patch) | |
tree | 64813c6d3e206f9ad51009a640750f26ce9e7231 /object.c | |
parent | 50dbcf5f6d56b95fd1c240341b5b2615715b2720 (diff) |
dig
* array.c (rb_ary_dig): new method Array#dig.
* hash.c (rb_hash_dig): new method Hash#dig.
* object.c (rb_obj_dig): dig in nested arrays/hashes.
[Feature #11643]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52504 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'object.c')
-rw-r--r-- | object.c | 47 |
1 files changed, 47 insertions, 0 deletions
@@ -3144,6 +3144,52 @@ rb_f_hash(VALUE obj, VALUE arg) return rb_Hash(arg); } +struct dig_method { + VALUE klass; + int basic; +}; + +static ID id_dig; + +static int +dig_basic_p(VALUE obj, struct dig_method *cache) +{ + VALUE klass = RBASIC_CLASS(obj); + if (klass != cache->klass) { + cache->klass = klass; + cache->basic = rb_method_basic_definition_p(klass, id_dig); + } + return cache->basic; +} + +VALUE +rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound) +{ + struct dig_method hash = {Qnil}, ary = {Qnil}; + + for (; argc > 0; ++argv, --argc) { + if (!SPECIAL_CONST_P(obj)) { + switch (BUILTIN_TYPE(obj)) { + case T_HASH: + if (dig_basic_p(obj, &hash)) { + obj = rb_hash_aref(obj, *argv); + continue; + } + break; + case T_ARRAY: + if (dig_basic_p(obj, &ary)) { + obj = rb_ary_at(obj, *argv); + continue; + } + } + } + obj = rb_check_funcall(obj, id_dig, argc, argv); + if (obj == Qundef) return notfound; + break; + } + return obj; +} + /* * Document-class: Class * @@ -3521,5 +3567,6 @@ void Init_Object(void) { id_to_f = rb_intern_const("to_f"); + id_dig = rb_intern_const("dig"); InitVM(Object); } |