-
-
Save zliang-min/1506851 to your computer and use it in GitHub Desktop.
Stupid simple JSON parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'strscan' | |
require 'forwardable' | |
# Stupid JSON parser. Only handles well-formed JSON. | |
# Otherwise, it may go into an endless loop. | |
class Parser | |
WSP = /\s+/ | |
OBJ = /[{\[]/ | |
NUM = /-?\d+(\.\d+)?([eE][+-]?\d+)?/ | |
BOL = /(?:true|false)\b/ | |
NUL = /null\b/ | |
extend Forwardable | |
attr_reader :scanner | |
alias_method :s, :scanner | |
private :s | |
def_delegators :scanner, :scan, :matched | |
def initialize data | |
@scanner = StringScanner.new data.to_s | |
end | |
def space | |
scan WSP | |
end | |
def parse | |
space | |
object | |
end | |
def object | |
case scan(OBJ) | |
when '{' then hash | |
when '[' then array | |
end | |
end | |
def value | |
object or string or | |
(scan(NUM) || scan(BOL)) ? eval(matched) : | |
scan(NUL) && nil | |
end | |
def hash | |
current = {} | |
space | |
until scan /\}/ | |
key = string | |
scan /\s*:\s*/ | |
current[key] = value | |
scan /\s*,\s*/ or space | |
end | |
current | |
end | |
def array | |
current = [] | |
space | |
until scan /\]/ | |
current << value | |
scan /\s*,\s*/ or space | |
end | |
current | |
end | |
def string | |
if str = scan(/"/) | |
begin; str << s.scan_until(/"/); end while s.pre_match[-1,1] == '\\' | |
eval str | |
end | |
end | |
end | |
if __FILE__ == $0 | |
require 'test/unit' | |
class ParserTest < Test::Unit::TestCase | |
PARSED = Parser.new(DATA.read).parse | |
def parsed() PARSED end | |
def test_string | |
assert_equal "Pagination library for \"Rails 3\", Sinatra, Merb, DataMapper, and more", | |
parsed['head']['repository']['description'] | |
end | |
def test_hash | |
assert_equal %w[label ref repository sha user], parsed['head'].keys.sort | |
end | |
def test_number | |
assert_equal 124.3e2, parsed['head']['repository']['size'] | |
end | |
def test_bool | |
assert_equal true, parsed['head']['repository']['fork'] | |
assert_equal false, parsed['head']['repository']['private'] | |
end | |
def test_bool | |
assert_nil parsed['head']['user']['company'] | |
end | |
def test_array | |
assert_equal ["4438f", {"a" => "b"}], parsed['head']['sha'] | |
end | |
end | |
end | |
__END__ | |
{ | |
"head": { | |
"ref": "master", | |
"repository": { | |
"forks": 0, | |
"integrate_branch": "rails3", | |
"watchers": 1, | |
"language": "Ruby", | |
"description": "Pagination library for \"Rails 3\", Sinatra, Merb, DataMapper, and more", | |
"has_downloads": true, | |
"fork": true, | |
"created_at": "2011/10/24 03:20:48 -0700", | |
"homepage": "http://github.com/mislav/will_paginate/wikis", | |
"size": 124.3e2, | |
"private": false, | |
"has_wiki": true, | |
"name": "will_paginate", | |
"owner": "dbackeus", | |
"url": "https://github.com/dbackeus/will_paginate", | |
"has_issues": false, | |
"open_issues": 0, | |
"pushed_at": "2011/10/25 05:44:05 -0700" | |
}, | |
"label": "dbackeus:master", | |
"sha": ["4438f", { "a" : "b" }], | |
"user": { | |
"name": "David Backeus", | |
"company": null, | |
"gravatar_id": "ebe96524f5db9e92188f0542dc9d1d1a", | |
"location": "Stockholm (Sweden)", | |
"type": "User", | |
"login": "dbackeus" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment