From 1d7dcf9f997f01e36ee0217f36cef2525ebfd8ab Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Sun, 17 May 2009 15:22:45 -0700 Subject: [PATCH] add yajl-ruby as a JSON parser backend --- .../lib/active_support/json/backends/yajl.rb | 40 ++++++++++++++++++++ activesupport/test/json/decoding_test.rb | 38 ++++++++++++++++-- 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 activesupport/lib/active_support/json/backends/yajl.rb diff --git a/activesupport/lib/active_support/json/backends/yajl.rb b/activesupport/lib/active_support/json/backends/yajl.rb new file mode 100644 index 0000000..42efce6 --- /dev/null +++ b/activesupport/lib/active_support/json/backends/yajl.rb @@ -0,0 +1,40 @@ +require 'stringio' unless defined?(StringIO) +module ActiveSupport + module JSON + ParseError = ::Yajl::ParseError + + module Backends + module Yajl + extend self + + # Parses a JSON string or IO and converts it into an object + def decode(json) + unless json.respond_to?(:read) + json = StringIO.new(json) + end + data = ::Yajl::Stream.parse(json) + if ActiveSupport.parse_json_times + convert_dates_from(data) + else + data + end + end + + private + def convert_dates_from(data) + case data + when DATE_REGEX + DateTime.parse(data) + when Array + data.map! { |d| convert_dates_from(d) } + when Hash + data.each do |key, value| + data[key] = convert_dates_from(value) + end + else data + end + end + end + end + end +end \ No newline at end of file diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index 7e1bfcc..f4d47c3 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -2,6 +2,7 @@ require 'abstract_unit' require 'active_support/json' require 'active_support/core_ext/kernel/reporting' +require 'stringio' class TestJSONDecoding < ActiveSupport::TestCase TESTS = { @@ -36,6 +37,7 @@ class TestJSONDecoding < ActiveSupport::TestCase %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} } + time_parsing_backends = %w(JSONGem Yajl) backends = %w(Yaml) begin gem 'json', '>= 1.1' @@ -44,6 +46,19 @@ class TestJSONDecoding < ActiveSupport::TestCase rescue Gem::LoadError # Skip JSON gem tests end + gem_name = 'yajl-ruby' + begin + gem gem_name + require 'yajl' + backends << "Yajl" + rescue Gem::LoadError + if gem_name =~ /^yajl/ + gem_name = "brianmario-#{gem_name}" + retry + end + puts $! + # Skip JSON gem tests + end backends.each do |backend| TESTS.each do |json, expected| @@ -60,17 +75,30 @@ class TestJSONDecoding < ActiveSupport::TestCase end end - if backends.include?("JSONGem") - test "json decodes time json with time parsing disabled" do + (backends & time_parsing_backends).each do |backend| + test "json decodes with time parsing disabled using #{backend} backend" do ActiveSupport.parse_json_times = false expected = {"a" => "2007-01-01 01:12:34 Z"} - ActiveSupport::JSON.with_backend "JSONGem" do + ActiveSupport::JSON.with_backend backend do assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) end end end def test_failed_json_decoding - assert_raise(ActiveSupport::JSON::ParseError) { ActiveSupport::JSON.decode(%({: 1})) } + assert_raise(ActiveSupport::JSON::ParseError) { + ActiveSupport::JSON.decode(%({: 1})) + } + end + + (backends & time_parsing_backends).each do |backend| + test "json decodes from an IO using #{backend} backend" do + ActiveSupport.parse_json_times = false + expected = {"a" => "2007-01-01 01:12:34 Z"} + ActiveSupport::JSON.with_backend backend do + io = StringIO.new(%({"a": "2007-01-01 01:12:34 Z"})) + assert_equal expected, ActiveSupport::JSON.decode(io) + end + end end -end +end \ No newline at end of file -- 1.6.1