From 3c4c6bd0df598f865f49a983b4c65c415af4bcfc Mon Sep 17 00:00:00 2001 From: rick Date: Thu, 23 Apr 2009 00:08:40 -0700 Subject: * Add pluggable JSON backends with support for the JSON gem. [rick] Example: ActiveSupport::JSON.backend = "JSONGem" All internal Rails JSON encoding is now handled by ActiveSupport::JSON.encode(). Use of #to_json is not recommended, as it may clash with other libraries that overwrite it. However, you can recover Rails specific functionality if you really want to use #to_json. gem 'json' ActiveSupport::JSON.backend = "JSONGem" class ActiveRecord::Base alias to_json rails_to_json end --- .../lib/active_support/json/backends/jsongem.rb | 36 ++++++++++ .../lib/active_support/json/backends/yaml.rb | 83 ++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 activesupport/lib/active_support/json/backends/jsongem.rb create mode 100644 activesupport/lib/active_support/json/backends/yaml.rb (limited to 'activesupport/lib/active_support/json/backends') diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb new file mode 100644 index 0000000000..de847e30a3 --- /dev/null +++ b/activesupport/lib/active_support/json/backends/jsongem.rb @@ -0,0 +1,36 @@ +module ActiveSupport + module JSON + ParseError = ::JSON::ParserError + + module Backends + module JSONGem + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + 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 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/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb new file mode 100644 index 0000000000..c7db508c23 --- /dev/null +++ b/activesupport/lib/active_support/json/backends/yaml.rb @@ -0,0 +1,83 @@ +require 'active_support/core_ext/string/starts_ends_with' + +module ActiveSupport + module JSON + class ParseError < StandardError + end + + module Backends + module Yaml + extend self + + # Converts a JSON string into a Ruby object. + def decode(json) + YAML.load(convert_json_to_yaml(json)) + rescue ArgumentError => e + raise ParseError, "Invalid JSON string" + 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 json[pos..scanner.pos-2] =~ DATE_REGEX + # found a date, track the exact positions of the quotes so we can remove them later. + # oh, and increment them for each current mark, each one is an extra padded space that bumps + # the position in the final YAML output + total_marks = marks.size + times << pos+total_marks << scanner.pos+total_marks + end + quoting = false + end + when ":","," + marks << scanner.pos - 1 unless quoting + end + end + + if marks.empty? + json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + 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 + output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do + ustr = $1 + if ustr.start_with?('u') + [ustr[1..-1].to_i(16)].pack("U") + elsif ustr == '\\' + '\\\\' + else + ustr + end + end + end + output = output * " " + + times.each { |i| output[i-1] = ' ' } + output.gsub!(/\\\//, '/') + output + end + end + end + end + end +end -- cgit v1.2.3 From 53dda29f8b34073a4b135ee224c1d09c1f10de02 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Sun, 17 May 2009 10:37:30 -0500 Subject: Add support for parsing XML and JSON from an IO as well as a string [#2659 state:resolved] Signed-off-by: Joshua Peek --- activesupport/lib/active_support/json/backends/jsongem.rb | 5 ++++- activesupport/lib/active_support/json/backends/yaml.rb | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'activesupport/lib/active_support/json/backends') diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb index de847e30a3..d1a1cdd7d7 100644 --- a/activesupport/lib/active_support/json/backends/jsongem.rb +++ b/activesupport/lib/active_support/json/backends/jsongem.rb @@ -6,8 +6,11 @@ module ActiveSupport module JSONGem extend self - # Converts a JSON string into a Ruby object. + # 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) diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb index c7db508c23..1c18fc4801 100644 --- a/activesupport/lib/active_support/json/backends/yaml.rb +++ b/activesupport/lib/active_support/json/backends/yaml.rb @@ -9,8 +9,11 @@ module ActiveSupport module Yaml extend self - # Converts a JSON string into a Ruby object. + # 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 ArgumentError => e raise ParseError, "Invalid JSON string" -- cgit v1.2.3 From e89241c92fbcf68b59d9efb50c21c5040e9f3156 Mon Sep 17 00:00:00 2001 From: rick Date: Sun, 17 May 2009 19:16:11 -0700 Subject: load the JSON Backend lazily. If the JSON gem is already loaded, use the JSONGem backend by default. --- activesupport/lib/active_support/json/backends/jsongem.rb | 4 +++- activesupport/lib/active_support/json/backends/yaml.rb | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'activesupport/lib/active_support/json/backends') diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb index d1a1cdd7d7..649e6301d1 100644 --- a/activesupport/lib/active_support/json/backends/jsongem.rb +++ b/activesupport/lib/active_support/json/backends/jsongem.rb @@ -1,6 +1,8 @@ +require 'json' unless defined?(JSON) + module ActiveSupport module JSON - ParseError = ::JSON::ParserError + ParseError = ::JSON::ParserError unless const_defined?(:ParseError) module Backends module JSONGem diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb index 1c18fc4801..667016f45d 100644 --- a/activesupport/lib/active_support/json/backends/yaml.rb +++ b/activesupport/lib/active_support/json/backends/yaml.rb @@ -2,7 +2,9 @@ require 'active_support/core_ext/string/starts_ends_with' module ActiveSupport module JSON - class ParseError < StandardError + unless const_defined?(:ParseError) + class ParseError < StandardError + end end module Backends -- cgit v1.2.3