From 52fe5ef61693c921ec8582c49e4112918cff6ffb Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sun, 4 Oct 2015 22:51:13 -0400 Subject: [PATCH] change ordered keyword to dicttype keyword; this provides more flexibility, and avoids the pseudo-dependency on DataStructures that was causing precompile problems --- README.md | 19 +++++++++++-------- src/JSON.jl | 8 ++++---- src/Parser.jl | 37 +++++++++++-------------------------- test/runtests.jl | 2 +- 4 files changed, 27 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 05f12a4..3f338dd 100644 --- a/README.md +++ b/README.md @@ -52,15 +52,18 @@ json(a::Any) Returns a compact JSON representation as an `AbstractString`. ```julia -JSON.parse(s::AbstractString; ordered=false) -JSON.parse(io::IO; ordered=false) -JSON.parsefile(filename::AbstractString; ordered=false, use_mmap=true) +JSON.parse(s::AbstractString; dicttype=Dict) +JSON.parse(io::IO; dicttype=Dict) +JSON.parsefile(filename::AbstractString; dicttype=Dict, use_mmap=true) ``` Parses a JSON `AbstractString` or IO stream into a nested Array or Dict. -If `ordered=true` is specified, JSON objects are parsed into -`OrderedDicts`, which maintains the insertion order of the items in -the object. (*) - -(*) Requires the `DataStructures.jl` package to be installed. +The `dicttype` indicates the dictionary type (`<: Associative`) that +JSON objects are parsed to. It defaults to `Dict` (the built-in Julia +dictionary), but a different type can be passed to, for example, +provide a desired ordering. For example, if you `import DataStructures` +(assuming the [DataStructures +package](https://github.com/JuliaLang/DataStructures.jl) is +installed), you can pass `dicttype=DataStructures.OrderedDict` to +maintain the insertion order of the items in the object. diff --git a/src/JSON.jl b/src/JSON.jl index 24cb112..4bf38dc 100644 --- a/src/JSON.jl +++ b/src/JSON.jl @@ -253,7 +253,7 @@ function consumeString(io::IO, obj::IOBuffer) throw(EOFError()) end -function parse(io::IO; ordered::Bool=false) +function parse{T<:Associative}(io::IO; dicttype::Type{T}=Dict) open_bracket = close_bracket = nothing try open_bracket, close_bracket = determine_bracket_type(io) @@ -278,14 +278,14 @@ function parse(io::IO; ordered::Bool=false) consumeString(io, obj) end end - JSON.parse(takebuf_string(obj), ordered=ordered) + JSON.parse(takebuf_string(obj); dicttype=dicttype) end -function parsefile(filename::AbstractString; ordered::Bool=false, use_mmap=true) +function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict, use_mmap=true) sz = filesize(filename) open(filename) do io s = use_mmap ? UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readall(io) - JSON.parse(s, ordered=ordered) + JSON.parse(s; dicttype=dicttype) end end diff --git a/src/Parser.jl b/src/Parser.jl index 060d3af..084454e 100644 --- a/src/Parser.jl +++ b/src/Parser.jl @@ -2,16 +2,6 @@ module Parser #JSON using Compat -#Define ordered dictionary from DataStructures if present -function __init__() - global _HAVE_DATASTRUCTURES = try - @eval import DataStructures.OrderedDict - true - catch - false - end -end - const TYPES = Any # Union{Dict, Array, AbstractString, Number, Bool, Void} # Types it may encounter const KEY_TYPES = AbstractString # Union{AbstractString} # Types it may encounter as object keys @@ -77,13 +67,13 @@ end # PARSING -function parse_array{T<:AbstractString}(ps::ParserState{T}, ordered::Bool) +function parse_array{T<:AbstractString}(ps::ParserState{T}, dictT::Type) incr(ps) # Skip over the '[' _array = TYPES[] chomp_space(ps) charat(ps)==']' && (incr(ps); return _array) # Check for empty array while true # Extract values from array - v = parse_value(ps, ordered) # Extract value + v = parse_value(ps, dictT) # Extract value push!(_array, v) # Eat up trailing whitespace chomp_space(ps) @@ -101,15 +91,11 @@ function parse_array{T<:AbstractString}(ps::ParserState{T}, ordered::Bool) return _array end -function parse_object{T<:AbstractString}(ps::ParserState{T}, ordered::Bool) - if ordered - parse_object(ps, ordered, OrderedDict{KEY_TYPES,TYPES}()) - else - parse_object(ps, ordered, Dict{KEY_TYPES,TYPES}()) - end +function parse_object{T<:AbstractString}(ps::ParserState{T}, dictT::Type) + parse_object(ps, dictT, dictT{KEY_TYPES,TYPES}()) end -function parse_object{T<:AbstractString}(ps::ParserState{T}, ordered::Bool, obj) +function parse_object{T<:AbstractString}(ps::ParserState{T}, dictT::Type, obj) incr(ps) # Skip over opening '{' chomp_space(ps) charat(ps)=='}' && (incr(ps); return obj) # Check for empty object @@ -117,7 +103,7 @@ function parse_object{T<:AbstractString}(ps::ParserState{T}, ordered::Bool, obj) chomp_space(ps) _key = parse_string(ps) # Key skip_separator(ps) - _value = parse_value(ps, ordered) # Value + _value = parse_value(ps, dictT) # Value obj[_key] = _value # Building object chomp_space(ps) c = charat(ps) # Find the next pair or end of object @@ -213,7 +199,7 @@ function parse_simple{T<:AbstractString}(ps::ParserState{T}) ret end -function parse_value{T<:AbstractString}(ps::ParserState{T}, ordered::Bool) +function parse_value{T<:AbstractString}(ps::ParserState{T}, dictT::Type) chomp_space(ps) (ps.s > ps.e) && return nothing # Nothing left @@ -221,11 +207,11 @@ function parse_value{T<:AbstractString}(ps::ParserState{T}, ordered::Bool) if ch == '"' ret = parse_string(ps) elseif ch == '{' - ret = parse_object(ps, ordered) + ret = parse_object(ps, dictT) elseif (ch >= '0' && ch <= '9') || ch=='-' || ch=='+' ret = parse_number(ps) elseif ch == '[' - ret = parse_array(ps, ordered) + ret = parse_array(ps, dictT) elseif ch == 'f' || ch == 't' || ch == 'n' ret = parse_simple(ps) else @@ -315,12 +301,11 @@ function parse_number{T<:AbstractString}(ps::ParserState{T}) end end -function parse(str::AbstractString; ordered::Bool=false) +function parse{T<:Associative}(str::AbstractString; dicttype::Type{T}=Dict) pos::Int = 1 len::Int = endof(str) len < 1 && return - ordered && !_HAVE_DATASTRUCTURES && error("DataStructures package required for ordered parsing: try `Pkg.add(\"DataStructures\")`") - parse_value(ParserState(str, pos, len), ordered) + parse_value(ParserState(str, pos, len), dicttype) end end #module Parser diff --git a/test/runtests.jl b/test/runtests.jl index a138512..03e246b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,7 +5,7 @@ import DataStructures include(joinpath(dirname(@__FILE__),"json_samples.jl")) -@test JSON.parse("{\"x\": 3}"; ordered = true) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)]) +@test JSON.parse("{\"x\": 3}", dicttype=DataStructures.OrderedDict) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)]) # Test definitions ------- validate_c(c) = begin