json 1.8.3 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +241 -90
  3. data/Gemfile +10 -6
  4. data/{COPYING-json-jruby → LICENSE} +5 -6
  5. data/{README.rdoc → README.md} +201 -134
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +264 -104
  9. data/ext/json/ext/generator/generator.h +12 -4
  10. data/ext/json/ext/parser/extconf.rb +28 -0
  11. data/ext/json/ext/parser/parser.c +425 -462
  12. data/ext/json/ext/parser/parser.h +5 -5
  13. data/ext/json/ext/parser/parser.rl +181 -181
  14. data/ext/json/extconf.rb +1 -1
  15. data/json.gemspec +0 -0
  16. data/lib/json.rb +550 -29
  17. data/lib/json/add/bigdecimal.rb +3 -2
  18. data/lib/json/add/complex.rb +4 -4
  19. data/lib/json/add/core.rb +1 -0
  20. data/lib/json/add/date.rb +1 -1
  21. data/lib/json/add/date_time.rb +1 -1
  22. data/lib/json/add/exception.rb +1 -1
  23. data/lib/json/add/ostruct.rb +3 -3
  24. data/lib/json/add/range.rb +1 -1
  25. data/lib/json/add/rational.rb +3 -3
  26. data/lib/json/add/regexp.rb +3 -3
  27. data/lib/json/add/set.rb +29 -0
  28. data/lib/json/add/struct.rb +1 -1
  29. data/lib/json/add/symbol.rb +1 -1
  30. data/lib/json/add/time.rb +1 -1
  31. data/lib/json/common.rb +381 -162
  32. data/lib/json/ext.rb +0 -6
  33. data/lib/json/generic_object.rb +5 -4
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/pure/generator.rb +83 -126
  36. data/lib/json/pure/parser.rb +62 -84
  37. data/lib/json/version.rb +2 -1
  38. data/tests/fixtures/fail29.json +1 -0
  39. data/tests/fixtures/fail30.json +1 -0
  40. data/tests/fixtures/fail31.json +1 -0
  41. data/tests/fixtures/fail32.json +1 -0
  42. data/tests/fixtures/obsolete_fail1.json +1 -0
  43. data/tests/{test_json_addition.rb → json_addition_test.rb} +28 -25
  44. data/tests/json_common_interface_test.rb +169 -0
  45. data/tests/json_encoding_test.rb +107 -0
  46. data/tests/json_ext_parser_test.rb +15 -0
  47. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +13 -8
  48. data/tests/{test_json_generate.rb → json_generator_test.rb} +109 -47
  49. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  50. data/tests/json_parser_test.rb +497 -0
  51. data/tests/json_string_matching_test.rb +38 -0
  52. data/tests/lib/core_assertions.rb +763 -0
  53. data/tests/lib/envutil.rb +365 -0
  54. data/tests/lib/find_executable.rb +22 -0
  55. data/tests/lib/helper.rb +4 -0
  56. data/tests/ractor_test.rb +30 -0
  57. data/tests/test_helper.rb +17 -0
  58. metadata +48 -76
  59. data/.gitignore +0 -16
  60. data/.travis.yml +0 -26
  61. data/COPYING +0 -58
  62. data/GPL +0 -340
  63. data/README-json-jruby.markdown +0 -33
  64. data/Rakefile +0 -412
  65. data/TODO +0 -1
  66. data/data/example.json +0 -1
  67. data/data/index.html +0 -38
  68. data/data/prototype.js +0 -4184
  69. data/diagrams/.keep +0 -0
  70. data/install.rb +0 -23
  71. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  72. data/java/src/json/ext/Generator.java +0 -444
  73. data/java/src/json/ext/GeneratorMethods.java +0 -232
  74. data/java/src/json/ext/GeneratorService.java +0 -43
  75. data/java/src/json/ext/GeneratorState.java +0 -543
  76. data/java/src/json/ext/OptionsReader.java +0 -114
  77. data/java/src/json/ext/Parser.java +0 -2645
  78. data/java/src/json/ext/Parser.rl +0 -969
  79. data/java/src/json/ext/ParserService.java +0 -35
  80. data/java/src/json/ext/RuntimeInfo.java +0 -121
  81. data/java/src/json/ext/StringDecoder.java +0 -167
  82. data/java/src/json/ext/StringEncoder.java +0 -106
  83. data/java/src/json/ext/Utils.java +0 -89
  84. data/json-java.gemspec +0 -23
  85. data/json_pure.gemspec +0 -40
  86. data/tests/fixtures/fail1.json +0 -1
  87. data/tests/setup_variant.rb +0 -11
  88. data/tests/test_json.rb +0 -553
  89. data/tests/test_json_encoding.rb +0 -65
  90. data/tests/test_json_string_matching.rb +0 -39
  91. data/tests/test_json_unicode.rb +0 -72
  92. data/tools/fuzz.rb +0 -139
  93. data/tools/server.rb +0 -62
