This class implements the JSON parser that is used to parse a JSON string into a Ruby data structure.
Methods
Constants
STRING | = | /"((?:[^"\\]|\\.)*)"/ |
INTEGER | = | /-?\d+/ |
FLOAT | = | /-?\d+\.(\d*)(?i:e[+-]?\d+)?/ |
OBJECT_OPEN | = | /\{/ |
OBJECT_CLOSE | = | /\}/ |
ARRAY_OPEN | = | /\[/ |
ARRAY_CLOSE | = | /\]/ |
PAIR_DELIMITER | = | /:/ |
COLLECTION_DELIMITER | = | /,/ |
TRUE | = | /true/ |
FALSE | = | /false/ |
NULL | = | /null/ |
IGNORE | = | %r( (?: //[^\n\r]*[\n\r]| # line comments /\* # c-style comments (?: [^*/]| # normal chars /[^*]| # slashes that do not start a nested comment \*[^/]| # asterisks that do not end this comment /(?=\*/) # single slash before this comment's end )* \*/ # the end of this comment |\s+ # whitespaces )+ )mx |
UNPARSED | = | Object.new |
Public Instance methods
Parses the current JSON string and returns the complete data structure as a result.
[ show source ]
# File lib/facets/more/json.rb, line 213 def parse reset until eos? case when scan(ARRAY_OPEN) return parse_array when scan(OBJECT_OPEN) return parse_object when skip(IGNORE) ; when !((value = parse_value).equal? UNPARSED) return value else raise ParserError, "source '#{peek(20)}' not in JSON!" end end end
Private Instance methods
[ show source ]
# File lib/facets/more/json.rb, line 283 def parse_array result = [] until eos? case when (value = parse_value) != UNPARSED result << value skip(IGNORE) unless scan(COLLECTION_DELIMITER) or match?(ARRAY_CLOSE) raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!" end when scan(ARRAY_CLOSE) break when skip(IGNORE) ; else raise ParserError, "unexpected token in array at '#{peek(20)}'!" end end result end
[ show source ]
# File lib/facets/more/json.rb, line 304 def parse_object result = {} until eos? case when (string = parse_string) != UNPARSED skip(IGNORE) unless scan(PAIR_DELIMITER) raise ParserError, "expected ':' in object at '#{peek(20)}'!" end skip(IGNORE) unless (value = parse_value).equal? UNPARSED result[string] = value skip(IGNORE) unless scan(COLLECTION_DELIMITER) or match?(OBJECT_CLOSE) raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!" end else raise ParserError, "expected value in object at '#{peek(20)}'!" end when scan(OBJECT_CLOSE) if klassname = result['json_class'] klass = klassname.sub(/^:+/, '').split(/::/).inject(Object) do |p,k| p.const_get(k) rescue nil end break unless klass and klass.json_creatable? result = klass.json_create(result) end break when skip(IGNORE) ; else raise ParserError, "unexpected token in object at '#{peek(20)}'!" end end result end
[ show source ]
# File lib/facets/more/json.rb, line 233 def parse_string if scan(STRING) return '' if self[1].empty? self[1].gsub(/\\(?:[\\bfnrt"]|u([A-Fa-f\d]{4}))/) do case $~[0] when '\\\\' then '\\' when '\\b' then "\b" when '\\f' then "\f" when '\\n' then "\n" when '\\r' then "\r" when '\\t' then "\t" when '\\"' then '"' else if JSON.support_unicode? and $KCODE == 'UTF8' JSON.utf16_to_utf8($~[1]) else # if utf8 mode is switched off or unicode not supported, try to # transform unicode \u-notation to bytes directly: $~[1].to_i(16).chr end end end else UNPARSED end end
[ show source ]
# File lib/facets/more/json.rb, line 260 def parse_value case when scan(FLOAT) Float(self[0]) when scan(INTEGER) Integer(self[0]) when scan(TRUE) true when scan(FALSE) false when scan(NULL) nil when (string = parse_string) != UNPARSED string when scan(ARRAY_OPEN) parse_array when scan(OBJECT_OPEN) parse_object else UNPARSED end end