diff --git a/README.md b/README.md index 488c427d0..3b0b6ebfe 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,14 @@ ## Description -This is a implementation of the JSON specification according to RFC 7159 -http://www.ietf.org/rfc/rfc7159.txt . Starting from version 1.0.0 on there -will be two variants available: +This is an implementation of the JSON specification according to RFC 7159 +http://www.ietf.org/rfc/rfc7159.txt . There is two variants available: -* A pure ruby variant, that relies on the iconv and the stringscan - extensions, which are both part of the ruby standard library. +* A pure ruby variant, that relies on the `strscan` extensions, which is + part of the ruby standard library. * The quite a bit faster native extension variant, which is in parts - implemented in C or Java and comes with its own unicode conversion - functions and a parser generated by the [Ragel] state machine compiler. + implemented in C or Java and comes with a parser generated by the [Ragel] + state machine compiler. Both variants of the JSON generator generate UTF-8 character sequences by default. If an :ascii\_only option with a true value is given, they escape all @@ -32,45 +31,19 @@ It's recommended to use the extension variant of JSON, because it's faster than the pure ruby variant. If you cannot build it on your system, you can settle for the latter. -Just type into the command line as root: +Install the gem and add to the application's Gemfile by executing: -``` -# rake install -``` - -The above command will build the extensions and install them on your system. - -``` -# rake install_pure -``` - -or - -``` -# ruby install.rb -``` + $ bundle add json -will just install the pure ruby implementation of JSON. +If bundler is not being used to manage dependencies, install the gem by executing: -If you use Rubygems you can type + $ gem install json -``` -# gem install json -``` - -instead, to install the newest JSON version. There is also a pure ruby json only variant of the gem, that can be installed with: -``` -# gem install json_pure -``` - -## Compiling the extensions yourself - -If you want to create the `parser.c` file from its `parser.rl` file or draw nice -graphviz images of the state machines, you need [Ragel]. + $ gem install json_pure ## Usage @@ -254,131 +227,6 @@ There are also the methods `Kernel#j` for generate, and `Kernel#jj` for `pretty_generate` output to the console, that work analogous to Core Ruby's `p` and the `pp` library's `pp` methods. -The script `tools/server.rb` contains a small example if you want to test, how -receiving a JSON object from a webrick server in your browser with the -JavaScript prototype library http://www.prototypejs.org works. - -## Speed Comparisons - -I have created some benchmark results (see the benchmarks/data-p4-3Ghz -subdir of the package) for the JSON-parser to estimate the speed up in the C -extension: - -``` - Comparing times (call_time_mean): - 1 ParserBenchmarkExt#parser 900 repeats: - 553.922304770 ( real) -> 21.500x - 0.001805307 - 2 ParserBenchmarkYAML#parser 1000 repeats: - 224.513358139 ( real) -> 8.714x - 0.004454078 - 3 ParserBenchmarkPure#parser 1000 repeats: - 26.755020642 ( real) -> 1.038x - 0.037376163 - 4 ParserBenchmarkRails#parser 1000 repeats: - 25.763381731 ( real) -> 1.000x - 0.038814780 - calls/sec ( time) -> speed covers - secs/call -``` - -In the table above 1 is `JSON::Ext::Parser`, 2 is `YAML.load` with YAML -compatible JSON document, 3 is is `JSON::Pure::Parser`, and 4 is -`ActiveSupport::JSON.decode`. The ActiveSupport JSON-decoder converts the -input first to YAML and then uses the YAML-parser, the conversion seems to -slow it down so much that it is only as fast as the `JSON::Pure::Parser`! - -If you look at the benchmark data you can see that this is mostly caused by -the frequent high outliers - the median of the Rails-parser runs is still -overall smaller than the median of the `JSON::Pure::Parser` runs: - -``` - Comparing times (call_time_median): - 1 ParserBenchmarkExt#parser 900 repeats: - 800.592479481 ( real) -> 26.936x - 0.001249075 - 2 ParserBenchmarkYAML#parser 1000 repeats: - 271.002390644 ( real) -> 9.118x - 0.003690004 - 3 ParserBenchmarkRails#parser 1000 repeats: - 30.227910865 ( real) -> 1.017x - 0.033082008 - 4 ParserBenchmarkPure#parser 1000 repeats: - 29.722384421 ( real) -> 1.000x - 0.033644676 - calls/sec ( time) -> speed covers - secs/call -``` - -I have benchmarked the `JSON-Generator` as well. This generated a few more -values, because there are different modes that also influence the achieved -speed: - -``` - Comparing times (call_time_mean): - 1 GeneratorBenchmarkExt#generator_fast 1000 repeats: - 547.354332608 ( real) -> 15.090x - 0.001826970 - 2 GeneratorBenchmarkExt#generator_safe 1000 repeats: - 443.968212317 ( real) -> 12.240x - 0.002252414 - 3 GeneratorBenchmarkExt#generator_pretty 900 repeats: - 375.104545883 ( real) -> 10.341x - 0.002665923 - 4 GeneratorBenchmarkPure#generator_fast 1000 repeats: - 49.978706968 ( real) -> 1.378x - 0.020008521 - 5 GeneratorBenchmarkRails#generator 1000 repeats: - 38.531868759 ( real) -> 1.062x - 0.025952543 - 6 GeneratorBenchmarkPure#generator_safe 1000 repeats: - 36.927649925 ( real) -> 1.018x 7 (>=3859) - 0.027079979 - 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats: - 36.272134441 ( real) -> 1.000x 6 (>=3859) - 0.027569373 - calls/sec ( time) -> speed covers - secs/call -``` - -In the table above 1-3 are `JSON::Ext::Generator` methods. 4, 6, and 7 are -`JSON::Pure::Generator` methods and 5 is the Rails JSON generator. It is now a -bit faster than the `generator_safe` and `generator_pretty` methods of the pure -variant but slower than the others. - -To achieve the fastest JSON document output, you can use the `fast_generate` -method. Beware, that this will disable the checking for circular Ruby data -structures, which may cause JSON to go into an infinite loop. - -Here are the median comparisons for completeness' sake: - -``` - Comparing times (call_time_median): - 1 GeneratorBenchmarkExt#generator_fast 1000 repeats: - 708.258020939 ( real) -> 16.547x - 0.001411915 - 2 GeneratorBenchmarkExt#generator_safe 1000 repeats: - 569.105020353 ( real) -> 13.296x - 0.001757145 - 3 GeneratorBenchmarkExt#generator_pretty 900 repeats: - 482.825371244 ( real) -> 11.280x - 0.002071142 - 4 GeneratorBenchmarkPure#generator_fast 1000 repeats: - 62.717626652 ( real) -> 1.465x - 0.015944481 - 5 GeneratorBenchmarkRails#generator 1000 repeats: - 43.965681162 ( real) -> 1.027x - 0.022745013 - 6 GeneratorBenchmarkPure#generator_safe 1000 repeats: - 43.929073409 ( real) -> 1.026x 7 (>=3859) - 0.022763968 - 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats: - 42.802514491 ( real) -> 1.000x 6 (>=3859) - 0.023363113 - calls/sec ( time) -> speed covers - secs/call -``` - ## Development ### Release diff --git a/tools/diff.sh b/tools/diff.sh deleted file mode 100755 index 89385b038..000000000 --- a/tools/diff.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -files=`find ext -name '*.[ch]' -o -name parser.rl` - -for f in $files -do - b=`basename $f` - g=`find ../ruby/ext/json -name $b` - d=`diff -u $f $g` - test -z "$d" && continue - echo "$d" - read -p "Edit diff of $b? " a - case $a in - [yY]*) - vimdiff $f $g - ;; - esac -done diff --git a/tools/server.rb b/tools/server.rb deleted file mode 100755 index 084377fa9..000000000 --- a/tools/server.rb +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env ruby - -require 'webrick' -include WEBrick -$:.unshift 'ext' -$:.unshift 'lib' -require 'json' - -class JSONServlet < HTTPServlet::AbstractServlet - @@count = 1 - - def do_GET(req, res) - obj = { - "TIME" => Time.now.strftime("%FT%T"), - "foo" => "Bär", - "bar" => "© ≠ €!", - 'a' => 2, - 'b' => 3.141, - 'COUNT' => @@count += 1, - 'c' => 'c', - 'd' => [ 1, "b", 3.14 ], - 'e' => { 'foo' => 'bar' }, - 'g' => "松本行弘", - 'h' => 1000.0, - 'i' => 0.001, - 'j' => "\xf0\xa0\x80\x81", - } - res.body = JSON.generate obj - res['Content-Type'] = "application/json" - end -end - -def create_server(err, dir, port) - dir = File.expand_path(dir) - err.puts "Surf to:", "http://#{Socket.gethostname}:#{port}" - - s = HTTPServer.new( - :Port => port, - :DocumentRoot => dir, - :Logger => WEBrick::Log.new(err), - :AccessLog => [ - [ err, WEBrick::AccessLog::COMMON_LOG_FORMAT ], - [ err, WEBrick::AccessLog::REFERER_LOG_FORMAT ], - [ err, WEBrick::AccessLog::AGENT_LOG_FORMAT ] - ] - ) - s.mount("/json", JSONServlet) - s -end - -default_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'data')) -dir = ARGV.shift || default_dir -port = (ARGV.shift || 6666).to_i -s = create_server(STDERR, dir, 6666) -t = Thread.new { s.start } -trap(:INT) do - s.shutdown - t.join - exit -end -sleep