json_pure 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGES +9 -0
  2. data/Rakefile +47 -53
  3. data/VERSION +1 -1
  4. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  5. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  6. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  7. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  8. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  9. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  10. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  11. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  12. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  13. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  14. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  15. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  16. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  17. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  18. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  19. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  20. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  21. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  22. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  23. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  24. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  25. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  26. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  27. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  28. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  29. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  30. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  31. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  32. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  33. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  34. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  35. data/benchmarks/generator_benchmark.rb +162 -0
  36. data/benchmarks/parser_benchmark.rb +193 -0
  37. data/bin/edit_json.rb +0 -1
  38. data/bin/prettify_json.rb +0 -1
  39. data/doc-templates/main.txt +284 -0
  40. data/ext/json/ext/generator/extconf.rb +2 -0
  41. data/ext/json/ext/generator/generator.c +62 -18
  42. data/ext/json/ext/parser/extconf.rb +2 -0
  43. data/ext/json/ext/parser/parser.c +128 -81
  44. data/ext/json/ext/parser/parser.rl +31 -7
  45. data/ext/json/ext/parser/unicode.c +4 -4
  46. data/lib/json/add/core.rb +1 -1
  47. data/lib/json/editor.rb +11 -2
  48. data/lib/json/ext.rb +2 -0
  49. data/lib/json/pure/generator.rb +77 -41
  50. data/lib/json/pure/parser.rb +6 -2
  51. data/lib/json/pure.rb +2 -0
  52. data/lib/json/version.rb +1 -1
  53. data/lib/json.rb +0 -221
  54. data/tests/test_json.rb +7 -4
  55. data/tests/test_json_addition.rb +8 -5
  56. data/tests/test_json_fixtures.rb +6 -2
  57. data/tests/test_json_generate.rb +8 -2
  58. data/tests/test_json_rails.rb +30 -2
  59. data/tests/test_json_unicode.rb +8 -7
  60. data/tools/fuzz.rb +0 -1
  61. data/tools/server.rb +0 -1
  62. metadata +46 -9
  63. data/benchmarks/benchmark.txt +0 -133
  64. data/benchmarks/benchmark_generator.rb +0 -48
  65. data/benchmarks/benchmark_parser.rb +0 -26
  66. data/benchmarks/benchmark_rails.rb +0 -26
  67. data/tests/runner.rb +0 -25
@@ -1,10 +1,28 @@
1
1
  #include "ruby.h"
2
+ #include "unicode.h"
3
+ #if HAVE_RE_H
2
4
  #include "re.h"
5
+ #endif
6
+ #if HAVE_RUBY_ST_H
7
+ #include "ruby/st.h"
8
+ #endif
9
+ #if HAVE_ST_H
3
10
  #include "st.h"
4
- #include "unicode.h"
11
+ #endif
5
12
 
6
13
  #define EVIL 0x666
7
14
 
15
+ #ifndef RHASH_TBL
16
+ #define RHASH_TBL(hsh) (RHASH(hsh)->tbl)
17
+ #endif
18
+
19
+ #ifdef HAVE_RUBY_ENCODING_H
20
+ #include "ruby/encoding.h"
21
+ #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
22
+ #else
23
+ #define FORCE_UTF8(obj)
24
+ #endif
25
+
8
26
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
9
27
  static VALUE CNaN, CInfinity, CMinusInfinity;
10
28
 
@@ -392,8 +410,14 @@ static VALUE json_string_unescape(char *p, char *pe)
392
410
 
393
411
  action parse_string {
394
412
  *result = json_string_unescape(json->memo + 1, p);
395
- if (NIL_P(*result)) { fhold; fbreak; } else fexec p + 1;
396
- }
413
+ if (NIL_P(*result)) {
414
+ fhold;
415
+ fbreak;
416
+ } else {
417
+ FORCE_UTF8(*result);
418
+ fexec p + 1;
419
+ }
420
+ }
397
421
 
