aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/json/decoding.rb
blob: 60003a94e53fbd4aa2cb242eba336dfd3a20b9f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
require 'yaml'
require 'strscan'

module ActiveSupport
  module JSON
    class ParseError < StandardError
    end
    
    class << 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:
          scanner, quoting, marks = StringScanner.new(json), false, []

          while scanner.scan_until(/(['":,]|\\.)/)
            case char = scanner[1]
            when '"', "'"
              quoting = quoting == char ? false : char
            when ":", ","
              marks << scanner.pos - 1 unless quoting
            end
          end
          
          if marks.empty?
            json
          else
            ranges = ([0] + marks.map(&:succ)).zip(marks + [json.length])
            ranges.map { |(left, right)| json[left..right] }.join(" ")
          end
        end  
    end
  end
end