json 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -5
- data/CHANGES.md +33 -0
- data/README.md +16 -0
- data/Rakefile +8 -87
- data/VERSION +1 -1
- data/ext/json/ext/generator/generator.c +119 -6
- data/ext/json/ext/generator/generator.h +5 -2
- data/ext/json/ext/parser/extconf.rb +25 -0
- data/ext/json/ext/parser/parser.c +99 -71
- data/ext/json/ext/parser/parser.h +1 -0
- data/ext/json/ext/parser/parser.rl +29 -1
- data/ext/json/extconf.rb +1 -0
- data/java/src/json/ext/Generator.java +11 -30
- data/java/src/json/ext/GeneratorState.java +30 -0
- data/java/src/json/ext/Parser.java +85 -73
- data/java/src/json/ext/Parser.rl +14 -2
- data/java/src/json/ext/StringEncoder.java +8 -2
- data/json-java.gemspec +22 -21
- data/json.gemspec +0 -0
- data/json_pure.gemspec +8 -13
- data/lib/json/add/complex.rb +0 -1
- data/lib/json/add/rational.rb +0 -1
- data/lib/json/common.rb +339 -113
- data/lib/json/pure/generator.rb +29 -9
- data/lib/json/pure/parser.rb +22 -4
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +549 -29
- data/tests/json_addition_test.rb +0 -4
- data/tests/json_common_interface_test.rb +43 -0
- data/tests/json_fixtures_test.rb +9 -1
- data/tests/json_generator_test.rb +13 -2
- data/tests/json_parser_test.rb +25 -0
- data/tests/test_helper.rb +3 -3
- metadata +23 -12
@@ -10,13 +10,10 @@ import org.jruby.RubyArray;
|
|
10
10
|
import org.jruby.RubyBasicObject;
|
11
11
|
import org.jruby.RubyBignum;
|
12
12
|
import org.jruby.RubyBoolean;
|
13
|
-
import org.jruby.RubyClass;
|
14
13
|
import org.jruby.RubyFixnum;
|
15
14
|
import org.jruby.RubyFloat;
|
16
15
|
import org.jruby.RubyHash;
|
17
|
-
import org.jruby.RubyNumeric;
|
18
16
|
import org.jruby.RubyString;
|
19
|
-
import org.jruby.runtime.ClassIndex;
|
20
17
|
import org.jruby.runtime.ThreadContext;
|
21
18
|
import org.jruby.runtime.builtin.IRubyObject;
|
22
19
|
import org.jruby.util.ByteList;
|
@@ -32,8 +29,7 @@ public final class Generator {
|
|
32
29
|
static <T extends IRubyObject> RubyString
|
33
30
|
generateJson(ThreadContext context, T object,
|
34
31
|
Handler<? super T> handler, IRubyObject[] args) {
|
35
|
-
Session session = new Session(context, args.length > 0 ? args[0]
|
36
|
-
: null);
|
32
|
+
Session session = new Session(context, args.length > 0 ? args[0] : null);
|
37
33
|
return session.infect(handler.generateNew(session, object));
|
38
34
|
}
|
39
35
|
|
@@ -43,7 +39,7 @@ public final class Generator {
|
|
43
39
|
*/
|
44
40
|
static <T extends IRubyObject> RubyString
|
45
41
|
generateJson(ThreadContext context, T object, IRubyObject[] args) {
|
46
|
-
Handler<? super T> handler = getHandlerFor(context.
|
42
|
+
Handler<? super T> handler = getHandlerFor(context.runtime, object);
|
47
43
|
return generateJson(context, object, handler, args);
|
48
44
|
}
|
49
45
|
|
@@ -55,33 +51,18 @@ public final class Generator {
|
|
55
51
|
generateJson(ThreadContext context, T object,
|
56
52
|
GeneratorState config) {
|
57
53
|
Session session = new Session(context, config);
|
58
|
-
Handler<? super T> handler = getHandlerFor(context.
|
54
|
+
Handler<? super T> handler = getHandlerFor(context.runtime, object);
|
59
55
|
return handler.generateNew(session, object);
|
60
56
|
}
|
61
57
|
|
62
|
-
// NOTE: drop this once Ruby 1.9.3 support is gone!
|
63
|
-
private static final int FIXNUM = 1;
|
64
|
-
private static final int BIGNUM = 2;
|
65
|
-
private static final int ARRAY = 3;
|
66
|
-
private static final int STRING = 4;
|
67
|
-
private static final int NIL = 5;
|
68
|
-
private static final int TRUE = 6;
|
69
|
-
private static final int FALSE = 7;
|
70
|
-
private static final int HASH = 10;
|
71
|
-
private static final int FLOAT = 11;
|
72
|
-
// hard-coded due JRuby 1.7 compatibility
|
73
|
-
// https://github.com/jruby/jruby/blob/1.7.27/core/src/main/java/org/jruby/runtime/ClassIndex.java
|
74
|
-
|
75
58
|
/**
|
76
59
|
* Returns the best serialization handler for the given object.
|
77
60
|
*/
|
78
61
|
// Java's generics can't handle this satisfactorily, so I'll just leave
|
79
62
|
// the best I could get and ignore the warnings
|
80
63
|
@SuppressWarnings("unchecked")
|
81
|
-
private static <T extends IRubyObject>
|
82
|
-
|
83
|
-
switch (((RubyBasicObject) object).getNativeTypeIndex()) {
|
84
|
-
// can not use getNativeClassIndex due 1.7 compatibility
|
64
|
+
private static <T extends IRubyObject> Handler<? super T> getHandlerFor(Ruby runtime, T object) {
|
65
|
+
switch (((RubyBasicObject) object).getNativeClassIndex()) {
|
85
66
|
case NIL : return (Handler) NIL_HANDLER;
|
86
67
|
case TRUE : return (Handler) TRUE_HANDLER;
|
87
68
|
case FALSE : return (Handler) FALSE_HANDLER;
|
@@ -158,7 +139,7 @@ public final class Generator {
|
|
158
139
|
|
159
140
|
public StringEncoder getStringEncoder() {
|
160
141
|
if (stringEncoder == null) {
|
161
|
-
stringEncoder = new StringEncoder(context, getState().asciiOnly());
|
142
|
+
stringEncoder = new StringEncoder(context, getState().asciiOnly(), getState().escapeSlash());
|
162
143
|
}
|
163
144
|
return stringEncoder;
|
164
145
|
}
|
@@ -353,13 +334,13 @@ public final class Generator {
|
|
353
334
|
|
354
335
|
buffer.append((byte)'{');
|
355
336
|
buffer.append(objectNl);
|
356
|
-
object.visitAll(new RubyHash.Visitor() {
|
357
|
-
private boolean firstPair = true;
|
358
337
|
|
338
|
+
final boolean[] firstPair = new boolean[]{true};
|
339
|
+
object.visitAll(new RubyHash.Visitor() {
|
359
340
|
@Override
|
360
341
|
public void visit(IRubyObject key, IRubyObject value) {
|
361
|
-
if (firstPair) {
|
362
|
-
firstPair = false;
|
342
|
+
if (firstPair[0]) {
|
343
|
+
firstPair[0] = false;
|
363
344
|
} else {
|
364
345
|
buffer.append((byte)',');
|
365
346
|
buffer.append(objectNl);
|
@@ -379,7 +360,7 @@ public final class Generator {
|
|
379
360
|
}
|
380
361
|
});
|
381
362
|
state.decreaseDepth();
|
382
|
-
if (objectNl.length() != 0) {
|
363
|
+
if (!firstPair[0] && objectNl.length() != 0) {
|
383
364
|
buffer.append(objectNl);
|
384
365
|
buffer.append(Utils.repeat(state.getIndent(), state.getDepth()));
|
385
366
|
}
|
@@ -82,6 +82,12 @@ public class GeneratorState extends RubyObject {
|
|
82
82
|
*/
|
83
83
|
private boolean quirksMode = DEFAULT_QUIRKS_MODE;
|
84
84
|
static final boolean DEFAULT_QUIRKS_MODE = false;
|
85
|
+
/**
|
86
|
+
* If set to <code>true</code> the forward slash will be escaped in
|
87
|
+
* json output.
|
88
|
+
*/
|
89
|
+
private boolean escapeSlash = DEFAULT_ESCAPE_SLASH;
|
90
|
+
static final boolean DEFAULT_ESCAPE_SLASH = false;
|
85
91
|
/**
|
86
92
|
* The initial buffer length of this state. (This isn't really used on all
|
87
93
|
* non-C implementations.)
|
@@ -171,6 +177,9 @@ public class GeneratorState extends RubyObject {
|
|
171
177
|
* <code>-Infinity</code> should be generated, otherwise an exception is
|
172
178
|
* thrown if these values are encountered.
|
173
179
|
* This options defaults to <code>false</code>.
|
180
|
+
* <dt><code>:escape_slash</code>
|
181
|
+
* <dd>set to <code>true</code> if the forward slashes should be escaped
|
182
|
+
* in the json output (default: <code>false</code>)
|
174
183
|
*/
|
175
184
|
@JRubyMethod(optional=1, visibility=Visibility.PRIVATE)
|
176
185
|
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
@@ -194,6 +203,7 @@ public class GeneratorState extends RubyObject {
|
|
194
203
|
this.allowNaN = orig.allowNaN;
|
195
204
|
this.asciiOnly = orig.asciiOnly;
|
196
205
|
this.quirksMode = orig.quirksMode;
|
206
|
+
this.escapeSlash = orig.escapeSlash;
|
197
207
|
this.bufferInitialLength = orig.bufferInitialLength;
|
198
208
|
this.depth = orig.depth;
|
199
209
|
return this;
|
@@ -346,6 +356,24 @@ public class GeneratorState extends RubyObject {
|
|
346
356
|
return max_nesting;
|
347
357
|
}
|
348
358
|
|
359
|
+
/**
|
360
|
+
* Returns true if forward slashes are escaped in the json output.
|
361
|
+
*/
|
362
|
+
public boolean escapeSlash() {
|
363
|
+
return escapeSlash;
|
364
|
+
}
|
365
|
+
|
366
|
+
@JRubyMethod(name="escape_slash")
|
367
|
+
public RubyBoolean escape_slash_get(ThreadContext context) {
|
368
|
+
return context.getRuntime().newBoolean(escapeSlash);
|
369
|
+
}
|
370
|
+
|
371
|
+
@JRubyMethod(name="escape_slash=")
|
372
|
+
public IRubyObject escape_slash_set(IRubyObject escape_slash) {
|
373
|
+
escapeSlash = escape_slash.isTrue();
|
374
|
+
return escape_slash.getRuntime().newBoolean(escapeSlash);
|
375
|
+
}
|
376
|
+
|
349
377
|
public boolean allowNaN() {
|
350
378
|
return allowNaN;
|
351
379
|
}
|
@@ -430,6 +458,7 @@ public class GeneratorState extends RubyObject {
|
|
430
458
|
maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
|
431
459
|
allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
|
432
460
|
asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
|
461
|
+
escapeSlash = opts.getBool("escape_slash", DEFAULT_ESCAPE_SLASH);
|
433
462
|
bufferInitialLength = opts.getInt("buffer_initial_length", DEFAULT_BUFFER_INITIAL_LENGTH);
|
434
463
|
|
435
464
|
depth = opts.getInt("depth", 0);
|
@@ -457,6 +486,7 @@ public class GeneratorState extends RubyObject {
|
|
457
486
|
result.op_aset(context, runtime.newSymbol("allow_nan"), allow_nan_p(context));
|
458
487
|
result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
|
459
488
|
result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
|
489
|
+
result.op_aset(context, runtime.newSymbol("escape_slash"), escape_slash_get(context));
|
460
490
|
result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
|
461
491
|
result.op_aset(context, runtime.newSymbol("buffer_initial_length"), buffer_initial_length_get(context));
|
462
492
|
for (String name: getInstanceVariableNameList()) {
|