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
@@ -1,232 +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 java.lang.ref.WeakReference;
10
- import org.jruby.Ruby;
11
- import org.jruby.RubyArray;
12
- import org.jruby.RubyBoolean;
13
- import org.jruby.RubyFixnum;
14
- import org.jruby.RubyFloat;
15
- import org.jruby.RubyHash;
16
- import org.jruby.RubyInteger;
17
- import org.jruby.RubyModule;
18
- import org.jruby.RubyNumeric;
19
- import org.jruby.RubyString;
20
- import org.jruby.anno.JRubyMethod;
21
- import org.jruby.runtime.ThreadContext;
22
- import org.jruby.runtime.builtin.IRubyObject;
23
- import org.jruby.util.ByteList;
24
-
25
- /**
26
- * A class that populates the
27
- * <code>Json::Ext::Generator::GeneratorMethods</code> module.
28
- *
29
- * @author mernen
30
- */
31
- class GeneratorMethods {
32
- /**
33
- * Populates the given module with all modules and their methods
34
- * @param info
35
- * @param generatorMethodsModule The module to populate
36
- * (normally <code>JSON::Generator::GeneratorMethods</code>)
37
- */
38
- static void populate(RuntimeInfo info, RubyModule module) {
39
- defineMethods(module, "Array", RbArray.class);
40
- defineMethods(module, "FalseClass", RbFalse.class);
41
- defineMethods(module, "Float", RbFloat.class);
42
- defineMethods(module, "Hash", RbHash.class);
43
- defineMethods(module, "Integer", RbInteger.class);
44
- defineMethods(module, "NilClass", RbNil.class);
45
- defineMethods(module, "Object", RbObject.class);
46
- defineMethods(module, "String", RbString.class);
47
- defineMethods(module, "TrueClass", RbTrue.class);
48
-
49
- info.stringExtendModule = new WeakReference<RubyModule>(module.defineModuleUnder("String")
50
- .defineModuleUnder("Extend"));
51
- info.stringExtendModule.get().defineAnnotatedMethods(StringExtend.class);
52
- }
53
-
54
- /**
55
- * Convenience method for defining methods on a submodule.
56
- * @param parentModule
57
- * @param submoduleName
58
- * @param klass
59
- */
60
- private static void defineMethods(RubyModule parentModule,
61
- String submoduleName, Class klass) {
62
- RubyModule submodule = parentModule.defineModuleUnder(submoduleName);
63
- submodule.defineAnnotatedMethods(klass);
64
- }
65
-
66
-
67
- public static class RbHash {
68
- @JRubyMethod(rest=true)
69
- public static IRubyObject to_json(ThreadContext context,
70
- IRubyObject vSelf, IRubyObject[] args) {
71
- return Generator.generateJson(context, (RubyHash)vSelf,
72
- Generator.HASH_HANDLER, args);
73
- }
74
- }
75
-
76
- public static class RbArray {
77
- @JRubyMethod(rest=true)
78
- public static IRubyObject to_json(ThreadContext context,
79
- IRubyObject vSelf, IRubyObject[] args) {
80
- return Generator.generateJson(context, (RubyArray)vSelf,
81
- Generator.ARRAY_HANDLER, args);
82
- }
83
- }
84
-
85
- public static class RbInteger {
86
- @JRubyMethod(rest=true)
87
- public static IRubyObject to_json(ThreadContext context,
88
- IRubyObject vSelf, IRubyObject[] args) {
89
- return Generator.generateJson(context, vSelf, args);
90
- }
91
- }
92
-
93
- public static class RbFloat {
94
- @JRubyMethod(rest=true)
95
- public static IRubyObject to_json(ThreadContext context,
96
- IRubyObject vSelf, IRubyObject[] args) {
97
- return Generator.generateJson(context, (RubyFloat)vSelf,
98
- Generator.FLOAT_HANDLER, args);
99
- }
100
- }
101
-
102
- public static class RbString {
103
- @JRubyMethod(rest=true)
104
- public static IRubyObject to_json(ThreadContext context,
105
- IRubyObject vSelf, IRubyObject[] args) {
106
- return Generator.generateJson(context, (RubyString)vSelf,
107
- Generator.STRING_HANDLER, args);
108
- }
109
-
110
- /**
111
- * <code>{@link RubyString String}#to_json_raw(*)</code>
112
- *
113
- * <p>This method creates a JSON text from the result of a call to
114
- * {@link #to_json_raw_object} of this String.
115
- */
116
- @JRubyMethod(rest=true)
117
- public static IRubyObject to_json_raw(ThreadContext context,
118
- IRubyObject vSelf, IRubyObject[] args) {
119
- RubyHash obj = toJsonRawObject(context, Utils.ensureString(vSelf));
120
- return Generator.generateJson(context, obj,
121
- Generator.HASH_HANDLER, args);
122
- }
123
-
124
- /**
125
- * <code>{@link RubyString String}#to_json_raw_object(*)</code>
126
- *
127
- * <p>This method creates a raw object Hash, that can be nested into
128
- * other data structures and will be unparsed as a raw string. This
129
- * method should be used if you want to convert raw strings to JSON
130
- * instead of UTF-8 strings, e.g. binary data.
131
- */
132
- @JRubyMethod(rest=true)
133
- public static IRubyObject to_json_raw_object(ThreadContext context,
134
- IRubyObject vSelf, IRubyObject[] args) {
135
- return toJsonRawObject(context, Utils.ensureString(vSelf));
136
- }
137
-
138
- private static RubyHash toJsonRawObject(ThreadContext context,
139
- RubyString self) {
140
- Ruby runtime = context.getRuntime();
141
- RubyHash result = RubyHash.newHash(runtime);
142
-
143
- IRubyObject createId = RuntimeInfo.forRuntime(runtime)
144
- .jsonModule.get().callMethod(context, "create_id");
145
- result.op_aset(context, createId, self.getMetaClass().to_s());
146
-
147
- ByteList bl = self.getByteList();
148
- byte[] uBytes = bl.unsafeBytes();
149
- RubyArray array = runtime.newArray(bl.length());
150
- for (int i = bl.begin(), t = bl.begin() + bl.length(); i < t; i++) {
151
- array.store(i, runtime.newFixnum(uBytes[i] & 0xff));
152
- }
153
-
154
- result.op_aset(context, runtime.newString("raw"), array);
155
- return result;
156
- }
157
-
158
- @JRubyMethod(required=1, module=true)
159
- public static IRubyObject included(ThreadContext context,
160
- IRubyObject vSelf, IRubyObject module) {
161
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
162
- return module.callMethod(context, "extend", info.stringExtendModule.get());
163
- }
164
- }
165
-
166
- public static class StringExtend {
167
- /**
168
- * <code>{@link RubyString String}#json_create(o)</code>
169
- *
170
- * <p>Raw Strings are JSON Objects (the raw bytes are stored in an
171
- * array for the key "raw"). The Ruby String can be created by this
172
- * module method.
173
- */
174
- @JRubyMethod(required=1)
175
- public static IRubyObject json_create(ThreadContext context,
176
- IRubyObject vSelf, IRubyObject vHash) {
177
- Ruby runtime = context.getRuntime();
178
- RubyHash o = vHash.convertToHash();
179
- IRubyObject rawData = o.fastARef(runtime.newString("raw"));
180
- if (rawData == null) {
181
- throw runtime.newArgumentError("\"raw\" value not defined "
182
- + "for encoded String");
183
- }
184
- RubyArray ary = Utils.ensureArray(rawData);
185
- byte[] bytes = new byte[ary.getLength()];
186
- for (int i = 0, t = ary.getLength(); i < t; i++) {
187
- IRubyObject element = ary.eltInternal(i);
188
- if (element instanceof RubyFixnum) {
189
- bytes[i] = (byte)RubyNumeric.fix2long(element);
190
- } else {
191
- throw runtime.newTypeError(element, runtime.getFixnum());
192
- }
193
- }
194
- return runtime.newString(new ByteList(bytes, false));
195
- }
196
- }
197
-
198
- public static class RbTrue {
199
- @JRubyMethod(rest=true)
200
- public static IRubyObject to_json(ThreadContext context,
201
- IRubyObject vSelf, IRubyObject[] args) {
202
- return Generator.generateJson(context, (RubyBoolean)vSelf,
203
- Generator.TRUE_HANDLER, args);
204
- }
205
- }
206
-
207
- public static class RbFalse {
208
- @JRubyMethod(rest=true)
209
- public static IRubyObject to_json(ThreadContext context,
210
- IRubyObject vSelf, IRubyObject[] args) {
211
- return Generator.generateJson(context, (RubyBoolean)vSelf,
212
- Generator.FALSE_HANDLER, args);
213
- }
214
- }
215
-
216
- public static class RbNil {
217
- @JRubyMethod(rest=true)
218
- public static IRubyObject to_json(ThreadContext context,
219
- IRubyObject vSelf, IRubyObject[] args) {
220
- return Generator.generateJson(context, vSelf,
221
- Generator.NIL_HANDLER, args);
222
- }
223
- }
224
-
225
- public static class RbObject {
226
- @JRubyMethod(rest=true)
227
- public static IRubyObject to_json(ThreadContext context,
228
- IRubyObject self, IRubyObject[] args) {
229
- return RbString.to_json(context, self.asString(), args);
230
- }
231
- }
232
- }
@@ -1,43 +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 java.io.IOException;
10
- import java.lang.ref.WeakReference;
11
-
12
- import org.jruby.Ruby;
13
- import org.jruby.RubyClass;
14
- import org.jruby.RubyModule;
15
- import org.jruby.runtime.load.BasicLibraryService;
16
-
17
- /**
18
- * The service invoked by JRuby's {@link org.jruby.runtime.load.LoadService LoadService}.
19
- * Defines the <code>JSON::Ext::Generator</code> module.
20
- * @author mernen
21
- */
22
- public class GeneratorService implements BasicLibraryService {
23
- public boolean basicLoad(Ruby runtime) throws IOException {
24
- runtime.getLoadService().require("json/common");
25
- RuntimeInfo info = RuntimeInfo.initRuntime(runtime);
26
-
27
- info.jsonModule = new WeakReference<RubyModule>(runtime.defineModule("JSON"));
28
- RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext");
29
- RubyModule generatorModule = jsonExtModule.defineModuleUnder("Generator");
30
-
31
- RubyClass stateClass =
32
- generatorModule.defineClassUnder("State", runtime.getObject(),
33
- GeneratorState.ALLOCATOR);
34
- stateClass.defineAnnotatedMethods(GeneratorState.class);
35
- info.generatorStateClass = new WeakReference<RubyClass>(stateClass);
36
-
37
- RubyModule generatorMethods =
38
- generatorModule.defineModuleUnder("GeneratorMethods");
39
- GeneratorMethods.populate(info, generatorMethods);
40
-
41
- return true;
42
- }
43
- }
@@ -1,543 +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.RubyBoolean;
11
- import org.jruby.RubyClass;
12
- import org.jruby.RubyHash;
13
- import org.jruby.RubyInteger;
14
- import org.jruby.RubyNumeric;
15
- import org.jruby.RubyObject;
16
- import org.jruby.RubyString;
17
- import org.jruby.anno.JRubyMethod;
18
- import org.jruby.runtime.Block;
19
- import org.jruby.runtime.ObjectAllocator;
20
- import org.jruby.runtime.ThreadContext;
21
- import org.jruby.runtime.Visibility;
22
- import org.jruby.runtime.builtin.IRubyObject;
23
- import org.jruby.util.ByteList;
24
-
25
- /**
26
- * The <code>JSON::Ext::Generator::State</code> class.
27
- *
28
- * <p>This class is used to create State instances, that are use to hold data
29
- * while generating a JSON text from a a Ruby data structure.
30
- *
31
- * @author mernen
32
- */
33
- public class GeneratorState extends RubyObject {
34
- /**
35
- * The indenting unit string. Will be repeated several times for larger
36
- * indenting levels.
37
- */
38
- private ByteList indent = ByteList.EMPTY_BYTELIST;
39
- /**
40
- * The spacing to be added after a semicolon on a JSON object.
41
- * @see #spaceBefore
42
- */
43
- private ByteList space = ByteList.EMPTY_BYTELIST;
44
- /**
45
- * The spacing to be added before a semicolon on a JSON object.
46
- * @see #space
47
- */
48
- private ByteList spaceBefore = ByteList.EMPTY_BYTELIST;
49
- /**
50
- * Any suffix to be added after the comma for each element on a JSON object.
51
- * It is assumed to be a newline, if set.
52
- */
53
- private ByteList objectNl = ByteList.EMPTY_BYTELIST;
54
- /**
55
- * Any suffix to be added after the comma for each element on a JSON Array.
56
- * It is assumed to be a newline, if set.
57
- */
58
- private ByteList arrayNl = ByteList.EMPTY_BYTELIST;
59
-
60
- /**
61
- * The maximum level of nesting of structures allowed.
62
- * <code>0</code> means disabled.
63
- */
64
- private int maxNesting = DEFAULT_MAX_NESTING;
65
- static final int DEFAULT_MAX_NESTING = 100;
66
- /**
67
- * Whether special float values (<code>NaN</code>, <code>Infinity</code>,
68
- * <code>-Infinity</code>) are accepted.
69
- * If set to <code>false</code>, an exception will be thrown upon
70
- * encountering one.
71
- */
72
- private boolean allowNaN = DEFAULT_ALLOW_NAN;
73
- static final boolean DEFAULT_ALLOW_NAN = false;
74
- /**
75
- * If set to <code>true</code> all JSON documents generated do not contain
76
- * any other characters than ASCII characters.
77
- */
78
- private boolean asciiOnly = DEFAULT_ASCII_ONLY;
79
- static final boolean DEFAULT_ASCII_ONLY = false;
80
- /**
81
- * If set to <code>true</code> all JSON values generated might not be
82
- * RFC-conform JSON documents.
83
- */
84
- private boolean quirksMode = DEFAULT_QUIRKS_MODE;
85
- static final boolean DEFAULT_QUIRKS_MODE = false;
86
- /**
87
- * The initial buffer length of this state. (This isn't really used on all
88
- * non-C implementations.)
89
- */
90
- private int bufferInitialLength = DEFAULT_BUFFER_INITIAL_LENGTH;
91
- static final int DEFAULT_BUFFER_INITIAL_LENGTH = 1024;
92
-
93
- /**
94
- * The current depth (inside a #to_json call)
95
- */
96
- private int depth = 0;
97
-
98
- static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
99
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
100
- return new GeneratorState(runtime, klazz);
101
- }
102
- };
103
-
104
- public GeneratorState(Ruby runtime, RubyClass metaClass) {
105
- super(runtime, metaClass);
106
- }
107
-
108
- /**
109
- * <code>State.from_state(opts)</code>
110
- *
111
- * <p>Creates a State object from <code>opts</code>, which ought to be
112
- * {@link RubyHash Hash} to create a new <code>State</code> instance
113
- * configured by <codes>opts</code>, something else to create an
114
- * unconfigured instance. If <code>opts</code> is a <code>State</code>
115
- * object, it is just returned.
116
- * @param clazzParam The receiver of the method call
117
- * ({@link RubyClass} <code>State</code>)
118
- * @param opts The object to use as a base for the new <code>State</code>
119
- * @param block The block passed to the method
120
- * @return A <code>GeneratorState</code> as determined above
121
- */
122
- @JRubyMethod(meta=true)
123
- public static IRubyObject from_state(ThreadContext context,
124
- IRubyObject klass, IRubyObject opts) {
125
- return fromState(context, opts);
126
- }
127
-
128
- static GeneratorState fromState(ThreadContext context, IRubyObject opts) {
129
- return fromState(context, RuntimeInfo.forRuntime(context.getRuntime()), opts);
130
- }
131
-
132
- static GeneratorState fromState(ThreadContext context, RuntimeInfo info,
133
- IRubyObject opts) {
134
- RubyClass klass = info.generatorStateClass.get();
135
- if (opts != null) {
136
- // if the given parameter is a Generator::State, return itself
137
- if (klass.isInstance(opts)) return (GeneratorState)opts;
138
-
139
- // if the given parameter is a Hash, pass it to the instantiator
140
- if (context.getRuntime().getHash().isInstance(opts)) {
141
- return (GeneratorState)klass.newInstance(context,
142
- new IRubyObject[] {opts}, Block.NULL_BLOCK);
143
- }
144
- }
145
-
146
- // for other values, return the safe prototype
147
- return (GeneratorState)info.getSafeStatePrototype(context).dup();
148
- }
149
-
150
- /**
151
- * <code>State#initialize(opts = {})</code>
152
- *
153
- * Instantiates a new <code>State</code> object, configured by <code>opts</code>.
154
- *
155
- * <code>opts</code> can have the following keys:
156
- *
157
- * <dl>
158
- * <dt><code>:indent</code>
159
- * <dd>a {@link RubyString String} used to indent levels (default: <code>""</code>)
160
- * <dt><code>:space</code>
161
- * <dd>a String that is put after a <code>':'</code> or <code>','</code>
162
- * delimiter (default: <code>""</code>)
163
- * <dt><code>:space_before</code>
164
- * <dd>a String that is put before a <code>":"</code> pair delimiter
165
- * (default: <code>""</code>)
166
- * <dt><code>:object_nl</code>
167
- * <dd>a String that is put at the end of a JSON object (default: <code>""</code>)
168
- * <dt><code>:array_nl</code>
169
- * <dd>a String that is put at the end of a JSON array (default: <code>""</code>)
170
- * <dt><code>:allow_nan</code>
171
- * <dd><code>true</code> if <code>NaN</code>, <code>Infinity</code>, and
172
- * <code>-Infinity</code> should be generated, otherwise an exception is
173
- * thrown if these values are encountered.
174
- * This options defaults to <code>false</code>.
175
- */
176
- @JRubyMethod(optional=1, visibility=Visibility.PRIVATE)
177
- public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
178
- configure(context, args.length > 0 ? args[0] : null);
179
- return this;
180
- }
181
-
182
- @JRubyMethod
183
- public IRubyObject initialize_copy(ThreadContext context, IRubyObject vOrig) {
184
- Ruby runtime = context.getRuntime();
185
- if (!(vOrig instanceof GeneratorState)) {
186
- throw runtime.newTypeError(vOrig, getType());
187
- }
188
- GeneratorState orig = (GeneratorState)vOrig;
189
- this.indent = orig.indent;
190
- this.space = orig.space;
191
- this.spaceBefore = orig.spaceBefore;
192
- this.objectNl = orig.objectNl;
193
- this.arrayNl = orig.arrayNl;
194
- this.maxNesting = orig.maxNesting;
195
- this.allowNaN = orig.allowNaN;
196
- this.asciiOnly = orig.asciiOnly;
197
- this.quirksMode = orig.quirksMode;
198
- this.bufferInitialLength = orig.bufferInitialLength;
199
- this.depth = orig.depth;
200
- return this;
201
- }
202
-
203
- /**
204
- * Generates a valid JSON document from object <code>obj</code> and returns
205
- * the result. If no valid JSON document can be created this method raises
206
- * a GeneratorError exception.
207
- */
208
- @JRubyMethod
209
- public IRubyObject generate(ThreadContext context, IRubyObject obj) {
210
- RubyString result = Generator.generateJson(context, obj, this);
211
- if (!quirksMode && !objectOrArrayLiteral(result)) {
212
- throw Utils.newException(context, Utils.M_GENERATOR_ERROR,
213
- "only generation of JSON objects or arrays allowed");
214
- }
215
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
216
- if (info.encodingsSupported()) {
217
- result.force_encoding(context, info.utf8.get());
218
- }
219
- return result;
220
- }
221
-
222
- /**
223
- * Ensures the given string is in the form "[...]" or "{...}", being
224
- * possibly surrounded by white space.
225
- * The string's encoding must be ASCII-compatible.
226
- * @param value
227
- * @return
228
- */
229
- private static boolean objectOrArrayLiteral(RubyString value) {
230
- ByteList bl = value.getByteList();
231
- int len = bl.length();
232
-
233
- for (int pos = 0; pos < len - 1; pos++) {
234
- int b = bl.get(pos);
235
- if (Character.isWhitespace(b)) continue;
236
-
237
- // match the opening brace
238
- switch (b) {
239
- case '[':
240
- return matchClosingBrace(bl, pos, len, ']');
241
- case '{':
242
- return matchClosingBrace(bl, pos, len, '}');
243
- default:
244
- return false;
245
- }
246
- }
247
- return false;
248
- }
249
-
250
- private static boolean matchClosingBrace(ByteList bl, int pos, int len,
251
- int brace) {
252
- for (int endPos = len - 1; endPos > pos; endPos--) {
253
- int b = bl.get(endPos);
254
- if (Character.isWhitespace(b)) continue;
255
- return b == brace;
256
- }
257
- return false;
258
- }
259
-
260
- @JRubyMethod(name="[]", required=1)
261
- public IRubyObject op_aref(ThreadContext context, IRubyObject vName) {
262
- String name = vName.asJavaString();
263
- if (getMetaClass().isMethodBound(name, true)) {
264
- return send(context, vName, Block.NULL_BLOCK);
265
- } else {
266
- IRubyObject value = getInstanceVariables().getInstanceVariable("@" + name);
267
- return value == null ? context.nil : value;
268
- }
269
- }
270
-
271
- @JRubyMethod(name="[]=", required=2)
272
- public IRubyObject op_aset(ThreadContext context, IRubyObject vName, IRubyObject value) {
273
- String name = vName.asJavaString();
274
- String nameWriter = name + "=";
275
- if (getMetaClass().isMethodBound(nameWriter, true)) {
276
- return send(context, context.getRuntime().newString(nameWriter), value, Block.NULL_BLOCK);
277
- } else {
278
- getInstanceVariables().setInstanceVariable("@" + name, value);
279
- }
280
- return context.getRuntime().getNil();
281
- }
282
-
283
- public ByteList getIndent() {
284
- return indent;
285
- }
286
-
287
- @JRubyMethod(name="indent")
288
- public RubyString indent_get(ThreadContext context) {
289
- return context.getRuntime().newString(indent);
290
- }
291
-
292
- @JRubyMethod(name="indent=")
293
- public IRubyObject indent_set(ThreadContext context, IRubyObject indent) {
294
- this.indent = prepareByteList(context, indent);
295
- return indent;
296
- }
297
-
298
- public ByteList getSpace() {
299
- return space;
300
- }
301
-
302
- @JRubyMethod(name="space")
303
- public RubyString space_get(ThreadContext context) {
304
- return context.getRuntime().newString(space);
305
- }
306
-
307
- @JRubyMethod(name="space=")
308
- public IRubyObject space_set(ThreadContext context, IRubyObject space) {
309
- this.space = prepareByteList(context, space);
310
- return space;
311
- }
312
-
313
- public ByteList getSpaceBefore() {
314
- return spaceBefore;
315
- }
316
-
317
- @JRubyMethod(name="space_before")
318
- public RubyString space_before_get(ThreadContext context) {
319
- return context.getRuntime().newString(spaceBefore);
320
- }
321
-
322
- @JRubyMethod(name="space_before=")
323
- public IRubyObject space_before_set(ThreadContext context,
324
- IRubyObject spaceBefore) {
325
- this.spaceBefore = prepareByteList(context, spaceBefore);
326
- return spaceBefore;
327
- }
328
-
329
- public ByteList getObjectNl() {
330
- return objectNl;
331
- }
332
-
333
- @JRubyMethod(name="object_nl")
334
- public RubyString object_nl_get(ThreadContext context) {
335
- return context.getRuntime().newString(objectNl);
336
- }
337
-
338
- @JRubyMethod(name="object_nl=")
339
- public IRubyObject object_nl_set(ThreadContext context,
340
- IRubyObject objectNl) {
341
- this.objectNl = prepareByteList(context, objectNl);
342
- return objectNl;
343
- }
344
-
345
- public ByteList getArrayNl() {
346
- return arrayNl;
347
- }
348
-
349
- @JRubyMethod(name="array_nl")
350
- public RubyString array_nl_get(ThreadContext context) {
351
- return context.getRuntime().newString(arrayNl);
352
- }
353
-
354
- @JRubyMethod(name="array_nl=")
355
- public IRubyObject array_nl_set(ThreadContext context,
356
- IRubyObject arrayNl) {
357
- this.arrayNl = prepareByteList(context, arrayNl);
358
- return arrayNl;
359
- }
360
-
361
- @JRubyMethod(name="check_circular?")
362
- public RubyBoolean check_circular_p(ThreadContext context) {
363
- return context.getRuntime().newBoolean(maxNesting != 0);
364
- }
365
-
366
- /**
367
- * Returns the maximum level of nesting configured for this state.
368
- */
369
- public int getMaxNesting() {
370
- return maxNesting;
371
- }
372
-
373
- @JRubyMethod(name="max_nesting")
374
- public RubyInteger max_nesting_get(ThreadContext context) {
375
- return context.getRuntime().newFixnum(maxNesting);
376
- }
377
-
378
- @JRubyMethod(name="max_nesting=")
379
- public IRubyObject max_nesting_set(IRubyObject max_nesting) {
380
- maxNesting = RubyNumeric.fix2int(max_nesting);
381
- return max_nesting;
382
- }
383
-
384
- public boolean allowNaN() {
385
- return allowNaN;
386
- }
387
-
388
- @JRubyMethod(name="allow_nan?")
389
- public RubyBoolean allow_nan_p(ThreadContext context) {
390
- return context.getRuntime().newBoolean(allowNaN);
391
- }
392
-
393
- public boolean asciiOnly() {
394
- return asciiOnly;
395
- }
396
-
397
- @JRubyMethod(name="ascii_only?")
398
- public RubyBoolean ascii_only_p(ThreadContext context) {
399
- return context.getRuntime().newBoolean(asciiOnly);
400
- }
401
-
402
- @JRubyMethod(name="quirks_mode")
403
- public RubyBoolean quirks_mode_get(ThreadContext context) {
404
- return context.getRuntime().newBoolean(quirksMode);
405
- }
406
-
407
- @JRubyMethod(name="quirks_mode=")
408
- public IRubyObject quirks_mode_set(IRubyObject quirks_mode) {
409
- quirksMode = quirks_mode.isTrue();
410
- return quirks_mode.getRuntime().newBoolean(quirksMode);
411
- }
412
-
413
- @JRubyMethod(name="buffer_initial_length")
414
- public RubyInteger buffer_initial_length_get(ThreadContext context) {
415
- return context.getRuntime().newFixnum(bufferInitialLength);
416
- }
417
-
418
- @JRubyMethod(name="buffer_initial_length=")
419
- public IRubyObject buffer_initial_length_set(IRubyObject buffer_initial_length) {
420
- int newLength = RubyNumeric.fix2int(buffer_initial_length);
421
- if (newLength > 0) bufferInitialLength = newLength;
422
- return buffer_initial_length;
423
- }
424
-
425
- @JRubyMethod(name="quirks_mode?")
426
- public RubyBoolean quirks_mode_p(ThreadContext context) {
427
- return context.getRuntime().newBoolean(quirksMode);
428
- }
429
-
430
- public int getDepth() {
431
- return depth;
432
- }
433
-
434
- @JRubyMethod(name="depth")
435
- public RubyInteger depth_get(ThreadContext context) {
436
- return context.getRuntime().newFixnum(depth);
437
- }
438
-
439
- @JRubyMethod(name="depth=")
440
- public IRubyObject depth_set(IRubyObject vDepth) {
441
- depth = RubyNumeric.fix2int(vDepth);
442
- return vDepth;
443
- }
444
-
445
- private ByteList prepareByteList(ThreadContext context, IRubyObject value) {
446
- RubyString str = value.convertToString();
447
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
448
- if (info.encodingsSupported() && str.encoding(context) != info.utf8.get()) {
449
- str = (RubyString)str.encode(context, info.utf8.get());
450
- }
451
- return str.getByteList().dup();
452
- }
453
-
454
- /**
455
- * <code>State#configure(opts)</code>
456
- *
457
- * <p>Configures this State instance with the {@link RubyHash Hash}
458
- * <code>opts</code>, and returns itself.
459
- * @param vOpts The options hash
460
- * @return The receiver
461
- */
462
- @JRubyMethod(alias = "merge")
463
- public IRubyObject configure(ThreadContext context, IRubyObject vOpts) {
464
- OptionsReader opts = new OptionsReader(context, vOpts);
465
-
466
- ByteList indent = opts.getString("indent");
467
- if (indent != null) this.indent = indent;
468
-
469
- ByteList space = opts.getString("space");
470
- if (space != null) this.space = space;
471
-
472
- ByteList spaceBefore = opts.getString("space_before");
473
- if (spaceBefore != null) this.spaceBefore = spaceBefore;
474
-
475
- ByteList arrayNl = opts.getString("array_nl");
476
- if (arrayNl != null) this.arrayNl = arrayNl;
477
-
478
- ByteList objectNl = opts.getString("object_nl");
479
- if (objectNl != null) this.objectNl = objectNl;
480
-
481
- maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
482
- allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
483
- asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
484
- quirksMode = opts.getBool("quirks_mode", DEFAULT_QUIRKS_MODE);
485
- bufferInitialLength = opts.getInt("buffer_initial_length", DEFAULT_BUFFER_INITIAL_LENGTH);
486
-
487
- depth = opts.getInt("depth", 0);
488
-
489
- return this;
490
- }
491
-
492
- /**
493
- * <code>State#to_h()</code>
494
- *
495
- * <p>Returns the configuration instance variables as a hash, that can be
496
- * passed to the configure method.
497
- * @return the hash
498
- */
499
- @JRubyMethod(alias = "to_hash")
500
- public RubyHash to_h(ThreadContext context) {
501
- Ruby runtime = context.getRuntime();
502
- RubyHash result = RubyHash.newHash(runtime);
503
-
504
- result.op_aset(context, runtime.newSymbol("indent"), indent_get(context));
505
- result.op_aset(context, runtime.newSymbol("space"), space_get(context));
506
- result.op_aset(context, runtime.newSymbol("space_before"), space_before_get(context));
507
- result.op_aset(context, runtime.newSymbol("object_nl"), object_nl_get(context));
508
- result.op_aset(context, runtime.newSymbol("array_nl"), array_nl_get(context));
509
- result.op_aset(context, runtime.newSymbol("allow_nan"), allow_nan_p(context));
510
- result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
511
- result.op_aset(context, runtime.newSymbol("quirks_mode"), quirks_mode_p(context));
512
- result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
513
- result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
514
- result.op_aset(context, runtime.newSymbol("buffer_initial_length"), buffer_initial_length_get(context));
515
- for (String name: getInstanceVariableNameList()) {
516
- result.op_aset(context, runtime.newSymbol(name.substring(1)), getInstanceVariables().getInstanceVariable(name));
517
- }
518
- return result;
519
- }
520
-
521
- public int increaseDepth() {
522
- depth++;
523
- checkMaxNesting();
524
- return depth;
525
- }
526
-
527
- public int decreaseDepth() {
528
- return --depth;
529
- }
530
-
531
- /**
532
- * Checks if the current depth is allowed as per this state's options.
533
- * @param context
534
- * @param depth The corrent depth
535
- */
536
- private void checkMaxNesting() {
537
- if (maxNesting != 0 && depth > maxNesting) {
538
- depth--;
539
- throw Utils.newException(getRuntime().getCurrentContext(),
540
- Utils.M_NESTING_ERROR, "nesting of " + depth + " is too deep");
541
- }
542
- }
543
- }