@@ -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 , cFragment , 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 ) \
@@ -648,6 +649,7 @@ static void State_mark(void *ptr)
648649 rb_gc_mark_movable (state -> space_before );
649650 rb_gc_mark_movable (state -> object_nl );
650651 rb_gc_mark_movable (state -> array_nl );
652+ rb_gc_mark_movable (state -> as_json );
651653}
652654
653655static void State_compact (void * ptr )
@@ -658,6 +660,7 @@ static void State_compact(void *ptr)
658660 state -> space_before = rb_gc_location (state -> space_before );
659661 state -> object_nl = rb_gc_location (state -> object_nl );
660662 state -> array_nl = rb_gc_location (state -> array_nl );
663+ state -> as_json = rb_gc_location (state -> as_json );
661664}
662665
663666static void State_free (void * ptr )
@@ -714,6 +717,7 @@ static void vstate_spill(struct generate_json_data *data)
714717 RB_OBJ_WRITTEN (vstate , Qundef , state -> space_before );
715718 RB_OBJ_WRITTEN (vstate , Qundef , state -> object_nl );
716719 RB_OBJ_WRITTEN (vstate , Qundef , state -> array_nl );
720+ RB_OBJ_WRITTEN (vstate , Qundef , state -> as_json );
717721}
718722
719723static inline VALUE vstate_get (struct generate_json_data * data )
@@ -982,6 +986,8 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
982986static void generate_json (FBuffer * buffer , struct generate_json_data * data , JSON_Generator_State * state , VALUE obj )
983987{
984988 VALUE tmp ;
989+ bool as_json_called = false;
990+ start :
985991 if (obj == Qnil ) {
986992 generate_json_null (buffer , data , state , obj );
987993 } else if (obj == Qfalse ) {
@@ -1025,7 +1031,13 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10251031 default :
10261032 general :
10271033 if (state -> strict ) {
1028- raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1034+ if (RTEST (state -> as_json ) && !as_json_called ) {
1035+ obj = rb_proc_call_with_block (state -> as_json , 1 , & obj , Qnil );
1036+ as_json_called = true;
1037+ goto start ;
1038+ } else {
1039+ raise_generator_error (obj , "%" PRIsVALUE " not allowed in JSON" , CLASS_OF (obj ));
1040+ }
10291041 } else if (rb_respond_to (obj , i_to_json )) {
10301042 tmp = rb_funcall (obj , i_to_json , 1 , vstate_get (data ));
10311043 Check_Type (tmp , T_STRING );
@@ -1126,6 +1138,7 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
11261138 objState -> space_before = origState -> space_before ;
11271139 objState -> object_nl = origState -> object_nl ;
11281140 objState -> array_nl = origState -> array_nl ;
1141+ objState -> as_json = origState -> as_json ;
11291142 return obj ;
11301143}
11311144
@@ -1277,6 +1290,28 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
12771290 return Qnil ;
12781291}
12791292
1293+ /*
1294+ * call-seq: as_json()
1295+ *
1296+ * This string is put at the end of a line that holds a JSON array.
1297+ */
1298+ static VALUE cState_as_json (VALUE self )
1299+ {
1300+ GET_STATE (self );
1301+ return state -> as_json ;
1302+ }
1303+
1304+ /*
1305+ * call-seq: as_json=(as_json)
1306+ *
1307+ * This string is put at the end of a line that holds a JSON array.
1308+ */
1309+ static VALUE cState_as_json_set (VALUE self , VALUE as_json )
1310+ {
1311+ GET_STATE (self );
1312+ RB_OBJ_WRITE (self , & state -> as_json , rb_convert_type (as_json , T_DATA , "Proc" , "to_proc" ));
1313+ return Qnil ;
1314+ }
12801315
12811316/*
12821317* call-seq: check_circular?
@@ -1498,6 +1533,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
14981533 else if (key == sym_script_safe ) { state -> script_safe = RTEST (val ); }
14991534 else if (key == sym_escape_slash ) { state -> script_safe = RTEST (val ); }
15001535 else if (key == sym_strict ) { state -> strict = RTEST (val ); }
1536+ else if (key == sym_as_json ) { state -> as_json = rb_convert_type (val , T_DATA , "Proc" , "to_proc" ); }
15011537 return ST_CONTINUE ;
15021538}
15031539
@@ -1589,6 +1625,8 @@ void Init_generator(void)
15891625 rb_define_method (cState , "object_nl=" , cState_object_nl_set , 1 );
15901626 rb_define_method (cState , "array_nl" , cState_array_nl , 0 );
15911627 rb_define_method (cState , "array_nl=" , cState_array_nl_set , 1 );
1628+ rb_define_method (cState , "as_json" , cState_as_json , 0 );
1629+ rb_define_method (cState , "as_json=" , cState_as_json_set , 1 );
15921630 rb_define_method (cState , "max_nesting" , cState_max_nesting , 0 );
15931631 rb_define_method (cState , "max_nesting=" , cState_max_nesting_set , 1 );
15941632 rb_define_method (cState , "script_safe" , cState_script_safe , 0 );
@@ -1610,6 +1648,7 @@ void Init_generator(void)
16101648 rb_define_method (cState , "buffer_initial_length" , cState_buffer_initial_length , 0 );
16111649 rb_define_method (cState , "buffer_initial_length=" , cState_buffer_initial_length_set , 1 );
16121650 rb_define_method (cState , "generate" , cState_generate , -1 );
1651+ rb_define_alias (cState , "generate_new" , "generate" ); // :nodoc:
16131652
16141653 rb_define_singleton_method (cState , "generate" , cState_m_generate , 3 );
16151654
@@ -1680,6 +1719,7 @@ void Init_generator(void)
16801719 sym_script_safe = ID2SYM (rb_intern ("script_safe" ));
16811720 sym_escape_slash = ID2SYM (rb_intern ("escape_slash" ));
16821721 sym_strict = ID2SYM (rb_intern ("strict" ));
1722+ sym_as_json = ID2SYM (rb_intern ("as_json" ));
16831723
16841724 usascii_encindex = rb_usascii_encindex ();
16851725 utf8_encindex = rb_utf8_encindex ();
0 commit comments