json 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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()) {
|