6 class ParseError
< StandardError
10 # Converts a JSON string into a Ruby object.
12 YAML
.load(convert_json_to_yaml(json
))
13 rescue ArgumentError
=> e
14 raise ParseError
, "Invalid JSON string"
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})?)?)$/
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]
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
41 marks
<< scanner
.pos
- 1 unless quoting
46 json
.gsub(/\\([\\\/]|u
[[:xdigit:]]{4})/) do
48 if ustr
.starts_with
?('u')
49 [ustr
[1..-1].to_i(16)].pack("U")
57 left_pos
= [-1].push(*marks
)
58 right_pos
= marks
<< scanner
.pos
+ scanner
.rest_size
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
64 if ustr
.starts_with
?('u')
65 [ustr
[1..-1].to_i(16)].pack("U")
75 times
.each
{ |i
| output
[i-1
] = ' ' }
76 output
.gsub
!(/\\\//, '/')