Decode json strings as Dates/Times if they're using a YAML-compatible format. Closes #9614 [Rick]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7613 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Rick Olson 2007-09-24 17:41:55 +00:00
parent 911ea2f26f
commit 2a60093fa3
3 changed files with 29 additions and 8 deletions

View File

@ -1,5 +1,7 @@
*SVN* *SVN*
* Decode json strings as Dates/Times if they're using a YAML-compatible format. Closes #9614 [Rick]
* Fixed cache_page to use the request url instead of the routing options when picking a save path #8614 [josh] * Fixed cache_page to use the request url instead of the routing options when picking a save path #8614 [josh]
* Object.subclasses_of includes anonymous subclasses. [Jeremy Kemper] * Object.subclasses_of includes anonymous subclasses. [Jeremy Kemper]

View File

@ -15,17 +15,26 @@ module ActiveSupport
end end
protected protected
# matches YAML-formatted dates
DATE_REGEX = /^\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?$/
# Ensure that ":" and "," are always followed by a space # Ensure that ":" and "," are always followed by a space
def convert_json_to_yaml(json) #:nodoc: def convert_json_to_yaml(json) #:nodoc:
scanner, quoting, marks = StringScanner.new(json), false, [] scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, []
while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/) while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
case char = scanner[1] case char = scanner[1]
when '"', "'" when '"', "'"
if !quoting if !quoting
quoting = char quoting = char
pos = scanner.pos
elsif quoting == char 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 quoting = false
end end
when ":","," when ":",","
@ -37,7 +46,11 @@ module ActiveSupport
json json
else else
ranges = ([0] + marks.map(&:succ)).zip(marks + [json.length]) ranges = ([0] + marks.map(&:succ)).zip(marks + [json.length])
ranges.map { |(left, right)| json[left..right] }.join(" ") output = ranges.collect! { |(left, right)| json[left..right] }.join(" ")
times.each do |pos|
output[pos-1] = ' '
end
output
end end
end end
end end

View File

@ -8,8 +8,14 @@ class TestJSONDecoding < Test::Unit::TestCase
%({"returnTo":{"/categories":1}}) => {"returnTo" => {"/categories" => 1}}, %({"returnTo":{"/categories":1}}) => {"returnTo" => {"/categories" => 1}},
%({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
%({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
%({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
%({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
%({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
%({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
# no time zone
%({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
# needs to be *exact*
%({a: " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
%([]) => [], %([]) => [],
%({}) => {}, %({}) => {},
%(1) => 1, %(1) => 1,