398
422
  action exit { fhold; fbreak; }
399
423
 
@@ -496,7 +520,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
496
520
  rb_raise(rb_eArgError, "opts needs to be like a hash");
497
521
  } else {
498
522
  VALUE tmp = ID2SYM(i_max_nesting);
499
- if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
523
+ if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
500
524
  VALUE max_nesting = rb_hash_aref(opts, tmp);
501
525
  if (RTEST(max_nesting)) {
502
526
  Check_Type(max_nesting, T_FIXNUM);
@@ -508,14 +532,14 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
508
532
  json->max_nesting = 19;
509
533
  }
510
534
  tmp = ID2SYM(i_allow_nan);
511
- if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
535
+ if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
512
536
  VALUE allow_nan = rb_hash_aref(opts, tmp);
513
537
  json->allow_nan = RTEST(allow_nan) ? 1 : 0;
514
538
  } else {
515
539
  json->allow_nan = 0;
516
540
  }
517
541
  tmp = ID2SYM(i_create_additions);
518
- if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
542
+ if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
519
543
  VALUE create_additions = rb_hash_aref(opts, tmp);
520
544
  if (RTEST(create_additions)) {
521
545
  json->create_id = rb_funcall(mJSON, i_create_id, 0);
@@ -590,7 +614,7 @@ static void JSON_mark(JSON_Parser *json)
590
614
 
591
615
  static void JSON_free(JSON_Parser *json)
592
616
  {
593
- free(json);
617
+ ruby_xfree(json);
594
618
  }
595
619
 
596
620
  static VALUE cJSON_parser_s_allocate(VALUE klass)
@@ -103,12 +103,12 @@ char *JSON_convert_UTF16_to_UTF8 (
103
103
  + (ch2 - UNI_SUR_LOW_START) + halfBase;
104
104
  ++tmpPtr;
105
105
  } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
106
- free(tmp);
106
+ ruby_xfree(tmp);
107
107
  rb_raise(rb_path2class("JSON::ParserError"),
108
108
  "source sequence is illegal/malformed near %s", source);
109
109
  }
110
110
  } else { /* We don't have the 16 bits following the high surrogate. */
111
- free(tmp);
111
+ ruby_xfree(tmp);
112
112
  rb_raise(rb_path2class("JSON::ParserError"),
113
113
  "partial character in source, but hit end near %s", source);
114
114
  break;
@@ -116,7 +116,7 @@ char *JSON_convert_UTF16_to_UTF8 (
116
116
  } else if (flags == strictConversion) {
117
117
  /* UTF-16 surrogate values are illegal in UTF-32 */
118
118
  if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
119
- free(tmp);
119
+ ruby_xfree(tmp);
120
120
  rb_raise(rb_path2class("JSON::ParserError"),
121
121
  "source sequence is illegal/malformed near %s", source);
122
122
  }
@@ -148,7 +148,7 @@ char *JSON_convert_UTF16_to_UTF8 (
148
148
  }
149
149
  rb_str_buf_cat(buffer, p, bytesToWrite);
150
150
  }
151
- free(tmp);
151
+ ruby_xfree(tmp);
152
152
  source += 5 + (n - 1) * 6;
153
153
  return source;
154
154
  }
data/lib/json/add/core.rb CHANGED
@@ -96,7 +96,7 @@ class Struct
96
96
 
97
97
  def to_json(*args)
98
98
  klass = self.class.name