data/diagrams/.keep DELETED
File without changes
data/install.rb DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'fileutils'
4
- include FileUtils::Verbose
5
- require 'rbconfig'
6
- include\
7
- begin
8
- RbConfig
9
- rescue NameError
10
- Config
11
- end
12
-
13
- sitelibdir = CONFIG["sitelibdir"]
14
- cd 'lib' do
15
- install('json.rb', sitelibdir)
16
- mkdir_p File.join(sitelibdir, 'json')
17
- for file in Dir['json/**/*}']
18
- d = File.join(sitelibdir, file)
19
- mkdir_p File.dirname(d)
20
- install(file, d)
21
- end
22
- end
23
- warn " *** Installed PURE ruby library."
@@ -1,167 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
6
- */
7
- package json.ext;
8
-
9
- import org.jruby.exceptions.RaiseException;
10
- import org.jruby.runtime.ThreadContext;
11
- import org.jruby.util.ByteList;
12
-
13
- /**
14
- * A class specialized in transcoding a certain String format into another,
15
- * using UTF-8 ByteLists as both input and output.
16
- */
17
- abstract class ByteListTranscoder {
18
- protected final ThreadContext context;
19
-
20
- protected ByteList src;
21
- protected int srcEnd;
22
- /** Position where the last read character started */
23
- protected int charStart;
24
- /** Position of the next character to read */
25
- protected int pos;
26
-
27
- private ByteList out;
28
- /**
29
- * When a character that can be copied straight into the output is found,
30
- * its index is stored on this variable, and copying is delayed until
31
- * the sequence of characters that can be copied ends.
32
- *
33
- * <p>The variable stores -1 when not in a plain sequence.
34
- */
35
- private int quoteStart = -1;
36
-
37
- protected ByteListTranscoder(ThreadContext context) {
38
- this.context = context;
39
- }
40
-
41
- protected void init(ByteList src, ByteList out) {
42
- this.init(src, 0, src.length(), out);
43
- }
44
-
45
- protected void init(ByteList src, int start, int end, ByteList out) {
46
- this.src = src;
47
- this.pos = start;
48
- this.charStart = start;
49
- this.srcEnd = end;
50
- this.out = out;
51
- }
52
-
53
- /**
54
- * Returns whether there are any characters left to be read.
55
- */
56
- protected boolean hasNext() {
57
- return pos < srcEnd;
58
- }
59
-
60
- /**
61
- * Returns the next character in the buffer.
62
- */
63
- private char next() {
64
- return src.charAt(pos++);
65
- }
66
-
67
- /**
68
- * Reads an UTF-8 character from the input and returns its code point,
69
- * while advancing the input position.
70
- *
71
- * <p>Raises an {@link #invalidUtf8()} exception if an invalid byte
72
- * is found.
73
- */
74
- protected int readUtf8Char() {
75
- charStart = pos;
76
- char head = next();
77
- if (head <= 0x7f) { // 0b0xxxxxxx (ASCII)
78
- return head;
79
- }
80
- if (head <= 0xbf) { // 0b10xxxxxx
81
- throw invalidUtf8(); // tail byte with no head
82
- }
83
- if (head <= 0xdf) { // 0b110xxxxx
84
- ensureMin(1);
85
- int cp = ((head & 0x1f) << 6)
86
- | nextPart();
87
- if (cp < 0x0080) throw invalidUtf8();
88
- return cp;
89
- }
90
- if (head <= 0xef) { // 0b1110xxxx
91
- ensureMin(2);
92
- int cp = ((head & 0x0f) << 12)
93
- | (nextPart() << 6)
94
- | nextPart();
95
- if (cp < 0x0800) throw invalidUtf8();
96
- return cp;
97
- }
98
- if (head <= 0xf7) { // 0b11110xxx
99
- ensureMin(3);
100
- int cp = ((head & 0x07) << 18)
101
- | (nextPart() << 12)
102
- | (nextPart() << 6)
103
- | nextPart();
104
- if (!Character.isValidCodePoint(cp)) throw invalidUtf8();
105
- return cp;
106
- }
107
- // 0b11111xxx?
108
- throw invalidUtf8();
109
- }
110
-
111
- /**
112
- * Throws a GeneratorError if the input list doesn't have at least this
113
- * many bytes left.
114
- */
115
- protected void ensureMin(int n) {
116
- if (pos + n > srcEnd) throw incompleteUtf8();
117
- }
118
-
119
- /**
120
- * Reads the next byte of a multi-byte UTF-8 character and returns its
121
- * contents (lower 6 bits).
122
- *
123
- * <p>Throws a GeneratorError if the byte is not a valid tail.
124
- */
125
- private int nextPart() {
126
- char c = next();
127
- // tail bytes must be 0b10xxxxxx
128
- if ((c & 0xc0) != 0x80) throw invalidUtf8();
129
- return c & 0x3f;
130
- }
131
-
132
-
133
- protected void quoteStart() {
134
- if (quoteStart == -1) quoteStart = charStart;
135
- }
136
-
137
- /**
138
- * When in a sequence of characters that can be copied directly,
139
- * interrupts the sequence and copies it to the output buffer.
140
- *
141
- * @param endPos The offset until which the direct character quoting should
142
- * occur. You may pass {@link #pos} to quote until the most
143
- * recently read character, or {@link #charStart} to quote
144
- * until the character before it.
145
- */
146
- protected void quoteStop(int endPos) {
147
- if (quoteStart != -1) {
148
- out.append(src, quoteStart, endPos - quoteStart);
149
- quoteStart = -1;
150
- }
151
- }
152
-
153
- protected void append(int b) {
154
- out.append(b);
155
- }
156
-
157
- protected void append(byte[] origin, int start, int length) {
158
- out.append(origin, start, length);
159
- }
160
-
161
-
162
- protected abstract RaiseException invalidUtf8();
163
-
164
- protected RaiseException incompleteUtf8() {
165
- return invalidUtf8();
166
- }
167
- }
@@ -1,444 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
6
- */
7
- package json.ext;
8
-
9
- import org.jruby.Ruby;
10
- import org.jruby.RubyArray;
11
- import org.jruby.RubyBignum;
12
- import org.jruby.RubyBoolean;
13
- import org.jruby.RubyClass;
14
- import org.jruby.RubyFixnum;
15
- import org.jruby.RubyFloat;
16
- import org.jruby.RubyHash;
17
- import org.jruby.RubyNumeric;
18
- import org.jruby.RubyString;
19
- import org.jruby.runtime.ThreadContext;
20
- import org.jruby.runtime.builtin.IRubyObject;
21
- import org.jruby.util.ByteList;
22
-
23
- public final class Generator {
24
- private Generator() {
25
- throw new RuntimeException();
26
- }
27
-
28
- /**
29
- * Encodes the given object as a JSON string, using the given handler.
30
- */
31
- static <T extends IRubyObject> RubyString
32
- generateJson(ThreadContext context, T object,
33
- Handler<? super T> handler, IRubyObject[] args) {
34
- Session session = new Session(context, args.length > 0 ? args[0]
35
- : null);
36
- return session.infect(handler.generateNew(session, object));
37
- }
38
-
39
- /**
40
- * Encodes the given object as a JSON string, detecting the appropriate handler
41
- * for the given object.
42
- */
43
- static <T extends IRubyObject> RubyString
44
- generateJson(ThreadContext context, T object, IRubyObject[] args) {
45
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
46
- return generateJson(context, object, handler, args);
47
- }
48
-
49
- /**
50
- * Encodes the given object as a JSON string, using the appropriate
51
- * handler if one is found or calling #to_json if not.
52
- */
53
- public static <T extends IRubyObject> RubyString
54
- generateJson(ThreadContext context, T object,
55
- GeneratorState config) {
56
- Session session = new Session(context, config);
57
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
58
- return handler.generateNew(session, object);
59
- }
60
-
61
- /**
62
- * Returns the best serialization handler for the given object.
63
- */
64
- // Java's generics can't handle this satisfactorily, so I'll just leave
65
- // the best I could get and ignore the warnings
66
- @SuppressWarnings("unchecked")
67
- private static <T extends IRubyObject>
68
- Handler<? super T> getHandlerFor(Ruby runtime, T object) {
69
- RubyClass metaClass = object.getMetaClass();
70
- if (metaClass == runtime.getString()) return (Handler)STRING_HANDLER;
71
- if (metaClass == runtime.getFixnum()) return (Handler)FIXNUM_HANDLER;
72
- if (metaClass == runtime.getHash()) return (Handler)HASH_HANDLER;
73
- if (metaClass == runtime.getArray()) return (Handler)ARRAY_HANDLER;
74
- if (object.isNil()) return (Handler)NIL_HANDLER;
75
- if (object == runtime.getTrue()) return (Handler)TRUE_HANDLER;
76
- if (object == runtime.getFalse()) return (Handler)FALSE_HANDLER;
77
- if (metaClass == runtime.getFloat()) return (Handler)FLOAT_HANDLER;
78
- if (metaClass == runtime.getBignum()) return (Handler)BIGNUM_HANDLER;
79
- return GENERIC_HANDLER;
80
- }
81
-
82
-
83
- /* Generator context */
84
-
85
- /**
86
- * A class that concentrates all the information that is shared by
87
- * generators working on a single session.
88
- *
89
- * <p>A session is defined as the process of serializing a single root
90
- * object; any handler directly called by container handlers (arrays and
91
- * hashes/objects) shares this object with its caller.
92
- *
93
- * <p>Note that anything called indirectly (via {@link GENERIC_HANDLER})
94
- * won't be part of the session.
95
- */
96
- static class Session {
97
- private final ThreadContext context;
98
- private GeneratorState state;
99
- private IRubyObject possibleState;
100
- private RuntimeInfo info;
101
- private StringEncoder stringEncoder;
102
-
103
- private boolean tainted = false;
104
- private boolean untrusted = false;
105
-
106
- Session(ThreadContext context, GeneratorState state) {
107
- this.context = context;
108
- this.state = state;
109
- }
110
-
111
- Session(ThreadContext context, IRubyObject possibleState) {
112
- this.context = context;
113
- this.possibleState = possibleState == null || possibleState.isNil()
114
- ? null : possibleState;
115
- }
116
-
117
- public ThreadContext getContext() {
118
- return context;
119
- }
120
-
121
- public Ruby getRuntime() {
122
- return context.getRuntime();
123
- }
124
-
125
- public GeneratorState getState() {
126
- if (state == null) {
127
- state = GeneratorState.fromState(context, getInfo(), possibleState);
128
- }
129
- return state;
130
- }
131
-
132
- public RuntimeInfo getInfo() {
133
- if (info == null) info = RuntimeInfo.forRuntime(getRuntime());
134
- return info;
135
- }
136
-
137
- public StringEncoder getStringEncoder() {
138
- if (stringEncoder == null) {
139
- stringEncoder = new StringEncoder(context, getState().asciiOnly());
140
- }
141
- return stringEncoder;
142
- }
143
-
144
- public void infectBy(IRubyObject object) {
145
- if (object.isTaint()) tainted = true;
146
- if (object.isUntrusted()) untrusted = true;
147
- }
148
-
149
- public <T extends IRubyObject> T infect(T object) {
150
- if (tainted) object.setTaint(true);
151
- if (untrusted) object.setUntrusted(true);
152
- return object;
153
- }
154
- }
155
-
156
-
157
- /* Handler base classes */
158
-
159
- private static abstract class Handler<T extends IRubyObject> {
160
- /**
161
- * Returns an estimative of how much space the serialization of the
162
- * given object will take. Used for allocating enough buffer space
163
- * before invoking other methods.
164
- */
165
- int guessSize(Session session, T object) {
166
- return 4;
167
- }
168
-
169
- RubyString generateNew(Session session, T object) {
170
- RubyString result;
171
- ByteList buffer = new ByteList(guessSize(session, object));
172
- generate(session, object, buffer);
173
- result = RubyString.newString(session.getRuntime(), buffer);
174
- ThreadContext context = session.getContext();
175
- RuntimeInfo info = session.getInfo();
176
- if (info.encodingsSupported()) {
177
- result.force_encoding(context, info.utf8.get());
178
- }
179
- return result;
180
- }
181
-
182
- abstract void generate(Session session, T object, ByteList buffer);
183
- }
184
-
185
- /**
186
- * A handler that returns a fixed keyword regardless of the passed object.
187
- */
188
- private static class KeywordHandler<T extends IRubyObject>
189
- extends Handler<T> {
190
- private final ByteList keyword;
191
-
192
- private KeywordHandler(String keyword) {
193
- this.keyword = new ByteList(ByteList.plain(keyword), false);
194
- }
195
-
196
- @Override
197
- int guessSize(Session session, T object) {
198
- return keyword.length();
199
- }
200
-
201
- @Override
202
- RubyString generateNew(Session session, T object) {
203
- return RubyString.newStringShared(session.getRuntime(), keyword);
204
- }
205
-
206
- @Override
207
- void generate(Session session, T object, ByteList buffer) {
208
- buffer.append(keyword);
209
- }
210
- }
211
-
212
-
213
- /* Handlers */
214
-
215
- static final Handler<RubyBignum> BIGNUM_HANDLER =
216
- new Handler<RubyBignum>() {
217
- @Override
218
- void generate(Session session, RubyBignum object, ByteList buffer) {
219
- // JRUBY-4751: RubyBignum.to_s() returns generic object
220
- // representation (fixed in 1.5, but we maintain backwards
221
- // compatibility; call to_s(IRubyObject[]) then
222
- buffer.append(((RubyString)object.to_s(IRubyObject.NULL_ARRAY)).getByteList());
223
- }
224
- };
225
-
226
- static final Handler<RubyFixnum> FIXNUM_HANDLER =
227
- new Handler<RubyFixnum>() {
228
- @Override
229
- void generate(Session session, RubyFixnum object, ByteList buffer) {
230
- buffer.append(object.to_s().getByteList());
231
- }
232
- };
233
-
234
- static final Handler<RubyFloat> FLOAT_HANDLER =
235
- new Handler<RubyFloat>() {
236
- @Override
237
- void generate(Session session, RubyFloat object, ByteList buffer) {
238
- double value = RubyFloat.num2dbl(object);
239
-
240
- if (Double.isInfinite(value) || Double.isNaN(value)) {
241
- if (!session.getState().allowNaN()) {
242
- throw Utils.newException(session.getContext(),
243
- Utils.M_GENERATOR_ERROR,
244
- object + " not allowed in JSON");
245
- }
246
- }
247
- buffer.append(((RubyString)object.to_s()).getByteList());
248
- }
249
- };
250
-
251
- static final Handler<RubyArray> ARRAY_HANDLER =
252
- new Handler<RubyArray>() {
253
- @Override
254
- int guessSize(Session session, RubyArray object) {
255
- GeneratorState state = session.getState();
256
- int depth = state.getDepth();
257
- int perItem =
258
- 4 // prealloc
259
- + (depth + 1) * state.getIndent().length() // indent
260
- + 1 + state.getArrayNl().length(); // ',' arrayNl
261
- return 2 + object.size() * perItem;
262
- }
263
-
264
- @Override
265
- void generate(Session session, RubyArray object, ByteList buffer) {
266
- ThreadContext context = session.getContext();
267
- Ruby runtime = context.getRuntime();
268
- GeneratorState state = session.getState();
269
- int depth = state.increaseDepth();
270
-
271
- ByteList indentUnit = state.getIndent();
272
- byte[] shift = Utils.repeat(indentUnit, depth);
273
-
274
- ByteList arrayNl = state.getArrayNl();
275
- byte[] delim = new byte[1 + arrayNl.length()];
276
- delim[0] = ',';
277
- System.arraycopy(arrayNl.unsafeBytes(), arrayNl.begin(), delim, 1,
278
- arrayNl.length());
279
-
280
- session.infectBy(object);
281
-
282
- buffer.append((byte)'[');
283
- buffer.append(arrayNl);
284
- boolean firstItem = true;
285
- for (int i = 0, t = object.getLength(); i < t; i++) {
286
- IRubyObject element = object.eltInternal(i);
287
- session.infectBy(element);
288
- if (firstItem) {
289
- firstItem = false;
290
- } else {
291
- buffer.append(delim);
292
- }
293
- buffer.append(shift);
294
- Handler<IRubyObject> handler = getHandlerFor(runtime, element);
295
- handler.generate(session, element, buffer);
296
- }
297
-
298
- state.decreaseDepth();
299
- if (arrayNl.length() != 0) {
300
- buffer.append(arrayNl);
301
- buffer.append(shift, 0, state.getDepth() * indentUnit.length());
302
- }
303
-
304
- buffer.append((byte)']');
305
- }
306
- };
307
-
308
- static final Handler<RubyHash> HASH_HANDLER =
309
- new Handler<RubyHash>() {
310
- @Override
311
- int guessSize(Session session, RubyHash object) {
312
- GeneratorState state = session.getState();
313
- int perItem =
314
- 12 // key, colon, comma
315
- + (state.getDepth() + 1) * state.getIndent().length()
316
- + state.getSpaceBefore().length()
317
- + state.getSpace().length();
318
- return 2 + object.size() * perItem;
319
- }
320
-
321
- @Override
322
- void generate(final Session session, RubyHash object,
323
- final ByteList buffer) {
324
- ThreadContext context = session.getContext();
325
- final Ruby runtime = context.getRuntime();
326
- final GeneratorState state = session.getState();
327
- final int depth = state.increaseDepth();
328
-
329
- final ByteList objectNl = state.getObjectNl();
330
- final byte[] indent = Utils.repeat(state.getIndent(), depth);
331
- final ByteList spaceBefore = state.getSpaceBefore();
332
- final ByteList space = state.getSpace();
333
-
334
- buffer.append((byte)'{');
335
- buffer.append(objectNl);
336
- object.visitAll(new RubyHash.Visitor() {
337
- private boolean firstPair = true;
338
-
339
- @Override
340
- public void visit(IRubyObject key, IRubyObject value) {
341
- if (firstPair) {
342
- firstPair = false;
343
- } else {
344
- buffer.append((byte)',');
345
- buffer.append(objectNl);
346
- }
347
- if (objectNl.length() != 0) buffer.append(indent);
348
-
349
- STRING_HANDLER.generate(session, key.asString(), buffer);
350
- session.infectBy(key);
351
-
352
- buffer.append(spaceBefore);
353
- buffer.append((byte)':');
354
- buffer.append(space);
355
-
356
- Handler<IRubyObject> valueHandler = getHandlerFor(runtime, value);
357
- valueHandler.generate(session, value, buffer);
358
- session.infectBy(value);
359
- }
360
- });
361
- state.decreaseDepth();
362
- if (objectNl.length() != 0) {
363
- buffer.append(objectNl);
364
- buffer.append(Utils.repeat(state.getIndent(), state.getDepth()));
365
- }
366
- buffer.append((byte)'}');
367
- }
368
- };
369
-
370
- static final Handler<RubyString> STRING_HANDLER =
371
- new Handler<RubyString>() {
372
- @Override
373
- int guessSize(Session session, RubyString object) {
374
- // for most applications, most strings will be just a set of
375
- // printable ASCII characters without any escaping, so let's
376
- // just allocate enough space for that + the quotes
377
- return 2 + object.getByteList().length();
378
- }
379
-
380
- @Override
381
- void generate(Session session, RubyString object, ByteList buffer) {
382
- RuntimeInfo info = session.getInfo();
383
- RubyString src;
384
-
385
- if (info.encodingsSupported() &&
386
- object.encoding(session.getContext()) != info.utf8.get()) {
387
- src = (RubyString)object.encode(session.getContext(),
388
- info.utf8.get());
389
- } else {
390
- src = object;
391
- }
392
-
393
- session.getStringEncoder().encode(src.getByteList(), buffer);
394
- }
395
- };
396
-
397
- static final Handler<RubyBoolean> TRUE_HANDLER =
398
- new KeywordHandler<RubyBoolean>("true");
399
- static final Handler<RubyBoolean> FALSE_HANDLER =
400
- new KeywordHandler<RubyBoolean>("false");
401
- static final Handler<IRubyObject> NIL_HANDLER =
402
- new KeywordHandler<IRubyObject>("null");
403
-
404
- /**
405
- * The default handler (<code>Object#to_json</code>): coerces the object
406
- * to string using <code>#to_s</code>, and serializes that string.
407
- */
408
- static final Handler<IRubyObject> OBJECT_HANDLER =
409
- new Handler<IRubyObject>() {
410
- @Override
411
- RubyString generateNew(Session session, IRubyObject object) {
412
- RubyString str = object.asString();
413
- return STRING_HANDLER.generateNew(session, str);
414
- }
415
-
416
- @Override
417
- void generate(Session session, IRubyObject object, ByteList buffer) {
418
- RubyString str = object.asString();
419
- STRING_HANDLER.generate(session, str, buffer);
420
- }
421
- };
422
-
423
- /**
424
- * A handler that simply calls <code>#to_json(state)</code> on the
425
- * given object.
426
- */
427
- static final Handler<IRubyObject> GENERIC_HANDLER =
428
- new Handler<IRubyObject>() {
429
- @Override
430
- RubyString generateNew(Session session, IRubyObject object) {
431
- IRubyObject result =
432
- object.callMethod(session.getContext(), "to_json",
433
- new IRubyObject[] {session.getState()});
434
- if (result instanceof RubyString) return (RubyString)result;
435
- throw session.getRuntime().newTypeError("to_json must return a String");
436
- }
437
-
438
- @Override
439
- void generate(Session session, IRubyObject object, ByteList buffer) {
440
- RubyString result = generateNew(session, object);
441
- buffer.append(result.getByteList());
442
- }
443
- };
444
- }