diff options
| author | Jean Boussier <jean.boussier@gmail.com> | 2025-08-23 16:58:54 +0200 |
|---|---|---|
| committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2025-08-27 10:01:52 +0900 |
| commit | 0e0f0dfd070fc156ec74c58f44d86a884a0580e0 (patch) | |
| tree | 35fd9b889a7759ab8e87bdd9ba1ee64400dd528d | |
| parent | c3a80ca58226f588ef393ab5ae1de304eabf9a9d (diff) | |
Fix `JSON::Coder` to cast non-string keys.
| -rw-r--r-- | ext/json/generator/generator.c | 11 | ||||
| -rwxr-xr-x | test/json/json_coder_test.rb | 12 |
2 files changed, 22 insertions, 1 deletions
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index c71e2f28a7..52dcd24f0e 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -1026,6 +1026,9 @@ json_object_i(VALUE key, VALUE val, VALUE _arg) } VALUE key_to_s; + bool as_json_called = false; + + start: switch (rb_type(key)) { case T_STRING: if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) { @@ -1039,7 +1042,13 @@ json_object_i(VALUE key, VALUE val, VALUE _arg) break; default: if (data->state->strict) { - raise_generator_error(key, "%"PRIsVALUE" not allowed in JSON", rb_funcall(key, i_to_s, 0)); + if (RTEST(data->state->as_json) && !as_json_called) { + key = rb_proc_call_with_block(data->state->as_json, 1, &key, Qnil); + as_json_called = true; + goto start; + } else { + raise_generator_error(key, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(key)); + } } key_to_s = rb_convert_type(key, T_STRING, "String", "to_s"); break; diff --git a/test/json/json_coder_test.rb b/test/json/json_coder_test.rb index 9861181910..fc4aba2968 100755 --- a/test/json/json_coder_test.rb +++ b/test/json/json_coder_test.rb @@ -18,6 +18,18 @@ class JSONCoderTest < Test::Unit::TestCase assert_raise(JSON::GeneratorError) { coder.dump([Object.new]) } end + def test_json_coder_hash_key + obj = Object.new + coder = JSON::Coder.new(&:to_s) + assert_equal %({#{obj.to_s.inspect}:1}), coder.dump({ obj => 1 }) + + coder = JSON::Coder.new { 42 } + error = assert_raise JSON::GeneratorError do + coder.dump({ obj => 1 }) + end + assert_equal "Integer not allowed as object key in JSON", error.message + end + def test_json_coder_options coder = JSON::Coder.new(array_nl: "\n") do |object| 42 |
