json 2.0.3 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +66 -0
  3. data/Gemfile +1 -3
  4. data/LICENSE +56 -0
  5. data/README.md +54 -21
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +229 -54
  9. data/ext/json/ext/generator/generator.h +5 -3
  10. data/ext/json/ext/parser/extconf.rb +25 -0
  11. data/ext/json/ext/parser/parser.c +180 -85
  12. data/ext/json/ext/parser/parser.h +2 -0
  13. data/ext/json/ext/parser/parser.rl +104 -9
  14. data/ext/json/extconf.rb +1 -0
  15. data/json.gemspec +0 -0
  16. data/lib/json/add/bigdecimal.rb +2 -2
  17. data/lib/json/add/complex.rb +2 -3
  18. data/lib/json/add/ostruct.rb +1 -1
  19. data/lib/json/add/rational.rb +2 -3
  20. data/lib/json/add/regexp.rb +2 -2
  21. data/lib/json/add/set.rb +29 -0
  22. data/lib/json/common.rb +372 -125
  23. data/lib/json/pure/generator.rb +31 -10
  24. data/lib/json/pure/parser.rb +35 -5
  25. data/lib/json/version.rb +1 -1
  26. data/lib/json.rb +549 -29
  27. data/tests/fixtures/fail29.json +1 -0
  28. data/tests/fixtures/fail30.json +1 -0
  29. data/tests/fixtures/fail31.json +1 -0
  30. data/tests/fixtures/fail32.json +1 -0
  31. data/tests/json_addition_test.rb +6 -0
  32. data/tests/json_common_interface_test.rb +47 -4
  33. data/tests/json_encoding_test.rb +2 -0
  34. data/tests/json_fixtures_test.rb +9 -1
  35. data/tests/json_generator_test.rb +30 -8
  36. data/tests/json_parser_test.rb +43 -12
  37. data/tests/lib/core_assertions.rb +763 -0
  38. data/tests/lib/envutil.rb +365 -0
  39. data/tests/lib/find_executable.rb +22 -0
  40. data/tests/lib/helper.rb +4 -0
  41. data/tests/ractor_test.rb +30 -0
  42. data/tests/test_helper.rb +3 -7
  43. metadata +31 -44
  44. data/.gitignore +0 -17
  45. data/.travis.yml +0 -19
  46. data/README-json-jruby.md +0 -33
  47. data/Rakefile +0 -408
  48. data/data/example.json +0 -1
  49. data/data/index.html +0 -38
  50. data/data/prototype.js +0 -4184
  51. data/diagrams/.keep +0 -0
  52. data/install.rb +0 -23
  53. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  54. data/java/src/json/ext/Generator.java +0 -443
  55. data/java/src/json/ext/GeneratorMethods.java +0 -231
  56. data/java/src/json/ext/GeneratorService.java +0 -42
  57. data/java/src/json/ext/GeneratorState.java +0 -490
  58. data/java/src/json/ext/OptionsReader.java +0 -113
  59. data/java/src/json/ext/Parser.java +0 -2347
  60. data/java/src/json/ext/Parser.rl +0 -878
  61. data/java/src/json/ext/ParserService.java +0 -34
  62. data/java/src/json/ext/RuntimeInfo.java +0 -116
  63. data/java/src/json/ext/StringDecoder.java +0 -166
  64. data/java/src/json/ext/StringEncoder.java +0 -111
  65. data/java/src/json/ext/Utils.java +0 -88
  66. data/json-java.gemspec +0 -38
  67. data/json_pure.gemspec +0 -38
  68. data/references/rfc7159.txt +0 -899
  69. data/tools/diff.sh +0 -18
  70. data/tools/fuzz.rb +0 -131
  71. data/tools/server.rb +0 -62
