Skip to content

Instantly share code, notes, and snippets.

@zliang-min
Forked from mislav/stupid-json.rb
Created December 21, 2011 17:23
Show Gist options
  • Save zliang-min/1506851 to your computer and use it in GitHub Desktop.
Save zliang-min/1506851 to your computer and use it in GitHub Desktop.
Stupid simple JSON parser
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