From 0f596851c619f92c3f467bfd0de4dd78e854b145 Mon Sep 17 00:00:00 2001 From: Yosi Attias Date: Sat, 17 Oct 2015 14:49:24 +0300 Subject: [PATCH] objspace_dump.c: dump entries of hash * ext/objspace/objspace_dump.c(dump_object): Dump entries of hash - the key & values. * test/objspace/test_objspace.rb: Adding test for the entires - test_dump_entries_empty_hash and test_dump_entries_hash --- ChangeLog | 5 ++++ ext/objspace/objspace_dump.c | 59 ++++++++++++++++++++++++++++++++++++++++++ test/objspace/test_objspace.rb | 31 ++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/ChangeLog b/ChangeLog index d9a3c59..75d4ed2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,11 @@ Sat Oct 17 13:19:10 2015 Nobuyoshi Nakada merging load_file_internal and load_file_internal2, and remove nested rb_protect and rb_ensure. +Sat Oct 17 08:47:41 2015 Yosi Attias + + * ext/objspace/objspace_dump.c(dump_object): Dump entries of hash - the key & values. + * test/objspace/test_objspace.rb: Adding test for the entires - test_dump_entries_empty_hash and test_dump_entries_hash + Sat Oct 17 05:28:32 2015 Rei Odaira * test/ruby/test_symbol.rb (test_symbol_fstr_leak): add a warm-up diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index 57d136b..21a06ed 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -125,6 +125,64 @@ obj_type(VALUE obj) return "UNKNOWN"; } +struct hash_keys_iter { + struct dump_config *dc; + int cur_i; +}; + +static void +dump_variable_value(struct dump_config *dc, VALUE value) +{ + if(!SPECIAL_CONST_P(value)) { + dump_append(dc, "\"%p\"", (void *)value); + } else { + dump_append_string_value(dc, rb_obj_as_string(rb_funcallv(value, idTo_s, 0, 0))); + } +} + + +static int +hash_entries_iter(VALUE key, VALUE value, VALUE arg) +{ + struct hash_keys_iter *keys_iter = (struct hash_keys_iter *)arg; + if(keys_iter->cur_i > 0) { + dump_append(keys_iter->dc, ","); + } + + dump_append(keys_iter->dc, "{"); + + dump_append(keys_iter->dc, "\"key\":"); + dump_variable_value(keys_iter->dc, key); + dump_append(keys_iter->dc, ","); + + dump_append(keys_iter->dc, "\"value\":"); + dump_variable_value(keys_iter->dc, value); + + dump_append(keys_iter->dc, "}"); + + keys_iter->cur_i++; + return ST_CONTINUE; +} + +static void +dump_hash_entries(struct dump_config *dc, VALUE hash) +{ + if(RHASH_SIZE(hash) == 0) { + dump_append(dc, ", \"entries\": []"); + } else { + + struct hash_keys_iter arg; + arg.dc = dc; + arg.cur_i = 0; + + + dump_append(dc, ", \"entries\": ["); + rb_hash_foreach(hash, hash_entries_iter, (VALUE)&arg); + dump_append(dc, "]"); + } +} + + static void reachable_object_i(VALUE ref, void *data) { @@ -200,6 +258,7 @@ dump_object(VALUE obj, struct dump_config *dc) case T_HASH: dump_append(dc, ", \"size\":%ld", RHASH_SIZE(obj)); + dump_hash_entries(dc, obj); if (FL_TEST(obj, HASH_PROC_DEFAULT)) dump_append(dc, ", \"default\":\"%p\"", (void *)RHASH_IFNONE(obj)); break; diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index 0ac54bf..262801f 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -1,5 +1,6 @@ require "test/unit" require "objspace" +require "json" class TestObjSpace < Test::Unit::TestCase def test_memsize_of @@ -253,6 +254,36 @@ def assert_dump_object(info, line) assert_match /"method":"#{loc.base_label}"/, info end + def test_dump_entries_empty_hash + dumped_hash = JSON.parse(ObjectSpace.dump({})) + assert_equal [], dumped_hash["entries"] + end + + def test_dump_entries_hash + # freeze the string, so we will use the same string in the hash.. + str_key = "Hello world".freeze + hash = {} + hash[:a] = 1 + hash[str_key] = -1 + + str_key_d = JSON.parse(ObjectSpace.dump(str_key)) + dumped_hash = JSON.parse(ObjectSpace.dump(hash)) + + + # make sure we have two entries + assert_equal 2, dumped_hash["entries"].length + + # check the first entry + first_entry = dumped_hash["entries"][0] + assert_equal "a", first_entry["key"] + assert_equal "1", first_entry["value"] + + # check the second entry + second_entry = dumped_hash["entries"][1] + assert_equal str_key_d["address"], second_entry["key"] + assert_equal "-1", second_entry["value"] + end + def test_dump_special_consts # [ruby-core:69692] [Bug #11291] assert_equal('{}', ObjectSpace.dump(nil))