Skip to content

Commit c31ba89

Browse files
authored
Merge pull request #732 from etiennebarrie/fragment
Introduce JSON::Fragment
2 parents f8cfa26 + 9e3500f commit c31ba89

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ You can also use the `pretty_generate` method (which formats the output more
5252
verbosely and nicely) or `fast_generate` (which doesn't do any of the security
5353
checks generate performs, e. g. nesting deepness checks).
5454

55+
## Combining JSON fragments
56+
57+
To combine JSON fragments to build a bigger JSON document, you can use `JSON::Fragment`:
58+
59+
```ruby
60+
posts_json = cache.fetch_multi(post_ids) do |post_id|
61+
JSON.generate(Post.find(post_id))
62+
end
63+
posts_json.map { |post_json| JSON::Fragment.new(post_json) }
64+
JSON.generate({ posts: posts_json, count: posts_json.count })
65+
```
66+
5567
## Handling arbitrary types
5668

5769
> [!CAUTION]

ext/json/ext/generator/generator.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ typedef struct JSON_Generator_StateStruct {
2727
#define RB_UNLIKELY(cond) (cond)
2828
#endif
2929

30-
static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
30+
static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
3131

3232
static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
3333
static ID sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
@@ -68,6 +68,7 @@ static void generate_json_integer(FBuffer *buffer, struct generate_json_data *da
6868
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
6969
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
7070
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
71+
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
7172

7273
static int usascii_encindex, utf8_encindex, binary_encindex;
7374

@@ -971,6 +972,13 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
971972
fbuffer_append_str(buffer, tmp);
972973
}
973974

975+
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
976+
{
977+
VALUE fragment = RSTRUCT_GET(obj, 0);
978+
Check_Type(fragment, T_STRING);
979+
fbuffer_append_str(buffer, fragment);
980+
}
981+
974982
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
975983
{
976984
VALUE tmp;
@@ -1010,6 +1018,10 @@ static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON
10101018
if (klass != rb_cFloat) goto general;
10111019
generate_json_float(buffer, data, state, obj);
10121020
break;
1021+
case T_STRUCT:
1022+
if (klass != cFragment) goto general;
1023+
generate_json_fragment(buffer, data, state, obj);
1024+
break;
10131025
default:
10141026
general:
10151027
if (state->strict) {
@@ -1546,6 +1558,10 @@ void Init_generator(void)
15461558
rb_require("json/common");
15471559

15481560
mJSON = rb_define_module("JSON");
1561+
1562+
rb_global_variable(&cFragment);
1563+
cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
1564+
15491565
VALUE mExt = rb_define_module_under(mJSON, "Ext");
15501566
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
15511567

lib/json/common.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ def detailed_message(...)
167167
# system. Usually this means that the iconv library is not installed.
168168
class MissingUnicodeSupport < JSONError; end
169169

170+
Fragment = Struct.new(:json) do
171+
def to_json(state = nil)
172+
json
173+
end
174+
end
175+
170176
module_function
171177

172178
# :call-seq:

test/json/json_generator_test.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,4 +661,9 @@ def test_string_ext_included_calls_super
661661
def test_nonutf8_encoding
662662
assert_equal("\"5\u{b0}\"", "5\xb0".dup.force_encoding(Encoding::ISO_8859_1).to_json)
663663
end
664+
665+
def test_fragment
666+
fragment = JSON::Fragment.new(" 42")
667+
assert_equal '{"number": 42}', JSON.generate({ number: fragment })
668+
end
664669
end

0 commit comments

Comments
 (0)