~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/activesupport/lib/active_support/json/backends/yaml.rb

  • Committer: Michael Forrest
  • Date: 2010-10-15 16:28:50 UTC
  • Revision ID: michael.forrest@canonical.com-20101015162850-tj2vchanv0kr0dun
refrozeĀ gems

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'active_support/core_ext/string/starts_ends_with'
 
2
 
 
3
module ActiveSupport
 
4
  module JSON
 
5
    module Backends
 
6
      module Yaml
 
7
        ParseError = ::StandardError
 
8
        extend self
 
9
 
 
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
          # Ensure that ":" and "," are always followed by a space
 
19
          def convert_json_to_yaml(json) #:nodoc:
 
20
            require 'strscan' unless defined? ::StringScanner
 
21
            scanner, quoting, marks, pos, times = ::StringScanner.new(json), false, [], nil, []
 
22
            while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
 
23
              case char = scanner[1]
 
24
              when '"', "'"
 
25
                if !quoting
 
26
                  quoting = char
 
27
                  pos = scanner.pos
 
28
                elsif quoting == char
 
29
                  if json[pos..scanner.pos-2] =~ DATE_REGEX
 
30
                    # found a date, track the exact positions of the quotes so we can remove them later.
 
31
                    # oh, and increment them for each current mark, each one is an extra padded space that bumps
 
32
                    # the position in the final YAML output
 
33
                    total_marks = marks.size
 
34
                    times << pos+total_marks << scanner.pos+total_marks
 
35
                  end
 
36
                  quoting = false
 
37
                end
 
38
              when ":",","
 
39
                marks << scanner.pos - 1 unless quoting
 
40
              when "\\"
 
41
                scanner.skip(/\\/)
 
42
              end
 
43
            end
 
44
 
 
45
            if marks.empty?
 
46
              json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
 
47
                ustr = $1
 
48
                if ustr.start_with?('u')
 
49
                  [ustr[1..-1].to_i(16)].pack("U")
 
50
                elsif ustr == '\\'
 
51
                  '\\\\'
 
52
                else
 
53
                  ustr
 
54
                end
 
55
              end
 
56
            else
 
57
              left_pos  = [-1].push(*marks)
 
58
              right_pos = marks << scanner.pos + scanner.rest_size
 
59
              output    = []
 
60
              left_pos.each_with_index do |left, i|
 
61
                scanner.pos = left.succ
 
62
                output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
 
63
                  ustr = $1
 
64
                  if ustr.start_with?('u')
 
65
                    [ustr[1..-1].to_i(16)].pack("U")
 
66
                  elsif ustr == '\\'
 
67
                    '\\\\'
 
68
                  else
 
69
                    ustr
 
70
                  end
 
71
                end
 
72
              end
 
73
              output = output * " "
 
74
 
 
75
              times.each { |i| output[i-1] = ' ' }
 
76
              output.gsub!(/\\\//, '/')
 
77
              output
 
78
            end
 
79
          end
 
80
      end
 
81
    end
 
82
  end
 
83
end
 
84