diff options
Diffstat (limited to 'activesupport/lib')
4 files changed, 33 insertions, 227 deletions
diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb deleted file mode 100644 index 533ba25da3..0000000000 --- a/activesupport/lib/active_support/json/backends/jsongem.rb +++ /dev/null @@ -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 diff --git a/activesupport/lib/active_support/json/backends/yajl.rb b/activesupport/lib/active_support/json/backends/yajl.rb deleted file mode 100644 index 58818658c7..0000000000 --- a/activesupport/lib/active_support/json/backends/yajl.rb +++ /dev/null @@ -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 diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb deleted file mode 100644 index e25e29d36b..0000000000 --- a/activesupport/lib/active_support/json/backends/yaml.rb +++ /dev/null @@ -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 - diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index c1f6330c6c..ac99f180a5 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -1,32 +1,31 @@ require 'active_support/core_ext/module/attribute_accessors' require 'active_support/core_ext/module/delegation' +require 'multi_json' module ActiveSupport # Look for and parse json strings that look like ISO 8601 times. mattr_accessor :parse_json_times module JSON - # Listed in order of preference. - DECODERS = %w(Yajl Yaml) - class << self - attr_reader :parse_error - delegate :decode, :to => :backend + def decode(json, options ={}) + data = MultiJson.decode(json, options) + if ActiveSupport.parse_json_times + convert_dates_from(data) + else + data + end + end - def backend - set_default_backend unless defined?(@backend) - @backend + def engine + MultiJson.engine end + alias :backend :engine - def backend=(name) - if name.is_a?(Module) - @backend = name - else - require "active_support/json/backends/#{name.to_s.downcase}" - @backend = ActiveSupport::JSON::Backends::const_get(name) - end - @parse_error = @backend::ParseError + def engine=(name) + MultiJson.engine = name end + alias :backend= :engine= def with_backend(name) old_backend, self.backend = backend, name @@ -35,15 +34,26 @@ module ActiveSupport self.backend = old_backend end - def set_default_backend - DECODERS.find do |name| + private + + def convert_dates_from(data) + case data + when nil + nil + when DATE_REGEX begin - self.backend = name - true - rescue LoadError - # Try next decoder. - false + 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 |