Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/activesupport/lib/active_support/json/decoding.rb

Revision 8505, 2.1 kB (checked in by rick, 9 months ago)

remove multiple enumerations from ActiveSupport::JSON#convert_json_to_yaml when dealing with date/time values. [rick]

Line 
1 require 'yaml'
2 require 'strscan'
3
4 module ActiveSupport
5   module JSON
6     class ParseError < StandardError
7     end
8    
9     class << self
10       # Converts a JSON string into a Ruby object.
11       def decode(json)
12         YAML.load(convert_json_to_yaml(json))
13       rescue ArgumentError => e
14         raise ParseError, "Invalid JSON string"
15       end
16      
17       protected
18         # matches YAML-formatted dates
19         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})?)?$/
20
21         # Ensure that ":" and "," are always followed by a space
22         def convert_json_to_yaml(json) #:nodoc:
23           scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, []
24           while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
25             case char = scanner[1]
26             when '"', "'"
27               if !quoting
28                 quoting = char
29                 pos = scanner.pos
30               elsif quoting == char
31                 if json[pos..scanner.pos-2] =~ DATE_REGEX
32                   # found a date, track the exact positions of the quotes so we can remove them later.
33                   # oh, and increment them for each current mark, each one is an extra padded space that bumps
34                   # the position in the final yaml output
35                   total_marks = marks.size
36                   times << pos+total_marks << scanner.pos+total_marks
37                 end
38                 quoting = false
39               end
40             when ":",","
41               marks << scanner.pos - 1 unless quoting
42             end
43           end
44
45           if marks.empty?
46             json.gsub(/\\\//, '/')
47           else
48             left_pos  = [-1].push(*marks)
49             right_pos = marks << json.length
50             output    = []
51             left_pos.each_with_index do |left, i|
52               output << json[left.succ..right_pos[i]]
53             end
54             output = output * " "
55            
56             times.each { |i| output[i-1] = ' ' }
57             output.gsub!(/\\\//, '/')
58             output
59           end
60         end
61     end
62   end
63 end
Note: See TracBrowser for help on using the browser.