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.
@@ -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.getRuntime(), object);
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.getRuntime(), object);
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
- Handler<? super T> getHandlerFor(Ruby runtime, T object) {
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()) {