@@ -12,6 +12,7 @@ typedef struct JSON_Generator_StateStruct {
1212 VALUE space_before ;
1313 VALUE object_nl ;
1414 VALUE array_nl ;
15+ VALUE as_json ;
1516
1617 long max_nesting ;
1718 long depth ;
@@ -30,8 +31,8 @@ typedef struct JSON_Generator_StateStruct {
3031static VALUE mJSON , cState , mString_Extend , eGeneratorError , eNestingError , Encoding_UTF_8 ;
3132
3233static ID i_to_s , i_to_json , i_new , i_pack , i_unpack , i_create_id , i_extend , i_encode ;
33- static ID sym_indent , sym_space , sym_space_before , sym_object_nl , sym_array_nl , sym_max_nesting , sym_allow_nan ,
34- sym_ascii_only , sym_depth , sym_buffer_initial_length , sym_script_safe , sym_escape_slash , sym_strict ;
34+ static VALUE sym_indent , sym_space , sym_space_before , sym_object_nl , sym_array_nl , sym_max_nesting , sym_allow_nan ,
35+ sym_ascii_only , sym_depth , sym_buffer_initial_length , sym_script_safe , sym_escape_slash , sym_strict , sym_as_json ;
3536
3637
3738#define GET_STATE_TO (self , state ) \
@@ -647,6 +648,7 @@ static void State_mark(void *ptr)
647648 rb_gc_mark_movable (state -> space_before );
648649 rb_gc_mark_movable (state -> object_nl );
649650 rb_gc_mark_movable (state -> array_nl );
651+ rb_gc_mark_movable (state -> as_json );
650652}
651653
652654static void State_compact (void * ptr )
@@ -657,6 +659,7 @@ static void State_compact(void *ptr)
657659 state -> space_before = rb_gc_location (state -> space_before );
658660 state -> object_nl = rb_gc_location (state -> object_nl );
659661 state -> array_nl = rb_gc_location (state -> array_nl );
662+ state -> as_json = rb_gc_location (state -> as_json );
660663}
661664
662665static void State_free (void * ptr )
@@ -713,6 +716,7 @@ static void vstate_spill(struct generate_json_data *data)
713716 RB_OBJ_WRITTEN (vstate , Qundef , state -> space_before );
714717 RB_OBJ_WRITTEN (vstate , Qundef , state -> object_nl );
715718 RB_OBJ_WRITTEN (vstate , Qundef , state -> array_nl );
719+ RB_OBJ_WRITTEN (vstate , Qundef , state -> as_json );
716720}
717721
718722static inline VALUE vstate_get (struct generate_json_data * data )
@@ -974,6 +978,8 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
974978static void generate_json (FBuffer * buffer , struct generate_json_data * data , JSON_Generator_State * state , VALUE obj )
975979{
976980 VALUE tmp ;
981+ bool as_json_called = false;
982+ start :
977983 if (obj == Qnil ) {
978984 generate_json_null (buffer , data , state , obj );
979985 } else if (obj == Qfalse ) {
@@ -1013,7 +1019,13 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10131019 default :
10141020 general :
10151021 if (state -> strict ) {
1016- raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1022+ if (RTEST (state -> as_json ) && !as_json_called ) {
1023+ obj = rb_proc_call_with_block (state -> as_json , 1 , & obj , Qnil );
1024+ as_json_called = true;
1025+ goto start ;
1026+ } else {
1027+ raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1028+ }
10171029 } else if (rb_respond_to (obj , i_to_json )) {
10181030 tmp = rb_funcall (obj , i_to_json , 1 , vstate_get (data ));
10191031 Check_Type (tmp , T_STRING );
@@ -1114,6 +1126,7 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
11141126 objState -> space_before = origState -> space_before ;
11151127 objState -> object_nl = origState -> object_nl ;
11161128 objState -> array_nl = origState -> array_nl ;
1129+ objState -> as_json = origState -> as_json ;
11171130 return obj ;
11181131}
11191132
@@ -1486,6 +1499,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
14861499 else if (key == sym_script_safe ) { state -> script_safe = RTEST (val ); }
14871500 else if (key == sym_escape_slash ) { state -> script_safe = RTEST (val ); }
14881501 else if (key == sym_strict ) { state -> strict = RTEST (val ); }
1502+ else if (key == sym_as_json ) { state -> as_json = rb_convert_type (val , T_DATA , "Proc" , "to_proc" ); }
14891503 return ST_CONTINUE ;
14901504}
14911505
@@ -1664,6 +1678,7 @@ void Init_generator(void)
16641678 sym_script_safe = ID2SYM (rb_intern ("script_safe" ));
16651679 sym_escape_slash = ID2SYM (rb_intern ("escape_slash" ));
16661680 sym_strict = ID2SYM (rb_intern ("strict" ));
1681+ sym_as_json = ID2SYM (rb_intern ("as_json" ));
16671682
16681683 usascii_encindex = rb_usascii_encindex ();
16691684 utf8_encindex = rb_utf8_encindex ();
0 commit comments