Skip to content

Commit 1042a0b

Browse files
byroothsbt
authored andcommitted
JSON::Coder callback now recieve a second argument to mark object keys
e.g. ```ruby { 1 => 2 } ``` The callback will be invoked for `1` as while it has a native JSON equivalent, it's not legal as an object name.
1 parent dc406e9 commit 1042a0b

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

ext/json/generator/generator.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef struct JSON_Generator_StateStruct {
2929

3030
enum duplicate_key_action on_duplicate_key;
3131

32+
bool as_json_single_arg;
3233
bool allow_nan;
3334
bool ascii_only;
3435
bool script_safe;
@@ -1033,6 +1034,13 @@ json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
10331034
}
10341035
}
10351036

1037+
static VALUE
1038+
json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
1039+
{
1040+
VALUE proc_args[2] = {object, is_key};
1041+
return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
1042+
}
1043+
10361044
static int
10371045
json_object_i(VALUE key, VALUE val, VALUE _arg)
10381046
{
@@ -1086,7 +1094,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
10861094
default:
10871095
if (data->state->strict) {
10881096
if (RTEST(data->state->as_json) && !as_json_called) {
1089-
key = rb_proc_call_with_block(data->state->as_json, 1, &key, Qnil);
1097+
key = json_call_as_json(data->state, key, Qtrue);
10901098
key_type = rb_type(key);
10911099
as_json_called = true;
10921100
goto start;
@@ -1328,7 +1336,7 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
13281336
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
13291337
if (!allow_nan) {
13301338
if (data->state->strict && data->state->as_json) {
1331-
VALUE casted_obj = rb_proc_call_with_block(data->state->as_json, 1, &obj, Qnil);
1339+
VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
13321340
if (casted_obj != obj) {
13331341
increase_depth(data);
13341342
generate_json(buffer, data, casted_obj);
@@ -1416,7 +1424,7 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALU
14161424
general:
14171425
if (data->state->strict) {
14181426
if (RTEST(data->state->as_json) && !as_json_called) {
1419-
obj = rb_proc_call_with_block(data->state->as_json, 1, &obj, Qnil);
1427+
obj = json_call_as_json(data->state, obj, Qfalse);
14201428
as_json_called = true;
14211429
goto start;
14221430
} else {
@@ -1942,6 +1950,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
19421950
else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
19431951
else if (key == sym_as_json) {
19441952
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
1953+
state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
19451954
state_write_value(data, &state->as_json, proc);
19461955
}
19471956
return ST_CONTINUE;

test/json/json_coder_test.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ def test_json_coder_with_proc
1212
end
1313

1414
def test_json_coder_with_proc_with_unsupported_value
15-
coder = JSON::Coder.new do |object|
15+
coder = JSON::Coder.new do |object, is_key|
16+
assert_equal false, is_key
1617
Object.new
1718
end
1819
assert_raise(JSON::GeneratorError) { coder.dump([Object.new]) }
1920
end
2021

2122
def test_json_coder_hash_key
2223
obj = Object.new
23-
coder = JSON::Coder.new(&:to_s)
24+
coder = JSON::Coder.new do |obj, is_key|
25+
assert_equal true, is_key
26+
obj.to_s
27+
end
2428
assert_equal %({#{obj.to_s.inspect}:1}), coder.dump({ obj => 1 })
2529

2630
coder = JSON::Coder.new { 42 }
@@ -49,14 +53,14 @@ def test_json_coder_load_options
4953
end
5054

5155
def test_json_coder_dump_NaN_or_Infinity
52-
coder = JSON::Coder.new(&:inspect)
56+
coder = JSON::Coder.new { |o| o.inspect }
5357
assert_equal "NaN", coder.load(coder.dump(Float::NAN))
5458
assert_equal "Infinity", coder.load(coder.dump(Float::INFINITY))
5559
assert_equal "-Infinity", coder.load(coder.dump(-Float::INFINITY))
5660
end
5761

5862
def test_json_coder_dump_NaN_or_Infinity_loop
59-
coder = JSON::Coder.new(&:itself)
63+
coder = JSON::Coder.new { |o| o.itself }
6064
error = assert_raise JSON::GeneratorError do
6165
coder.dump(Float::NAN)
6266
end

test/json/json_generator_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ def test_fragment
822822

823823
def test_json_generate_as_json_convert_to_proc
824824
object = Object.new
825-
assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: :object_id)
825+
assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: -> (o, is_key) { o.object_id })
826826
end
827827

828828
def assert_float_roundtrip(expected, actual)

0 commit comments

Comments
 (0)