@@ -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 ) \
@@ -674,6 +675,7 @@ static void State_mark(void *ptr)
674675 rb_gc_mark_movable (state -> space_before );
675676 rb_gc_mark_movable (state -> object_nl );
676677 rb_gc_mark_movable (state -> array_nl );
678+ rb_gc_mark_movable (state -> as_json );
677679}
678680
679681static void State_compact (void * ptr )
@@ -684,6 +686,7 @@ static void State_compact(void *ptr)
684686 state -> space_before = rb_gc_location (state -> space_before );
685687 state -> object_nl = rb_gc_location (state -> object_nl );
686688 state -> array_nl = rb_gc_location (state -> array_nl );
689+ state -> as_json = rb_gc_location (state -> as_json );
687690}
688691
689692static void State_free (void * ptr )
@@ -740,6 +743,7 @@ static void vstate_spill(struct generate_json_data *data)
740743 RB_OBJ_WRITTEN (vstate , Qundef , state -> space_before );
741744 RB_OBJ_WRITTEN (vstate , Qundef , state -> object_nl );
742745 RB_OBJ_WRITTEN (vstate , Qundef , state -> array_nl );
746+ RB_OBJ_WRITTEN (vstate , Qundef , state -> as_json );
743747}
744748
745749static inline VALUE vstate_get (struct generate_json_data * data )
@@ -1003,6 +1007,8 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
10031007static void generate_json (FBuffer * buffer , struct generate_json_data * data , JSON_Generator_State * state , VALUE obj )
10041008{
10051009 VALUE tmp ;
1010+ bool as_json_called = false;
1011+ start :
10061012 if (obj == Qnil ) {
10071013 generate_json_null (buffer , data , state , obj );
10081014 } else if (obj == Qfalse ) {
@@ -1042,7 +1048,13 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10421048 default :
10431049 general :
10441050 if (state -> strict ) {
1045- raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1051+ if (RTEST (state -> as_json ) && !as_json_called ) {
1052+ obj = rb_proc_call_with_block (state -> as_json , 1 , & obj , Qnil );
1053+ as_json_called = true;
1054+ goto start ;
1055+ } else {
1056+ raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1057+ }
10461058 } else if (rb_respond_to (obj , i_to_json )) {
10471059 tmp = rb_funcall (obj , i_to_json , 1 , vstate_get (data ));
10481060 Check_Type (tmp , T_STRING );
@@ -1132,6 +1144,7 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
11321144 objState -> space_before = origState -> space_before ;
11331145 objState -> object_nl = origState -> object_nl ;
11341146 objState -> array_nl = origState -> array_nl ;
1147+ objState -> as_json = origState -> as_json ;
11351148 return obj ;
11361149}
11371150
@@ -1504,6 +1517,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
15041517 else if (key == sym_script_safe ) { state -> script_safe = RTEST (val ); }
15051518 else if (key == sym_escape_slash ) { state -> script_safe = RTEST (val ); }
15061519 else if (key == sym_strict ) { state -> strict = RTEST (val ); }
1520+ else if (key == sym_as_json ) { state -> as_json = rb_convert_type (val , T_DATA , "Proc" , "to_proc" ); }
15071521 return ST_CONTINUE ;
15081522}
15091523
@@ -1682,6 +1696,7 @@ void Init_generator(void)
16821696 sym_script_safe = ID2SYM (rb_intern ("script_safe" ));
16831697 sym_escape_slash = ID2SYM (rb_intern ("escape_slash" ));
16841698 sym_strict = ID2SYM (rb_intern ("strict" ));
1699+ sym_as_json = ID2SYM (rb_intern ("as_json" ));
16851700
16861701 usascii_encindex = rb_usascii_encindex ();
16871702 utf8_encindex = rb_utf8_encindex ();
0 commit comments