99
- klass.empty? and raise JSON::JSONError, "Only named structs are supported!"
99
+ klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
100
100
  {
101
101
  'json_class' => klass,
102
102
  'v' => values,
data/lib/json/editor.rb CHANGED
@@ -769,7 +769,12 @@ module JSON
769
769
  iter.type, iter.content = 'FalseClass', 'false'
770
770
  end
771
771
  when 'Numeric'
772
- iter.content = (Integer(value) rescue Float(value) rescue 0).to_s
772
+ iter.content =
773
+ if value == 'Infinity'
774
+ value
775
+ else
776
+ (Integer(value) rescue Float(value) rescue 0).to_s
777
+ end
773
778
  when 'String'
774
779
  iter.content = value
775
780
  when 'Hash', 'Array'
@@ -937,7 +942,11 @@ module JSON
937
942
  type = types[type_input.active]
938
943
  @content = case type
939
944
  when 'Numeric'
940
- Integer(value_input.text) rescue Float(value_input.text) rescue 0
945
+ if (t = value_input.text) == 'Infinity'
946
+ 1 / 0.0
947
+ else
948
+ Integer(t) rescue Float(t) rescue 0
949
+ end
941
950
  else
942
951
  value_input.text
943
952
  end.to_s
data/lib/json/ext.rb CHANGED
@@ -10,4 +10,6 @@ module JSON
10
10
  JSON.parser = Parser
11
11
  JSON.generator = Generator
12
12
  end
13
+
14
+ JSON_LOADED = true
13
15
  end
@@ -39,23 +39,48 @@ module JSON
39
39
 
40
40
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
41
41
  # UTF16 big endian characters as \u????, and return it.
42
- def utf8_to_json(string) # :nodoc:
43
- string = string.gsub(/["\\\/\x0-\x1f]/) { MAP[$&] }
44
- string.gsub!(/(
45
- (?:
46
- [\xc2-\xdf][\x80-\xbf] |
47
- [\xe0-\xef][\x80-\xbf]{2} |
48
- [\xf0-\xf4][\x80-\xbf]{3}
49
- )+ |
50
- [\x80-\xc1\xf5-\xff] # invalid
51
- )/nx) { |c|
52
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
53
- s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
54
- s.gsub!(/.{4}/n, '\\\\u\&')
55
- }
56
- string
57
- rescue Iconv::Failure => e
58
- raise GeneratorError, "Caught #{e.class}: #{e}"
42
+ if String.method_defined?(:force_encoding)
43
+ def utf8_to_json(string) # :nodoc:
44
+ string = string.dup
45
+ string << '' # XXX workaround: avoid buffer sharing
46
+ string.force_encoding(Encoding::ASCII_8BIT)
47
+ string.gsub!(/["\\\/\x0-\x1f]/) { MAP[$&] }
48
+ string.gsub!(/(
49
+ (?:
50
+ [\xc2-\xdf][\x80-\xbf] |
51
+ [\xe0-\xef][\x80-\xbf]{2} |
52
+ [\xf0-\xf4][\x80-\xbf]{3}
53
+ )+ |
54
+ [\x80-\xc1\xf5-\xff] # invalid
55
+ )/nx) { |c|
56
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
57
+ s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
58
+ s.gsub!(/.{4}/n, '\\\\u\&')
59
+ }
60
+ string.force_encoding(Encoding::UTF_8)
61
+ string
62
+ rescue Iconv::Failure => e
63
+ raise GeneratorError, "Caught #{e.class}: #{e}"
64
+ end
65
+ else
66
+ def utf8_to_json(string) # :nodoc:
67
+ string = string.gsub(/["\\\/\x0-\x1f]/) { MAP[$&] }
68
+ string.gsub!(/(
69
+ (?:
70
+ [\xc2-\xdf][\x80-\xbf] |
71
+ [\xe0-\xef][\x80-\xbf]{2} |
72
+ [\xf0-\xf4][\x80-\xbf]{3}
73
+ )+ |
74
+ [\x80-\xc1\xf5-\xff] # invalid
75
+ )/nx) { |c|
76
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
77
+ s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
78
+ s.gsub!(/.{4}/n, '\\\\u\&')
79
+ }
80
+ string
81
+ rescue Iconv::Failure => e
82
+ raise GeneratorError, "Caught #{e.class}: #{e}"
83
+ end
59
84
  end
60
85
  module_function :utf8_to_json
61
86
 
@@ -239,20 +264,28 @@ module JSON
239
264
 
240
265
  def json_transform(state, depth)
241
266
  delim = ','
242
- delim << state.object_nl if state
243
- result = '{'
244
- result << state.object_nl if state
245
- result << map { |key,value|
246
- s = json_shift(state, depth + 1)
247
- s << key.to_s.to_json(state, depth + 1)
248
- s << state.space_before if state
249
- s << ':'
250
- s << state.space if state
251
- s << value.to_json(state, depth + 1)
252
- }.join(delim)
253
- result << state.object_nl if state
254
- result << json_shift(state, depth)
255
- result << '}'
267
+ if state
268
+ delim << state.object_nl
269
+ result = '{'
270
+ result << state.object_nl
271
+ result << map { |key,value|
272
+ s = json_shift(state, depth + 1)
273
+ s << key.to_s.to_json(state, depth + 1)
274
+ s << state.space_before
275
+ s << ':'
276
+ s << state.space
277
+ s << value.to_json(state, depth + 1)
278
+ }.join(delim)
279
+ result << state.object_nl
280
+ result << json_shift(state, depth)
281
+ result << '}'
282
+ else
283
+ result = '{'
284
+ result << map { |key,value|
285
+ key.to_s.to_json << ':' << value.to_json
286
+ }.join(delim)
287
+ result << '}'
288
+ end
256
289
  result
257
290
  end
258
291
  end
@@ -293,16 +326,19 @@ module JSON
293
326
 
294
327
  def json_transform(state, depth)
295
328
  delim = ','
296
- delim << state.array_nl if state
297
- result = '['
298
- result << state.array_nl if state
299
- result << map { |value|
300
- json_shift(state, depth + 1) << value.to_json(state, depth + 1)
301
- }.join(delim)
302
- result << state.array_nl if state
303
- result << json_shift(state, depth)
304
- result << ']'
305
- result
329
+ if state
330
+ delim << state.array_nl
331
+ result = '['
332
+ result << state.array_nl
333
+ result << map { |value|
334
+ json_shift(state, depth + 1) << value.to_json(state, depth + 1)
335
+ }.join(delim)
336
+ result << state.array_nl
337
+ result << json_shift(state, depth)
338
+ result << ']'
339
+ else
340
+ '[' << map { |value| value.to_json }.join(delim) << ']'
341
+ end
306
342
  end
307
343
  end
308
344
 
@@ -122,19 +122,23 @@ module JSON
122
122
  def parse_string
123
123
  if scan(STRING)
124
124
  return '' if self[1].empty?
125
- self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
125
+ string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
126
126
  if u = UNESCAPE_MAP[$&[1]]
127
127
  u
128
128
  else # \uXXXX
129
129
  bytes = ''
130
130
  i = 0
131
- while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
131
+ while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
132
132
  bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
133
133
  i += 1
134
134
  end
135
135
  JSON::UTF16toUTF8.iconv(bytes)
136
136
  end
137
137
  end
138
+ if string.respond_to?(:force_encoding)
139
+ string.force_encoding(Encoding::UTF_8)
140
+ end
141
+ string
138
142
  else
139
143
  UNPARSED
140
144
  end
data/lib/json/pure.rb CHANGED
@@ -72,4 +72,6 @@ module JSON
72
72
  JSON.parser = Parser
73
73
  JSON.generator = Generator
74
74
  end
75
+
76
+ JSON_LOADED = true
75
77
  end
data/lib/json/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module JSON
2
2
  # JSON version
3
- VERSION = '1.1.3'
3
+ VERSION = '1.1.4'
4
4
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/json.rb CHANGED
@@ -1,223 +1,4 @@
1
1
  require 'json/common'
2
- # = json - JSON for Ruby
3
- #
4
- # == Description
5
- #
6
- # This is a implementation of the JSON specification according to RFC 4627
7
- # (http://www.ietf.org/rfc/rfc4627.txt). Starting from version 1.0.0 on there
8
- # will be two variants available:
9
- #
10
- # * A pure ruby variant, that relies on the iconv and the stringscan
11
- # extensions, which are both part of the ruby standard library.
12
- # * The quite a bit faster C extension variant, which is in parts implemented
13
- # in C and comes with its own unicode conversion functions and a parser
14
- # generated by the ragel state machine compiler
15
- # (http://www.cs.queensu.ca/~thurston/ragel).
16
- #
17
- # Both variants of the JSON generator escape all non-ASCII an control
18
- # characters with \uXXXX escape sequences, and support UTF-16 surrogate pairs
19
- # in order to be able to generate the whole range of unicode code points. This
20
- # means that generated JSON text is encoded as UTF-8 (because ASCII is a subset
21
- # of UTF-8) and at the same time avoids decoding problems for receiving
22
- # endpoints, that don't expect UTF-8 encoded texts. On the negative side this
23
- # may lead to a bit longer strings than necessarry.
24
- #
25
- # All strings, that are to be encoded as JSON strings, should be UTF-8 byte
26
- # sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
27
- # encoded, please use the to_json_raw_object method of String (which produces
28
- # an object, that contains a byte array) and decode the result on the receiving
29
- # endpoint.
30
- #
31
- # == Author
32
- #
33
- # Florian Frank <mailto:flori@ping.de>
34
- #
35
- # == License
36
- #
37
- # This software is distributed under the same license as Ruby itself, see
38
- # http://www.ruby-lang.org/en/LICENSE.txt.
39
- #
40
- # == Download
41
- #
42
- # The latest version of this library can be downloaded at
43
- #
44
- # * http://rubyforge.org/frs?group_id=953
45
- #
46
- # Online Documentation should be located at
47
- #
48
- # * http://json.rubyforge.org
49
- #
50
- # == Usage
51
- #
52
- # To use JSON you can
53
- # require 'json'
54
- # to load the installed variant (either the extension 'json' or the pure
55
- # variant 'json_pure'). If you have installed the extension variant, you can
56
- # pick either the extension variant or the pure variant by typing
57
- # require 'json/ext'
58
- # or
59
- # require 'json/pure'
60
- #
61
- # You can choose to load a set of common additions to ruby core's objects if
62
- # you
63
- # require 'json/add/core'
64
- #
65
- # After requiring this you can, e. g., serialise/deserialise Ruby ranges:
66
- #
67
- # JSON JSON(1..10) # => 1..10
68
- #
69
- # To find out how to add JSON support to other or your own classes, read the
70
- # Examples section below.
71
- #
72
- # To get the best compatibility to rails' JSON implementation, you can
73
- # require 'json/add/rails'
74
- #
75
- # Both of the additions attempt to require 'json' (like above) first, if it has
76
- # not been required yet.
77
- #
78
- # == Speed Comparisons
79
- #
80
- # I have created some benchmark results (see the benchmarks subdir of the
81
- # package) for the JSON-Parser to estimate the speed up in the C extension:
82
- #
83
- # JSON::Pure::Parser:: 28.90 calls/second
84
- # JSON::Ext::Parser:: 505.50 calls/second
85
- #
86
- # This is ca. <b>17.5</b> times the speed of the pure Ruby implementation.
87
- #
88
- # I have benchmarked the JSON-Generator as well. This generates a few more
89
- # values, because there are different modes, that also influence the achieved
90
- # speed:
91
- #
92
- # * JSON::Pure::Generator:
93
- # generate:: 35.06 calls/second
94
- # pretty_generate:: 34.00 calls/second
95
- # fast_generate:: 41.06 calls/second
96
- #
97
- # * JSON::Ext::Generator:
98
- # generate:: 492.11 calls/second
99
- # pretty_generate:: 348.85 calls/second
100
- # fast_generate:: 541.60 calls/second
101
- #
102
- # * Speedup Ext/Pure:
103
- # generate safe:: 14.0 times
104
- # generate pretty:: 10.3 times
105
- # generate fast:: 13.2 times
106
- #
107
- # The rails framework includes a generator as well, also it seems to be rather
108
- # slow: I measured only 23.87 calls/second which is slower than any of my pure
109
- # generator results. Here a comparison of the different speedups with the Rails
110
- # measurement as the divisor:
111
- #
112
- # * Speedup Pure/Rails:
113
- # generate safe:: 1.5 times
114
- # generate pretty:: 1.4 times
115
- # generate fast:: 1.7 times
116
- #
117
- # * Speedup Ext/Rails:
118
- # generate safe:: 20.6 times
119
- # generate pretty:: 14.6 times
120
- # generate fast:: 22.7 times
121
- #
122
- # To achieve the fastest JSON text output, you can use the
123
- # fast_generate/fast_unparse methods. Beware, that this will disable the
124
- # checking for circular Ruby data structures, which may cause JSON to go into
125
- # an infinite loop.
126
- #
127
- # == Examples
128
- #
129
- # To create a JSON text from a ruby data structure, you
130
- # can call JSON.generate (or JSON.unparse) like that:
131
- #
132
- # json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
133
- # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
134
- #
135
- # To create a valid JSON text you have to make sure, that the output is
136
- # embedded in either a JSON array [] or a JSON object {}. The easiest way to do
137
- # this, is by putting your values in a Ruby Array or Hash instance.
138
- #
139
- # To get back a ruby data structure from a JSON text, you have to call
140
- # JSON.parse on it:
141
- #
142
- # JSON.parse json
143
- # # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
144
- #
145
- # Note, that the range from the original data structure is a simple
146
- # string now. The reason for this is, that JSON doesn't support ranges
147
- # or arbitrary classes. In this case the json library falls back to call
148
- # Object#to_json, which is the same as #to_s.to_json.
149
- #
150
- # It's possible to add JSON support serialization to arbitrary classes by
151
- # simply implementing a more specialized version of the #to_json method, that
152
- # should return a JSON object (a hash converted to JSON with #to_json) like
153
- # this (don't forget the *a for all the arguments):
154
- #
155
- # class Range
156
- # def to_json(*a)
157
- # {
158
- # 'json_class' => self.class.name, # = 'Range'
159
- # 'data' => [ first, last, exclude_end? ]
160
- # }.to_json(*a)
161
- # end
162
- # end
163
- #
164
- # The hash key 'json_class' is the class, that will be asked to deserialise the
165
- # JSON representation later. In this case it's 'Range', but any namespace of
166
- # the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
167
- # used to store the necessary data to configure the object to be deserialised.
168
- #
169
- # If a the key 'json_class' is found in a JSON object, the JSON parser checks
170
- # if the given class responds to the json_create class method. If so, it is
171
- # called with the JSON object converted to a Ruby hash. So a range can
172
- # be deserialised by implementing Range.json_create like this:
173
- #
174
- # class Range
175
- # def self.json_create(o)
176
- # new(*o['data'])
177
- # end
178
- # end
179
- #
180
- # Now it possible to serialise/deserialise ranges as well:
181
- #
182
- # json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
183
- # # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
184
- # JSON.parse json
185
- # # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
186
- #
187
- # JSON.generate always creates the shortest possible string representation of a
188
- # ruby data structure in one line. This good for data storage or network
189
- # protocols, but not so good for humans to read. Fortunately there's also
190
- # JSON.pretty_generate (or JSON.pretty_generate) that creates a more
191
- # readable output:
192
- #
193
- # puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
194
- # [
195
- # 1,
196
- # 2,
197
- # {
198
- # "a": 3.141
199
- # },
200
- # false,
201
- # true,
202
- # null,
203
- # {
204
- # "json_class": "Range",
205
- # "data": [
206
- # 4,
207
- # 10,
208
- # false
209
- # ]
210
- # }
211
- # ]
212
- #
213
- # There are also the methods Kernel#j for unparse, and Kernel#jj for
214
- # pretty_unparse output to the console, that work analogous to Core Ruby's p
215
- # and the pp library's pp methods.
216
- #
217
- # The script tools/server.rb contains a small example if you want to test, how
218
- # receiving a JSON object from a webrick server in your browser with the
219
- # javasript prototype library (http://www.prototypejs.org) works.
220
- #
221
2
  module JSON
222
3
  require 'json/version'
223
4
 
@@ -230,6 +11,4 @@ module JSON
230
11
  require 'json/pure'
231
12
  end
232
13
  end
233
-
234
- JSON_LOADED = true
235
14
  end
data/tests/test_json.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
2
3
 
3
4
  require 'test/unit'
4
- require 'json'
5
+ case ENV['JSON']
6
+ when 'pure' then require 'json/pure'
7
+ when 'ext' then require 'json/ext'
8
+ else require 'json'
9
+ end
5
10
  require 'stringio'
6
11
 
7
12
  class TC_JSON < Test::Unit::TestCase
8
13
  include JSON
9
14
 
10
15
  def setup
11
- $KCODE = 'UTF8'
12
16
  @ary = [1, "foo", 3.14, 4711.0, 2.718, nil, [1,-2,3], false, true].map do
13
17
  |x| [x]
14
18
  end
@@ -26,10 +30,9 @@ class TC_JSON < Test::Unit::TestCase
26
30
  'h' => 1000.0,
27
31
  'i' => 0.001
28
32
  }
29
- @json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
33
+ @json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},'\
30
34
  '"g":"\\"\\u0000\\u001f","h":1.0E3,"i":1.0E-3}'
31
35
  end
32
- suite << TC_JSON.suite
33
36
 
34
37
  def test_construction
35
38
  parser = JSON::Parser.new('test')
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding:utf-8 -*-
2
3
 
3
4
  require 'test/unit'
5
+ case ENV['JSON']
6
+ when 'pure' then require 'json/pure'
7
+ when 'ext' then require 'json/ext'
8
+ else require 'json'
9
+ end
4
10
  require 'json/add/core'
5
11
  require 'date'
6
12
 
@@ -54,10 +60,6 @@ class TC_JSONAddition < Test::Unit::TestCase
54
60
  end
55
61
  end
56
62
 
57
- def setup
58
- $KCODE = 'UTF8'
59
- end
60
-
61
63
  def test_extended_json
62
64
  a = A.new(666)
63
65
  assert A.json_creatable?
@@ -98,6 +100,7 @@ class TC_JSONAddition < Test::Unit::TestCase
98
100
 
99
101
  def test_raw_strings
100
102
  raw = ''
103
+ raw.respond_to?(:encode!) and raw.encode!(Encoding::ASCII_8BIT)
101
104
  raw_array = []
102
105
  for i in 0..255
103
106
  raw << i
@@ -120,7 +123,7 @@ EOT
120
123
 
121
124
  def test_core
122
125
  t = Time.now
123
- assert_equal t, JSON(JSON(t))
126
+ assert_equal t.inspect, JSON(JSON(t)).inspect
124
127
  d = Date.today
125
128
  assert_equal d, JSON(JSON(d))
126
129
  d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
2
3
 
3
4
  require 'test/unit'
4
- require 'json'
5
+ case ENV['JSON']
6
+ when 'pure' then require 'json/pure'
7
+ when 'ext' then require 'json/ext'
8
+ else require 'json'
9
+ end
5
10
 
6
11
  class TC_JSONFixtures < Test::Unit::TestCase
7
12
  def setup
8
- $KCODE = 'UTF8'
9
13
  fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json')
10
14
  passed, failed = Dir[fixtures].partition { |f| f['pass'] }
11
15
  @passed = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort