[#70257] [Ruby trunk - Feature #11420] [Open] Introduce ID key table into MRI — ko1@...

Issue #11420 has been reported by Koichi Sasada.

11 messages 2015/08/06

[ruby-core:70295] Behavior of sprintf with dynamic hashes, possible improvement?

From: William Woodruff <william@...>
Date: 2015-08-10 03:51:10 UTC
List: ruby-core #70295
Hello all,

I came across this behavior while trying to use a dynamic hash to
populate a string via `sprintf`. While normal formatting works:

     "%{a}" % { a: "value" } # => "value"

Dynamic hashes do not:

     "%{a}" % Hash.new { |hash, key| hash[key] = "value" } # => KeyError

Ox0dea on #ruby helped me trace this down to trunk/sprintf.c#611:

     if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef);

and trunk/hash.c#795:

    return def; /* without Hash#default */

It seems like using `rb_hash_aref` instead of `rb_hash_lookup2` in
sprintf.c would solve this problem. To prevent the string from being
populated with empty strings when `rb_hash_aref` returns nil as the
default value, this could be guarded with a check like this:

     if (sym != Qnil) nextvalue = rb_hash_aref(hash, sym);
     if (nextvalue == Qnil) {
         nextvalue = rb_hash_lookup2(hash, sym, Qundef);
         if (nextvalue == Qundef) {
             rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, 
start);
         }
     }

I've tried this (patch attached) on a local build, but I'm running into
an ArgumentError that I'm having trouble tracing down:

     "%{a}" % Hash.new { |hash, key| hash[key] = "value\" }"

produces "unnumbered(1) mixed with named (ArgumentError)"

I'm still in the process of tracing that down.

Does anybody have any thoughts on this? Is formatting with dynamic
hashes something that could be included/supported in the future, or
am I pushing the principle too far in this case?

--
William Woodruff
william@tuffbizz.com

Attachments (1)

sprintf.diff (735 Bytes, text/x-diff)
diff --git a/sprintf.c b/sprintf.c
index 4549791..3aeb00e 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -608,9 +608,12 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
 		sym = rb_check_symbol_cstr(start + 1,
 					   len - 2 /* without parenthesis */,
 					   enc);
-		if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
-		if (nextvalue == Qundef) {
-		    rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start);
+		if (sym != Qnil) nextvalue = rb_hash_aref(hash, sym);
+		if (nextvalue == Qnil) {
+			nextvalue = rb_hash_lookup2(hash, sym, Qundef);
+			if (nextvalue == Qundef) {
+				rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start);
+			}
 		}
 		if (term == '}') goto format_s;
 		p++;

In This Thread

Prev Next