struct.c: dig

* object.c (rb_obj_dig): dig in nested structs too.
* struct.c (rb_struct_dig): new method Struct#dig.
  [Feature #11688]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52596 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2015-11-16 09:21:56 +00:00
parent 1ff30ea2b1
commit 20690026a7
6 changed files with 54 additions and 1 deletions

View File

@ -1,3 +1,10 @@
Mon Nov 16 18:21:52 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* object.c (rb_obj_dig): dig in nested structs too.
* struct.c (rb_struct_dig): new method Struct#dig.
[Feature #11688]
Mon Nov 16 17:41:33 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> Mon Nov 16 17:41:33 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* compile.c (iseq_peephole_optimize): optimize tail calls on aref * compile.c (iseq_peephole_optimize): optimize tail calls on aref

3
NEWS
View File

@ -95,6 +95,9 @@ with all sufficient information, see the ChangeLog file.
Backtrace doesn't show each methods (show block lines directly). Backtrace doesn't show each methods (show block lines directly).
TracePoint also ignore these calls. [Feature #11569] TracePoint also ignore these calls. [Feature #11569]
* Struct
* Struct#dig [Feature #11686]
* Thread * Thread
* Thread#name, Thread#name= are added to handle thread names [Feature #11251] * Thread#name, Thread#name= are added to handle thread names [Feature #11251]

View File

@ -1141,6 +1141,7 @@ VALUE rb_cstr_intern(const char *ptr, long len, rb_encoding *enc);
/* struct.c */ /* struct.c */
VALUE rb_struct_init_copy(VALUE copy, VALUE s); VALUE rb_struct_init_copy(VALUE copy, VALUE s);
VALUE rb_struct_lookup(VALUE s, VALUE idx);
/* time.c */ /* time.c */
struct timeval rb_time_timeval(VALUE); struct timeval rb_time_timeval(VALUE);

View File

@ -3165,7 +3165,7 @@ dig_basic_p(VALUE obj, struct dig_method *cache)
VALUE VALUE
rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound) rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
{ {
struct dig_method hash = {Qnil}, ary = {Qnil}; struct dig_method hash = {Qnil}, ary = {Qnil}, strt = {Qnil};
for (; argc > 0; ++argv, --argc) { for (; argc > 0; ++argv, --argc) {
if (!SPECIAL_CONST_P(obj)) { if (!SPECIAL_CONST_P(obj)) {
@ -3181,6 +3181,13 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
obj = rb_ary_at(obj, *argv); obj = rb_ary_at(obj, *argv);
continue; continue;
} }
break;
case T_STRUCT:
if (dig_basic_p(obj, &strt)) {
obj = rb_struct_lookup(obj, *argv);
continue;
}
break;
} }
} }
return rb_check_funcall_default(obj, id_dig, argc, argv, notfound); return rb_check_funcall_default(obj, id_dig, argc, argv, notfound);

View File

@ -923,6 +923,23 @@ rb_struct_aset(VALUE s, VALUE idx, VALUE val)
return val; return val;
} }
FUNC_MINIMIZED(VALUE rb_struct_lookup(VALUE s, VALUE idx));
NOINLINE(static VALUE rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound));
VALUE
rb_struct_lookup(VALUE s, VALUE idx)
{
return rb_struct_lookup_default(s, idx, Qnil);
}
static VALUE
rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound)
{
int i = rb_struct_pos(s, &idx);
if (i < 0) return notfound;
return RSTRUCT_GET(s, i);
}
static VALUE static VALUE
struct_entry(VALUE s, long n) struct_entry(VALUE s, long n)
{ {
@ -1109,6 +1126,16 @@ rb_struct_size(VALUE s)
return LONG2FIX(RSTRUCT_LEN(s)); return LONG2FIX(RSTRUCT_LEN(s));
} }
static VALUE
rb_struct_dig(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
self = rb_struct_lookup(self, *argv);
if (!--argc) return self;
++argv;
return rb_obj_dig(argc, argv, self, Qnil);
}
/* /*
* A Struct is a convenient way to bundle a number of attributes together, * A Struct is a convenient way to bundle a number of attributes together,
* using accessor methods, without having to write an explicit class. * using accessor methods, without having to write an explicit class.
@ -1166,6 +1193,7 @@ InitVM_Struct(void)
rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1); rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1);
rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0); rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0);
rb_define_method(rb_cStruct, "dig", rb_struct_dig, -1);
} }
#undef rb_intern #undef rb_intern

View File

@ -353,6 +353,13 @@ module TestStruct
assert_equal "[Bug #9353]", x.send(:a=, "[Bug #9353]") assert_equal "[Bug #9353]", x.send(:a=, "[Bug #9353]")
end end
def test_dig
klass = @Struct.new(:a)
o = klass.new(klass.new({b: [1, 2, 3]}))
assert_equal(1, o.dig(:a, :a, :b, 0))
assert_nil(o.dig(:b, 0))
end
class TopStruct < Test::Unit::TestCase class TopStruct < Test::Unit::TestCase
include TestStruct include TestStruct