mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
removed AS backends and instead rely on MultiJson for json decoding
This commit is contained in:
parent
3e33592316
commit
e019587e31
6 changed files with 40 additions and 235 deletions
2
Gemfile
2
Gemfile
|
@ -15,6 +15,8 @@ gem "sprockets", :git => "git://github.com/sstephenson/sprockets.git"
|
||||||
gem "coffee-script"
|
gem "coffee-script"
|
||||||
gem "sass", ">= 3.0"
|
gem "sass", ">= 3.0"
|
||||||
|
|
||||||
|
gem "multi_json", :git => 'git://github.com/intridea/multi_json.git'
|
||||||
|
|
||||||
gem "rake", ">= 0.8.7"
|
gem "rake", ">= 0.8.7"
|
||||||
gem "mocha", ">= 0.9.8"
|
gem "mocha", ">= 0.9.8"
|
||||||
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
require 'json' unless defined?(JSON)
|
|
||||||
|
|
||||||
module ActiveSupport
|
|
||||||
module JSON
|
|
||||||
module Backends
|
|
||||||
module JSONGem
|
|
||||||
ParseError = ::JSON::ParserError
|
|
||||||
extend self
|
|
||||||
|
|
||||||
# Parses a JSON string or IO and convert it into an object
|
|
||||||
def decode(json)
|
|
||||||
if json.respond_to?(:read)
|
|
||||||
json = json.read
|
|
||||||
end
|
|
||||||
data = ::JSON.parse(json)
|
|
||||||
if ActiveSupport.parse_json_times
|
|
||||||
convert_dates_from(data)
|
|
||||||
else
|
|
||||||
data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def convert_dates_from(data)
|
|
||||||
case data
|
|
||||||
when nil
|
|
||||||
nil
|
|
||||||
when DATE_REGEX
|
|
||||||
begin
|
|
||||||
DateTime.parse(data)
|
|
||||||
rescue ArgumentError
|
|
||||||
data
|
|
||||||
end
|
|
||||||
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
|
|
|
@ -1,44 +0,0 @@
|
||||||
require 'yajl' unless defined?(Yajl)
|
|
||||||
|
|
||||||
module ActiveSupport
|
|
||||||
module JSON
|
|
||||||
module Backends
|
|
||||||
module Yajl
|
|
||||||
ParseError = ::Yajl::ParseError
|
|
||||||
extend self
|
|
||||||
|
|
||||||
# Parses a JSON string or IO and convert it into an object
|
|
||||||
def decode(json)
|
|
||||||
data = ::Yajl::Parser.new.parse(json)
|
|
||||||
if ActiveSupport.parse_json_times
|
|
||||||
convert_dates_from(data)
|
|
||||||
else
|
|
||||||
data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def convert_dates_from(data)
|
|
||||||
case data
|
|
||||||
when nil
|
|
||||||
nil
|
|
||||||
when DATE_REGEX
|
|
||||||
begin
|
|
||||||
DateTime.parse(data)
|
|
||||||
rescue ArgumentError
|
|
||||||
data
|
|
||||||
end
|
|
||||||
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
|
|
|
@ -1,113 +0,0 @@
|
||||||
require 'active_support/core_ext/string/starts_ends_with'
|
|
||||||
|
|
||||||
module ActiveSupport
|
|
||||||
module JSON
|
|
||||||
module Backends
|
|
||||||
module Yaml
|
|
||||||
ParseError = ::StandardError
|
|
||||||
extend self
|
|
||||||
|
|
||||||
EXCEPTIONS = [::ArgumentError] # :nodoc:
|
|
||||||
begin
|
|
||||||
require 'psych'
|
|
||||||
EXCEPTIONS << Psych::SyntaxError
|
|
||||||
rescue LoadError
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parses a JSON string or IO and converts it into an object
|
|
||||||
def decode(json)
|
|
||||||
if json.respond_to?(:read)
|
|
||||||
json = json.read
|
|
||||||
end
|
|
||||||
YAML.load(convert_json_to_yaml(json))
|
|
||||||
rescue *EXCEPTIONS => e
|
|
||||||
raise ParseError, "Invalid JSON string: '%s'" % json
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
# Ensure that ":" and "," are always followed by a space
|
|
||||||
def convert_json_to_yaml(json) #:nodoc:
|
|
||||||
require 'strscan' unless defined? ::StringScanner
|
|
||||||
scanner, quoting, marks, pos, times = ::StringScanner.new(json), false, [], nil, []
|
|
||||||
while scanner.scan_until(/(\\['"]|['":,\\]|\\.|[\]])/)
|
|
||||||
case char = scanner[1]
|
|
||||||
when '"', "'"
|
|
||||||
if !quoting
|
|
||||||
quoting = char
|
|
||||||
pos = scanner.pos
|
|
||||||
elsif quoting == char
|
|
||||||
if valid_date?(json[pos..scanner.pos-2])
|
|
||||||
# found a date, track the exact positions of the quotes so we can
|
|
||||||
# overwrite them with spaces later.
|
|
||||||
times << pos
|
|
||||||
end
|
|
||||||
quoting = false
|
|
||||||
end
|
|
||||||
when ":",",", "]"
|
|
||||||
marks << scanner.pos - 1 unless quoting
|
|
||||||
when "\\"
|
|
||||||
scanner.skip(/\\/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if marks.empty?
|
|
||||||
json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
|
|
||||||
ustr = $1
|
|
||||||
if ustr.start_with?('u')
|
|
||||||
char = [ustr[1..-1].to_i(16)].pack("U")
|
|
||||||
# "\n" needs extra escaping due to yaml formatting
|
|
||||||
char == "\n" ? "\\n" : char
|
|
||||||
elsif ustr == '\\'
|
|
||||||
'\\\\'
|
|
||||||
else
|
|
||||||
ustr
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
left_pos = [-1].push(*marks)
|
|
||||||
right_pos = marks << scanner.pos + scanner.rest_size
|
|
||||||
output = []
|
|
||||||
left_pos.each_with_index do |left, i|
|
|
||||||
scanner.pos = left.succ
|
|
||||||
chunk = scanner.peek(right_pos[i] - scanner.pos + 1)
|
|
||||||
if ActiveSupport.parse_json_times
|
|
||||||
# overwrite the quotes found around the dates with spaces
|
|
||||||
while times.size > 0 && times[0] <= right_pos[i]
|
|
||||||
chunk.insert(times.shift - scanner.pos - 1, '! ')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
chunk.gsub!(/\\([\\\/]|u[[:xdigit:]]{4})/) do
|
|
||||||
ustr = $1
|
|
||||||
if ustr.start_with?('u')
|
|
||||||
char = [ustr[1..-1].to_i(16)].pack("U")
|
|
||||||
# "\n" needs extra escaping due to yaml formatting
|
|
||||||
char == "\n" ? "\\n" : char
|
|
||||||
elsif ustr == '\\'
|
|
||||||
'\\\\'
|
|
||||||
else
|
|
||||||
ustr
|
|
||||||
end
|
|
||||||
end
|
|
||||||
output << chunk
|
|
||||||
end
|
|
||||||
output = output * " "
|
|
||||||
|
|
||||||
output.gsub!(/\\\//, '/')
|
|
||||||
output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def valid_date?(date_string)
|
|
||||||
begin
|
|
||||||
date_string =~ DATE_REGEX && DateTime.parse(date_string)
|
|
||||||
rescue ArgumentError
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
require 'active_support/core_ext/module/attribute_accessors'
|
require 'active_support/core_ext/module/attribute_accessors'
|
||||||
require 'active_support/core_ext/module/delegation'
|
require 'active_support/core_ext/module/delegation'
|
||||||
|
require 'multi_json'
|
||||||
|
|
||||||
module ActiveSupport
|
module ActiveSupport
|
||||||
# Look for and parse json strings that look like ISO 8601 times.
|
# Look for and parse json strings that look like ISO 8601 times.
|
||||||
mattr_accessor :parse_json_times
|
mattr_accessor :parse_json_times
|
||||||
|
|
||||||
module JSON
|
module JSON
|
||||||
# Listed in order of preference.
|
|
||||||
DECODERS = %w(Yajl Yaml)
|
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_reader :parse_error
|
def decode(json, options ={})
|
||||||
delegate :decode, :to => :backend
|
data = MultiJson.decode(json, options)
|
||||||
|
if ActiveSupport.parse_json_times
|
||||||
def backend
|
convert_dates_from(data)
|
||||||
set_default_backend unless defined?(@backend)
|
|
||||||
@backend
|
|
||||||
end
|
|
||||||
|
|
||||||
def backend=(name)
|
|
||||||
if name.is_a?(Module)
|
|
||||||
@backend = name
|
|
||||||
else
|
else
|
||||||
require "active_support/json/backends/#{name.to_s.downcase}"
|
data
|
||||||
@backend = ActiveSupport::JSON::Backends::const_get(name)
|
|
||||||
end
|
end
|
||||||
@parse_error = @backend::ParseError
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def engine
|
||||||
|
MultiJson.engine
|
||||||
|
end
|
||||||
|
alias :backend :engine
|
||||||
|
|
||||||
|
def engine=(name)
|
||||||
|
MultiJson.engine = name
|
||||||
|
end
|
||||||
|
alias :backend= :engine=
|
||||||
|
|
||||||
def with_backend(name)
|
def with_backend(name)
|
||||||
old_backend, self.backend = backend, name
|
old_backend, self.backend = backend, name
|
||||||
yield
|
yield
|
||||||
|
@ -35,15 +34,26 @@ module ActiveSupport
|
||||||
self.backend = old_backend
|
self.backend = old_backend
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_default_backend
|
private
|
||||||
DECODERS.find do |name|
|
|
||||||
|
def convert_dates_from(data)
|
||||||
|
case data
|
||||||
|
when nil
|
||||||
|
nil
|
||||||
|
when DATE_REGEX
|
||||||
begin
|
begin
|
||||||
self.backend = name
|
DateTime.parse(data)
|
||||||
true
|
rescue ArgumentError
|
||||||
rescue LoadError
|
data
|
||||||
# Try next decoder.
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
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
|
||||||
|
|
|
@ -56,12 +56,9 @@ class TestJSONDecoding < ActiveSupport::TestCase
|
||||||
%q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}
|
%q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}
|
||||||
}
|
}
|
||||||
|
|
||||||
# load the default JSON backend
|
backends = [:ok_json]
|
||||||
ActiveSupport::JSON.backend = 'Yaml'
|
backends << :json_gem if defined?(::JSON)
|
||||||
|
backends << :yajl if defined?(::Yajl)
|
||||||
backends = %w(Yaml)
|
|
||||||
backends << "JSONGem" if defined?(::JSON)
|
|
||||||
backends << "Yajl" if defined?(::Yajl)
|
|
||||||
|
|
||||||
backends.each do |backend|
|
backends.each do |backend|
|
||||||
TESTS.each do |json, expected|
|
TESTS.each do |json, expected|
|
||||||
|
@ -85,7 +82,7 @@ class TestJSONDecoding < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_failed_json_decoding
|
def test_failed_json_decoding
|
||||||
assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({: 1})) }
|
assert_raise(MultiJson::DecodeError) { ActiveSupport::JSON.decode(%({: 1})) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue