mruby-struct: add recursive inspect check instead of _inspect hack

This commit is contained in:
Yukihiro "Matz" Matsumoto
2023-06-22 12:53:51 +09:00
parent 849963b81e
commit 6ae6b63aaf
3 changed files with 46 additions and 30 deletions
-29
View File
@@ -45,35 +45,6 @@ class Struct
ary
end
def _inspect(recur_list)
return "#<struct #{self.class}:...>" if recur_list[self.object_id]
recur_list[self.object_id] = true
name = self.class.to_s
if name[0] == "#"
str = "#<struct "
else
str = "#<struct #{name} "
end
buf = []
self.each_pair do |k,v|
buf.push k.to_s + "=" + v._inspect(recur_list)
end
str + buf.join(", ") + ">"
end
##
# call-seq:
# struct.to_s -> string
# struct.inspect -> string
#
# Describe the contents of this struct in a string.
#
# 15.2.18.4.10(x)
#
def inspect
self._inspect({})
end
##
# 15.2.18.4.11(x)
#
+45
View File
@@ -634,6 +634,49 @@ mrb_struct_values_at(mrb_state *mrb, mrb_value self)
return mrb_get_values_at(mrb, self, RSTRUCT_LEN(self), argc, argv, struct_aref_int);
}
/*
* call-seq:
* struct.to_s -> string
* struct.inspect -> string
*
* Returns a string representation of Data
*/
static mrb_value
mrb_struct_to_s(mrb_state *mrb, mrb_value self)
{
mrb_value members, ret, cname;
mrb_value *mems;
mrb_int mlen;
mrb->c->ci->mid = MRB_SYM(inspect);
ret = mrb_str_new_lit(mrb, "#<struct ");
int ai = mrb_gc_arena_save(mrb);
cname = mrb_class_path(mrb, mrb_class_real(mrb_class(mrb, self)));
if (!mrb_nil_p(cname)) {
mrb_str_cat_str(mrb, ret, cname);
mrb_str_cat_lit(mrb, ret, " ");
}
if (mrb_inspect_recursive_p(mrb, self)) {
mrb_str_cat_lit(mrb, ret, "...>");
return ret;
}
members = struct_members(mrb, self);
mlen = RARRAY_LEN(members);
mems = RARRAY_PTR(members);
for (mrb_int i=0; i<mlen; i++) {
mrb_int len;
const char *name = mrb_sym_name_len(mrb, mrb_symbol(mems[i]), &len);
if (i>0) mrb_str_cat_lit(mrb, ret, ", ");
mrb_str_cat(mrb, ret, name, len);
mrb_str_cat_lit(mrb, ret, "=");
mrb_str_cat_str(mrb, ret, mrb_inspect(mrb, mrb_ary_ref(mrb, self, i)));
mrb_gc_arena_restore(mrb, ai);
}
mrb_str_cat_lit(mrb, ret, ">");
return ret;
}
/*
* A <code>Struct</code> is a convenient way to bundle a number of
* attributes together, using accessor methods, without having to write
@@ -665,6 +708,8 @@ mrb_mruby_struct_gem_init(mrb_state* mrb)
mrb_define_method(mrb, st, "initialize", mrb_struct_initialize, MRB_ARGS_ANY()); /* 15.2.18.4.8 */
mrb_define_method(mrb, st, "initialize_copy", mrb_struct_init_copy, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */
mrb_define_method(mrb, st, "eql?", mrb_struct_eql, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */
mrb_define_method(mrb, st, "to_s", mrb_struct_to_s, MRB_ARGS_NONE()); /* 15.2.18.4.11(x) */
mrb_define_method(mrb, st, "inspect", mrb_struct_to_s, MRB_ARGS_NONE()); /* 15.2.18.4.10(x) */
mrb_define_method(mrb, st, "size", mrb_struct_len, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "length", mrb_struct_len, MRB_ARGS_NONE());
+1 -1
View File
@@ -119,7 +119,7 @@ assert('struct inspect') do
c = Struct.new(:m1, :m2, :m3, :m4, :m5, :recur)
cc = c.new(1,2,3,4,5,nil)
cc.recur = cc
assert_equal "#<struct m1=1, m2=2, m3=3, m4=4, m5=5, recur=#<struct #{cc.class}:...>>", cc.inspect
assert_equal "#<struct m1=1, m2=2, m3=3, m4=4, m5=5, recur=#<struct ...>>", cc.inspect
end
assert('Struct#length, Struct#size') do