Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 359 lines (275 sloc) 12.574 kb
2236e56 @plentz making the travis badge visible :)
plentz authored
1 = JSON implementation for Ruby {<img src="https://secure.travis-ci.org/flori/json.png" />}[http://travis-ci.org/flori/json]
b8f2b87 @flori Include travis-ci icon
authored
2
66f233e @flori changed docu title and headlines
authored
3 == Description
10f03df @flori initial commit
authored
4
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
5 This is a implementation of the JSON specification according to RFC 4627
07d7b71 @flori avoid rdoc issue, thx to github user spier.
authored
6 http://www.ietf.org/rfc/rfc4627.txt . Starting from version 1.0.0 on there
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
7 will be two variants available:
10f03df @flori initial commit
authored
8
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
9 * A pure ruby variant, that relies on the iconv and the stringscan
10 extensions, which are both part of the ruby standard library.
704a7cf @headius Fix mention of C extensions in README
headius authored
11 * The quite a bit faster native extension variant, which is in parts
12 implemented in C or Java and comes with its own unicode conversion
13 functions and a parser generated by the ragel state machine compiler
07d7b71 @flori avoid rdoc issue, thx to github user spier.
authored
14 http://www.cs.queensu.ca/~thurston/ragel .
10f03df @flori initial commit
authored
15
7bcff4c @flori changed documentation
authored
16 Both variants of the JSON generator generate UTF-8 character sequences by
17 default. If an :ascii_only option with a true value is given, they escape all
18 non-ASCII and control characters with \uXXXX escape sequences, and support
19 UTF-16 surrogate pairs in order to be able to generate the whole range of
20 unicode code points.
10f03df @flori initial commit
authored
21
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
22 All strings, that are to be encoded as JSON strings, should be UTF-8 byte
23 sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
24 encoded, please use the to_json_raw_object method of String (which produces
25 an object, that contains a byte array) and decode the result on the receiving
26 endpoint.
10f03df @flori initial commit
authored
27
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
28 The JSON parsers can parse UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, and UTF-32LE
29 JSON documents under Ruby 1.8. Under Ruby 1.9 they take advantage of Ruby's
30 M17n features and can parse all documents which have the correct
31 String#encoding set. If a document string has ASCII-8BIT as an encoding the
32 parser attempts to figure out which of the UTF encodings from above it is and
33 trys to parse it.
10f03df @flori initial commit
authored
34
66f233e @flori changed docu title and headlines
authored
35 == Installation
10f03df @flori initial commit
authored
36
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
37 It's recommended to use the extension variant of JSON, because it's faster than
38 the pure ruby variant. If you cannot build it on your system, you can settle
39 for the latter.
10f03df @flori initial commit
authored
40
41 Just type into the command line as root:
42
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
43 # rake install
10f03df @flori initial commit
authored
44
45 The above command will build the extensions and install them on your system.
46
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
47 # rake install_pure
10f03df @flori initial commit
authored
48
49 or
50
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
51 # ruby install.rb
10f03df @flori initial commit
authored
52
53 will just install the pure ruby implementation of JSON.
54
55 If you use Rubygems you can type
56
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
57 # gem install json
10f03df @flori initial commit
authored
58
59 instead, to install the newest JSON version.
60
61 There is also a pure ruby json only variant of the gem, that can be installed
62 with:
63
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
64 # gem install json_pure
65
66f233e @flori changed docu title and headlines
authored
66 == Compiling the extensions yourself
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
67
68 If you want to build the extensions yourself you need rake:
69
70 You can get it from rubyforge:
71 http://rubyforge.org/projects/rake
72
73 or just type
74
75 # gem install rake
76
77 for the installation via rubygems.
78
79 If you want to create the parser.c file from its parser.rl file or draw nice
80 graphviz images of the state machines, you need ragel from: http://www.cs.queensu.ca/~thurston/ragel
81
82
66f233e @flori changed docu title and headlines
authored
83 == Usage
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
84
85 To use JSON you can
86 require 'json'
87 to load the installed variant (either the extension 'json' or the pure
88 variant 'json_pure'). If you have installed the extension variant, you can
89 pick either the extension variant or the pure variant by typing
90 require 'json/ext'
91 or
92 require 'json/pure'
93
94 Now you can parse a JSON document into a ruby data structure by calling
95
96 JSON.parse(document)
97
98 If you want to generate a JSON document from a ruby data structure call
99 JSON.generate(data)
100
101 You can also use the pretty_generate method (which formats the output more
102 verbosely and nicely) or fast_generate (which doesn't do any of the security
103 checks generate performs, e. g. nesting deepness checks).
104
105 To create a valid JSON document you have to make sure, that the output is
106 embedded in either a JSON array [] or a JSON object {}. The easiest way to do
107 this, is by putting your values in a Ruby Array or Hash instance.
108
109 There are also the JSON and JSON[] methods which use parse on a String or
110 generate a JSON document from an array or hash:
111
112 document = JSON 'test' => 23 # => "{\"test\":23}"
113 document = JSON['test'] => 23 # => "{\"test\":23}"
114
115 and
116
117 data = JSON '{"test":23}' # => {"test"=>23}
118 data = JSON['{"test":23}'] # => {"test"=>23}
119
120 You can choose to load a set of common additions to ruby core's objects if
121 you
122 require 'json/add/core'
123
124 After requiring this you can, e. g., serialise/deserialise Ruby ranges:
10f03df @flori initial commit
authored
125
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
126 JSON JSON(1..10) # => 1..10
10f03df @flori initial commit
authored
127
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
128 To find out how to add JSON support to other or your own classes, read the
129 section "More Examples" below.
10f03df @flori initial commit
authored
130
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
131 To get the best compatibility to rails' JSON implementation, you can
132 require 'json/add/rails'
10f03df @flori initial commit
authored
133
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
134 Both of the additions attempt to require 'json' (like above) first, if it has
135 not been required yet.
10f03df @flori initial commit
authored
136
66f233e @flori changed docu title and headlines
authored
137 == More Examples
10f03df @flori initial commit
authored
138
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
139 To create a JSON document from a ruby data structure, you can call
140 JSON.generate like that:
10f03df @flori initial commit
authored
141
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
142 json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
143 # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
144
145 To get back a ruby data structure from a JSON document, you have to call
146 JSON.parse on it:
147
148 JSON.parse json
149 # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
150
151 Note, that the range from the original data structure is a simple
152 string now. The reason for this is, that JSON doesn't support ranges
153 or arbitrary classes. In this case the json library falls back to call
154 Object#to_json, which is the same as #to_s.to_json.
155
156 It's possible to add JSON support serialization to arbitrary classes by
157 simply implementing a more specialized version of the #to_json method, that
158 should return a JSON object (a hash converted to JSON with #to_json) like
159 this (don't forget the *a for all the arguments):
160
161 class Range
162 def to_json(*a)
163 {
164 'json_class' => self.class.name, # = 'Range'
165 'data' => [ first, last, exclude_end? ]
166 }.to_json(*a)
167 end
168 end
169
170 The hash key 'json_class' is the class, that will be asked to deserialise the
171 JSON representation later. In this case it's 'Range', but any namespace of
172 the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
173 used to store the necessary data to configure the object to be deserialised.
174
175 If a the key 'json_class' is found in a JSON object, the JSON parser checks
176 if the given class responds to the json_create class method. If so, it is
177 called with the JSON object converted to a Ruby hash. So a range can
178 be deserialised by implementing Range.json_create like this:
179
180 class Range
181 def self.json_create(o)
182 new(*o['data'])
183 end
184 end
185
186 Now it possible to serialise/deserialise ranges as well:
187
188 json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
189 # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
190 JSON.parse json
191 # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
192
193 JSON.generate always creates the shortest possible string representation of a
194 ruby data structure in one line. This is good for data storage or network
195 protocols, but not so good for humans to read. Fortunately there's also
196 JSON.pretty_generate (or JSON.pretty_generate) that creates a more readable
197 output:
198
199 puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
200 [
201 1,
202 2,
203 {
204 "a": 3.141
205 },
206 false,
207 true,
208 null,
209 {
210 "json_class": "Range",
211 "data": [
212 4,
213 10,
214 false
215 ]
216 }
217 ]
218
219 There are also the methods Kernel#j for generate, and Kernel#jj for
220 pretty_generate output to the console, that work analogous to Core Ruby's p and
221 the pp library's pp methods.
222
223 The script tools/server.rb contains a small example if you want to test, how
10f03df @flori initial commit
authored
224 receiving a JSON object from a webrick server in your browser with the
07d7b71 @flori avoid rdoc issue, thx to github user spier.
authored
225 javasript prototype library http://www.prototypejs.org works.
10f03df @flori initial commit
authored
226
66f233e @flori changed docu title and headlines
authored
227 == Speed Comparisons
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
228
229 I have created some benchmark results (see the benchmarks/data-p4-3Ghz
230 subdir of the package) for the JSON-parser to estimate the speed up in the C
231 extension:
232
233 Comparing times (call_time_mean):
234 1 ParserBenchmarkExt#parser 900 repeats:
235 553.922304770 ( real) -> 21.500x
236 0.001805307
237 2 ParserBenchmarkYAML#parser 1000 repeats:
238 224.513358139 ( real) -> 8.714x
239 0.004454078
240 3 ParserBenchmarkPure#parser 1000 repeats:
241 26.755020642 ( real) -> 1.038x
242 0.037376163
243 4 ParserBenchmarkRails#parser 1000 repeats:
244 25.763381731 ( real) -> 1.000x
245 0.038814780
246 calls/sec ( time) -> speed covers
247 secs/call
10f03df @flori initial commit
authored
248
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
249 In the table above 1 is JSON::Ext::Parser, 2 is YAML.load with YAML
250 compatbile JSON document, 3 is is JSON::Pure::Parser, and 4 is
251 ActiveSupport::JSON.decode. The ActiveSupport JSON-decoder converts the
252 input first to YAML and then uses the YAML-parser, the conversion seems to
253 slow it down so much that it is only as fast as the JSON::Pure::Parser!
10f03df @flori initial commit
authored
254
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
255 If you look at the benchmark data you can see that this is mostly caused by
256 the frequent high outliers - the median of the Rails-parser runs is still
257 overall smaller than the median of the JSON::Pure::Parser runs:
258
259 Comparing times (call_time_median):
260 1 ParserBenchmarkExt#parser 900 repeats:
261 800.592479481 ( real) -> 26.936x
262 0.001249075
263 2 ParserBenchmarkYAML#parser 1000 repeats:
264 271.002390644 ( real) -> 9.118x
265 0.003690004
266 3 ParserBenchmarkRails#parser 1000 repeats:
267 30.227910865 ( real) -> 1.017x
268 0.033082008
269 4 ParserBenchmarkPure#parser 1000 repeats:
270 29.722384421 ( real) -> 1.000x
271 0.033644676
272 calls/sec ( time) -> speed covers
273 secs/call
274
275 I have benchmarked the JSON-Generator as well. This generated a few more
276 values, because there are different modes that also influence the achieved
277 speed:
278
279 Comparing times (call_time_mean):
280 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
281 547.354332608 ( real) -> 15.090x
282 0.001826970
283 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
284 443.968212317 ( real) -> 12.240x
285 0.002252414
286 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
287 375.104545883 ( real) -> 10.341x
288 0.002665923
289 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
290 49.978706968 ( real) -> 1.378x
291 0.020008521
292 5 GeneratorBenchmarkRails#generator 1000 repeats:
293 38.531868759 ( real) -> 1.062x
294 0.025952543
295 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
296 36.927649925 ( real) -> 1.018x 7 (>=3859)
297 0.027079979
298 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
299 36.272134441 ( real) -> 1.000x 6 (>=3859)
300 0.027569373
301 calls/sec ( time) -> speed covers
302 secs/call
303
304 In the table above 1-3 are JSON::Ext::Generator methods. 4, 6, and 7 are
305 JSON::Pure::Generator methods and 5 is the Rails JSON generator. It is now a
306 bit faster than the generator_safe and generator_pretty methods of the pure
307 variant but slower than the others.
308
309 To achieve the fastest JSON document output, you can use the fast_generate
310 method. Beware, that this will disable the checking for circular Ruby data
311 structures, which may cause JSON to go into an infinite loop.
312
313 Here are the median comparisons for completeness' sake:
314
315 Comparing times (call_time_median):
316 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
317 708.258020939 ( real) -> 16.547x
318 0.001411915
319 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
320 569.105020353 ( real) -> 13.296x
321 0.001757145
322 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
323 482.825371244 ( real) -> 11.280x
324 0.002071142
325 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
326 62.717626652 ( real) -> 1.465x
327 0.015944481
328 5 GeneratorBenchmarkRails#generator 1000 repeats:
329 43.965681162 ( real) -> 1.027x
330 0.022745013
331 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
332 43.929073409 ( real) -> 1.026x 7 (>=3859)
333 0.022763968
334 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
335 42.802514491 ( real) -> 1.000x 6 (>=3859)
336 0.023363113
337 calls/sec ( time) -> speed covers
338 secs/call
339
66f233e @flori changed docu title and headlines
authored
340 == Author
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
341
342 Florian Frank <mailto:flori@ping.de>
343
66f233e @flori changed docu title and headlines
authored
344 == License
10f03df @flori initial commit
authored
345
346 Ruby License, see the COPYING file included in the source distribution. The
347 Ruby License includes the GNU General Public License (GPL), Version 2, so see
348 the file GPL as well.
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
349
66f233e @flori changed docu title and headlines
authored
350 == Download
03b1575 @flori implemented utf sniffing, transcoding in parser
authored
351
352 The latest version of this library can be downloaded at
353
354 * http://rubyforge.org/frs?group_id=953
355
356 Online Documentation should be located at
357
358 * http://json.rubyforge.org
Something went wrong with that request. Please try again.