@@ -1,490 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.Ruby;
9
- import org.jruby.RubyBoolean;
10
- import org.jruby.RubyClass;
11
- import org.jruby.RubyHash;
12
- import org.jruby.RubyInteger;
13
- import org.jruby.RubyNumeric;
14
- import org.jruby.RubyObject;
15
- import org.jruby.RubyString;
16
- import org.jruby.anno.JRubyMethod;
17
- import org.jruby.runtime.Block;
18
- import org.jruby.runtime.ObjectAllocator;
19
- import org.jruby.runtime.ThreadContext;
20
- import org.jruby.runtime.Visibility;
21
- import org.jruby.runtime.builtin.IRubyObject;
22
- import org.jruby.util.ByteList;
23
-
24
- /**
25
- * The <code>JSON::Ext::Generator::State</code> class.
26
- *
27
- * <p>This class is used to create State instances, that are use to hold data
28
- * while generating a JSON text from a a Ruby data structure.
29
- *
30
- * @author mernen
31
- */
32
- public class GeneratorState extends RubyObject {
33
- /**
34
- * The indenting unit string. Will be repeated several times for larger
35
- * indenting levels.
36
- */
37
- private ByteList indent = ByteList.EMPTY_BYTELIST;
38
- /**
39
- * The spacing to be added after a semicolon on a JSON object.
40
- * @see #spaceBefore
41
- */
42
- private ByteList space = ByteList.EMPTY_BYTELIST;
43
- /**
44
- * The spacing to be added before a semicolon on a JSON object.
45
- * @see #space
46
- */
47
- private ByteList spaceBefore = ByteList.EMPTY_BYTELIST;
48
- /**
49
- * Any suffix to be added after the comma for each element on a JSON object.
50
- * It is assumed to be a newline, if set.
51
- */
52
- private ByteList objectNl = ByteList.EMPTY_BYTELIST;
53
- /**
54
- * Any suffix to be added after the comma for each element on a JSON Array.
55
- * It is assumed to be a newline, if set.
56
- */
57
- private ByteList arrayNl = ByteList.EMPTY_BYTELIST;
58
-
59
- /**
60
- * The maximum level of nesting of structures allowed.
61
- * <code>0</code> means disabled.
62
- */
63
- private int maxNesting = DEFAULT_MAX_NESTING;
64
- static final int DEFAULT_MAX_NESTING = 100;
65
- /**
66
- * Whether special float values (<code>NaN</code>, <code>Infinity</code>,
67
- * <code>-Infinity</code>) are accepted.
68
- * If set to <code>false</code>, an exception will be thrown upon
69
- * encountering one.
70
- */
71
- private boolean allowNaN = DEFAULT_ALLOW_NAN;
72
- static final boolean DEFAULT_ALLOW_NAN = false;
73
- /**
74
- * If set to <code>true</code> all JSON documents generated do not contain
75
- * any other characters than ASCII characters.
76
- */
77
- private boolean asciiOnly = DEFAULT_ASCII_ONLY;
78
- static final boolean DEFAULT_ASCII_ONLY = false;
79
- /**
80
- * If set to <code>true</code> all JSON values generated might not be
81
- * RFC-conform JSON documents.
82
- */
83
- private boolean quirksMode = DEFAULT_QUIRKS_MODE;
84
- static final boolean DEFAULT_QUIRKS_MODE = false;
85
- /**
86
- * The initial buffer length of this state. (This isn't really used on all
87
- * non-C implementations.)
88
- */
89
- private int bufferInitialLength = DEFAULT_BUFFER_INITIAL_LENGTH;
90
- static final int DEFAULT_BUFFER_INITIAL_LENGTH = 1024;
91
-
92
- /**
93
- * The current depth (inside a #to_json call)
94
- */
95
- private int depth = 0;
96
-
97
- static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
98
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
99
- return new GeneratorState(runtime, klazz);
100
- }
101
- };
102
-
103
- public GeneratorState(Ruby runtime, RubyClass metaClass) {
104
- super(runtime, metaClass);
105
- }
106
-
107
- /**
108
- * <code>State.from_state(opts)</code>
109
- *
110
- * <p>Creates a State object from <code>opts</code>, which ought to be
111
- * {@link RubyHash Hash} to create a new <code>State</code> instance
112
- * configured by <codes>opts</code>, something else to create an
113
- * unconfigured instance. If <code>opts</code> is a <code>State</code>
114
- * object, it is just returned.
115
- * @param clazzParam The receiver of the method call
116
- * ({@link RubyClass} <code>State</code>)
117
- * @param opts The object to use as a base for the new <code>State</code>
118
- * @param block The block passed to the method
119
- * @return A <code>GeneratorState</code> as determined above
120
- */
121
- @JRubyMethod(meta=true)
122
- public static IRubyObject from_state(ThreadContext context,
123
- IRubyObject klass, IRubyObject opts) {
124
- return fromState(context, opts);
125
- }
126
-
127
- static GeneratorState fromState(ThreadContext context, IRubyObject opts) {
128
- return fromState(context, RuntimeInfo.forRuntime(context.getRuntime()), opts);
129
- }
130
-
131
- static GeneratorState fromState(ThreadContext context, RuntimeInfo info,
132
- IRubyObject opts) {
133
- RubyClass klass = info.generatorStateClass.get();
134
- if (opts != null) {
135
- // if the given parameter is a Generator::State, return itself
136
- if (klass.isInstance(opts)) return (GeneratorState)opts;
137
-
138
- // if the given parameter is a Hash, pass it to the instantiator
139
- if (context.getRuntime().getHash().isInstance(opts)) {
140
- return (GeneratorState)klass.newInstance(context,
141
- new IRubyObject[] {opts}, Block.NULL_BLOCK);
142
- }
143
- }
144
-
145
- // for other values, return the safe prototype
146
- return (GeneratorState)info.getSafeStatePrototype(context).dup();
147
- }
148
-
149
- /**
150
- * <code>State#initialize(opts = {})</code>
151
- *
152
- * Instantiates a new <code>State</code> object, configured by <code>opts</code>.
153
- *
154
- * <code>opts</code> can have the following keys:
155
- *
156
- * <dl>
157
- * <dt><code>:indent</code>
158
- * <dd>a {@link RubyString String} used to indent levels (default: <code>""</code>)
159
- * <dt><code>:space</code>
160
- * <dd>a String that is put after a <code>':'</code> or <code>','</code>
161
- * delimiter (default: <code>""</code>)
162
- * <dt><code>:space_before</code>
163
- * <dd>a String that is put before a <code>":"</code> pair delimiter
164
- * (default: <code>""</code>)
165
- * <dt><code>:object_nl</code>
166
- * <dd>a String that is put at the end of a JSON object (default: <code>""</code>)
167
- * <dt><code>:array_nl</code>
168
- * <dd>a String that is put at the end of a JSON array (default: <code>""</code>)
169
- * <dt><code>:allow_nan</code>
170
- * <dd><code>true</code> if <code>NaN</code>, <code>Infinity</code>, and
171
- * <code>-Infinity</code> should be generated, otherwise an exception is
172
- * thrown if these values are encountered.
173
- * This options defaults to <code>false</code>.
174
- */
175
- @JRubyMethod(optional=1, visibility=Visibility.PRIVATE)
176
- public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
177
- configure(context, args.length > 0 ? args[0] : null);
178
- return this;
179
- }
180
-
181
- @JRubyMethod
182
- public IRubyObject initialize_copy(ThreadContext context, IRubyObject vOrig) {
183
- Ruby runtime = context.getRuntime();
184
- if (!(vOrig instanceof GeneratorState)) {
185
- throw runtime.newTypeError(vOrig, getType());
186
- }
187
- GeneratorState orig = (GeneratorState)vOrig;
188
- this.indent = orig.indent;
189
- this.space = orig.space;
190
- this.spaceBefore = orig.spaceBefore;
191
- this.objectNl = orig.objectNl;
192
- this.arrayNl = orig.arrayNl;
193
- this.maxNesting = orig.maxNesting;
194
- this.allowNaN = orig.allowNaN;
195
- this.asciiOnly = orig.asciiOnly;
196
- this.quirksMode = orig.quirksMode;
197
- this.bufferInitialLength = orig.bufferInitialLength;
198
- this.depth = orig.depth;
199
- return this;
200
- }
201
-
202
- /**
203
- * Generates a valid JSON document from object <code>obj</code> and returns
204
- * the result. If no valid JSON document can be created this method raises
205
- * a GeneratorError exception.
206
- */
207
- @JRubyMethod
208
- public IRubyObject generate(ThreadContext context, IRubyObject obj) {
209
- RubyString result = Generator.generateJson(context, obj, this);
210
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
211
- result.force_encoding(context, info.utf8.get());
212
- return result;
213
- }
214
-
215
- private static boolean matchClosingBrace(ByteList bl, int pos, int len,
216
- int brace) {
217
- for (int endPos = len - 1; endPos > pos; endPos--) {
218
- int b = bl.get(endPos);
219
- if (Character.isWhitespace(b)) continue;
220
- return b == brace;
221
- }
222
- return false;
223
- }
224
-
225
- @JRubyMethod(name="[]", required=1)
226
- public IRubyObject op_aref(ThreadContext context, IRubyObject vName) {
227
- String name = vName.asJavaString();
228
- if (getMetaClass().isMethodBound(name, true)) {
229
- return send(context, vName, Block.NULL_BLOCK);
230
- } else {
231
- IRubyObject value = getInstanceVariables().getInstanceVariable("@" + name);
232
- return value == null ? context.nil : value;
233
- }
234
- }
235
-
236
- @JRubyMethod(name="[]=", required=2)
237
- public IRubyObject op_aset(ThreadContext context, IRubyObject vName, IRubyObject value) {
238
- String name = vName.asJavaString();
239
- String nameWriter = name + "=";
240
- if (getMetaClass().isMethodBound(nameWriter, true)) {
241
- return send(context, context.getRuntime().newString(nameWriter), value, Block.NULL_BLOCK);
242
- } else {
243
- getInstanceVariables().setInstanceVariable("@" + name, value);
244
- }
245
- return context.getRuntime().getNil();
246
- }
247
-
248
- public ByteList getIndent() {
249
- return indent;
250
- }
251
-
252
- @JRubyMethod(name="indent")
253
- public RubyString indent_get(ThreadContext context) {
254
- return context.getRuntime().newString(indent);
255
- }
256
-
257
- @JRubyMethod(name="indent=")
258
- public IRubyObject indent_set(ThreadContext context, IRubyObject indent) {
259
- this.indent = prepareByteList(context, indent);
260
- return indent;
261
- }
262
-
263
- public ByteList getSpace() {
264
- return space;
265
- }
266
-
267
- @JRubyMethod(name="space")
268
- public RubyString space_get(ThreadContext context) {
269
- return context.getRuntime().newString(space);
270
- }
271
-
272
- @JRubyMethod(name="space=")
273
- public IRubyObject space_set(ThreadContext context, IRubyObject space) {
274
- this.space = prepareByteList(context, space);
275
- return space;
276
- }
277
-
278
- public ByteList getSpaceBefore() {
279
- return spaceBefore;
280
- }
281
-
282
- @JRubyMethod(name="space_before")
283
- public RubyString space_before_get(ThreadContext context) {
284
- return context.getRuntime().newString(spaceBefore);
285
- }
286
-
287
- @JRubyMethod(name="space_before=")
288
- public IRubyObject space_before_set(ThreadContext context,
289
- IRubyObject spaceBefore) {
290
- this.spaceBefore = prepareByteList(context, spaceBefore);
291
- return spaceBefore;
292
- }
293
-
294
- public ByteList getObjectNl() {
295
- return objectNl;
296
- }
297
-
298
- @JRubyMethod(name="object_nl")
299
- public RubyString object_nl_get(ThreadContext context) {
300
- return context.getRuntime().newString(objectNl);
301
- }
302
-
303
- @JRubyMethod(name="object_nl=")
304
- public IRubyObject object_nl_set(ThreadContext context,
305
- IRubyObject objectNl) {
306
- this.objectNl = prepareByteList(context, objectNl);
307
- return objectNl;
308
- }
309
-
310
- public ByteList getArrayNl() {
311
- return arrayNl;
312
- }
313
-
314
- @JRubyMethod(name="array_nl")
315
- public RubyString array_nl_get(ThreadContext context) {
316
- return context.getRuntime().newString(arrayNl);
317
- }
318
-
319
- @JRubyMethod(name="array_nl=")
320
- public IRubyObject array_nl_set(ThreadContext context,
321
- IRubyObject arrayNl) {
322
- this.arrayNl = prepareByteList(context, arrayNl);
323
- return arrayNl;
324
- }
325
-
326
- @JRubyMethod(name="check_circular?")
327
- public RubyBoolean check_circular_p(ThreadContext context) {
328
- return context.getRuntime().newBoolean(maxNesting != 0);
329
- }
330
-
331
- /**
332
- * Returns the maximum level of nesting configured for this state.
333
- */
334
- public int getMaxNesting() {
335
- return maxNesting;
336
- }
337
-
338
- @JRubyMethod(name="max_nesting")
339
- public RubyInteger max_nesting_get(ThreadContext context) {
340
- return context.getRuntime().newFixnum(maxNesting);
341
- }
342
-
343
- @JRubyMethod(name="max_nesting=")
344
- public IRubyObject max_nesting_set(IRubyObject max_nesting) {
345
- maxNesting = RubyNumeric.fix2int(max_nesting);
346
- return max_nesting;
347
- }
348
-
349
- public boolean allowNaN() {
350
- return allowNaN;
351
- }
352
-
353
- @JRubyMethod(name="allow_nan?")
354
- public RubyBoolean allow_nan_p(ThreadContext context) {
355
- return context.getRuntime().newBoolean(allowNaN);
356
- }
357
-
358
- public boolean asciiOnly() {
359
- return asciiOnly;
360
- }
361
-
362
- @JRubyMethod(name="ascii_only?")
363
- public RubyBoolean ascii_only_p(ThreadContext context) {
364
- return context.getRuntime().newBoolean(asciiOnly);
365
- }
366
-
367
- @JRubyMethod(name="buffer_initial_length")
368
- public RubyInteger buffer_initial_length_get(ThreadContext context) {
369
- return context.getRuntime().newFixnum(bufferInitialLength);
370
- }
371
-
372
- @JRubyMethod(name="buffer_initial_length=")
373
- public IRubyObject buffer_initial_length_set(IRubyObject buffer_initial_length) {
374
- int newLength = RubyNumeric.fix2int(buffer_initial_length);
375
- if (newLength > 0) bufferInitialLength = newLength;
376
- return buffer_initial_length;
377
- }
378
-
379
- public int getDepth() {
380
- return depth;
381
- }
382
-
383
- @JRubyMethod(name="depth")
384
- public RubyInteger depth_get(ThreadContext context) {
385
- return context.getRuntime().newFixnum(depth);
386
- }
387
-
388
- @JRubyMethod(name="depth=")
389
- public IRubyObject depth_set(IRubyObject vDepth) {
390
- depth = RubyNumeric.fix2int(vDepth);
391
- return vDepth;
392
- }
393
-
394
- private ByteList prepareByteList(ThreadContext context, IRubyObject value) {
395
- RubyString str = value.convertToString();
396
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
397
- if (str.encoding(context) != info.utf8.get()) {
398
- str = (RubyString)str.encode(context, info.utf8.get());
399
- }
400
- return str.getByteList().dup();
401
- }
402
-
403
- /**
404
- * <code>State#configure(opts)</code>
405
- *
406
- * <p>Configures this State instance with the {@link RubyHash Hash}
407
- * <code>opts</code>, and returns itself.
408
- * @param vOpts The options hash
409
- * @return The receiver
410
- */
411
- @JRubyMethod(alias = "merge")
412
- public IRubyObject configure(ThreadContext context, IRubyObject vOpts) {
413
- OptionsReader opts = new OptionsReader(context, vOpts);
414
-
415
- ByteList indent = opts.getString("indent");
416
- if (indent != null) this.indent = indent;
417
-
418
- ByteList space = opts.getString("space");
419
- if (space != null) this.space = space;
420
-
421
- ByteList spaceBefore = opts.getString("space_before");
422
- if (spaceBefore != null) this.spaceBefore = spaceBefore;
423
-
424
- ByteList arrayNl = opts.getString("array_nl");
425
- if (arrayNl != null) this.arrayNl = arrayNl;
426
-
427
- ByteList objectNl = opts.getString("object_nl");
428
- if (objectNl != null) this.objectNl = objectNl;
429
-
430
- maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
431
- allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
432
- asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
433
- bufferInitialLength = opts.getInt("buffer_initial_length", DEFAULT_BUFFER_INITIAL_LENGTH);
434
-
435
- depth = opts.getInt("depth", 0);
436
-
437
- return this;
438
- }
439
-
440
- /**
441
- * <code>State#to_h()</code>
442
- *
443
- * <p>Returns the configuration instance variables as a hash, that can be
444
- * passed to the configure method.
445
- * @return the hash
446
- */
447
- @JRubyMethod(alias = "to_hash")
448
- public RubyHash to_h(ThreadContext context) {
449
- Ruby runtime = context.getRuntime();
450
- RubyHash result = RubyHash.newHash(runtime);
451
-
452
- result.op_aset(context, runtime.newSymbol("indent"), indent_get(context));
453
- result.op_aset(context, runtime.newSymbol("space"), space_get(context));
454
- result.op_aset(context, runtime.newSymbol("space_before"), space_before_get(context));
455
- result.op_aset(context, runtime.newSymbol("object_nl"), object_nl_get(context));
456
- result.op_aset(context, runtime.newSymbol("array_nl"), array_nl_get(context));
457
- result.op_aset(context, runtime.newSymbol("allow_nan"), allow_nan_p(context));
458
- result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
459
- result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
460
- result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
461
- result.op_aset(context, runtime.newSymbol("buffer_initial_length"), buffer_initial_length_get(context));
462
- for (String name: getInstanceVariableNameList()) {
463
- result.op_aset(context, runtime.newSymbol(name.substring(1)), getInstanceVariables().getInstanceVariable(name));
464
- }
465
- return result;
466
- }
467
-
468
- public int increaseDepth() {
469
- depth++;
470
- checkMaxNesting();
471
- return depth;
472
- }
473
-
474
- public int decreaseDepth() {
475
- return --depth;
476
- }
477
-
478
- /**
479
- * Checks if the current depth is allowed as per this state's options.
480
- * @param context
481
- * @param depth The corrent depth
482
- */
483
- private void checkMaxNesting() {
484
- if (maxNesting != 0 && depth > maxNesting) {
485
- depth--;
486
- throw Utils.newException(getRuntime().getCurrentContext(),
487
- Utils.M_NESTING_ERROR, "nesting of " + depth + " is too deep");
488
- }
489
- }
490
- }
@@ -1,113 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.Ruby;
9
- import org.jruby.RubyClass;
10
- import org.jruby.RubyHash;
11
- import org.jruby.RubyNumeric;
12
- import org.jruby.RubyString;
13
- import org.jruby.runtime.ThreadContext;
14
- import org.jruby.runtime.builtin.IRubyObject;
15
- import org.jruby.util.ByteList;
16
-
17
- final class OptionsReader {
18
- private final ThreadContext context;
19
- private final Ruby runtime;
20
- private final RubyHash opts;
21
- private RuntimeInfo info;
22
-
23
- OptionsReader(ThreadContext context, IRubyObject vOpts) {
24
- this.context = context;
25
- this.runtime = context.getRuntime();
26
- if (vOpts == null || vOpts.isNil()) {
27
- opts = null;
28
- } else if (vOpts.respondsTo("to_hash")) {
29
- opts = vOpts.convertToHash();
30
- } else if (vOpts.respondsTo("to_h")) {
31
- opts = vOpts.callMethod(context, "to_h").convertToHash();
32
- } else {
33
- opts = vOpts.convertToHash(); /* Should just raise the correct TypeError */
34
- }
35
- }
36
-
37
- private RuntimeInfo getRuntimeInfo() {
38
- if (info != null) return info;
39
- info = RuntimeInfo.forRuntime(runtime);
40
- return info;
41
- }
42
-
43
- /**
44
- * Efficiently looks up items with a {@link RubySymbol Symbol} key
45
- * @param key The Symbol name to look up for
46
- * @return The item in the {@link RubyHash Hash}, or <code>null</code>
47
- * if not found
48
- */
49
- IRubyObject get(String key) {
50
- return opts == null ? null : opts.fastARef(runtime.newSymbol(key));
51
- }
52
-
53
- boolean getBool(String key, boolean defaultValue) {
54
- IRubyObject value = get(key);
55
- return value == null ? defaultValue : value.isTrue();
56
- }
57
-
58
- int getInt(String key, int defaultValue) {
59
- IRubyObject value = get(key);
60
- if (value == null) return defaultValue;
61
- if (!value.isTrue()) return 0;
62
- return RubyNumeric.fix2int(value);
63
- }
64
-
65
- /**
66
- * Reads the setting from the options hash. If no entry is set for this
67
- * key or if it evaluates to <code>false</code>, returns null; attempts to
68
- * coerce the value to {@link RubyString String} otherwise.
69
- * @param key The Symbol name to look up for
70
- * @return <code>null</code> if the key is not in the Hash or if
71
- * its value evaluates to <code>false</code>
72
- * @throws RaiseException <code>TypeError</code> if the value does not
73
- * evaluate to <code>false</code> and can't be
74
- * converted to string
75
- */
76
- ByteList getString(String key) {
77
- RubyString str = getString(key, null);
78
- return str == null ? null : str.getByteList().dup();
79
- }
80
-
81
- RubyString getString(String key, RubyString defaultValue) {
82
- IRubyObject value = get(key);
83
- if (value == null || !value.isTrue()) return defaultValue;
84
-
85
- RubyString str = value.convertToString();
86
- RuntimeInfo info = getRuntimeInfo();
87
- if (str.encoding(context) != info.utf8.get()) {
88
- str = (RubyString)str.encode(context, info.utf8.get());
89
- }
90
- return str;
91
- }
92
-
93
- /**
94
- * Reads the setting from the options hash. If it is <code>nil</code> or
95
- * undefined, returns the default value given.
96
- * If not, ensures it is a RubyClass instance and shares the same
97
- * allocator as the default value (i.e. for the basic types which have
98
- * their specific allocators, this ensures the passed value is
99
- * a subclass of them).
100
- */
101
- RubyClass getClass(String key, RubyClass defaultValue) {
102
- IRubyObject value = get(key);
103
-
104
- if (value == null || value.isNil()) return defaultValue;
105
- return (RubyClass)value;
106
- }
107
-
108
- public RubyHash getHash(String key) {
109
- IRubyObject value = get(key);
110
- if (value == null || value.isNil()) return new RubyHash(runtime);
111
- return (RubyHash) value;
112
- }
113
- }