-
Notifications
You must be signed in to change notification settings - Fork 0
/
TOML.jl
100 lines (91 loc) · 3.96 KB
/
TOML.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""
getTable(params::Dict,tablename::String;tableOptional::Bool=false)
Returns the table named `tablename` from the contents of a TOML file, which was
previously parsed into the dictionary `params`. If `tableOptional` is `true`
the output will be either a dictionary with the contents of the table or
`missing`. If `tableOptional` is true the function will throw an error instead
of returning missing.
"""
function getTable(params::Dict,tablename::String;tableOptional::Bool=false)
for part in split(tablename,".")
params = get(params,part,missing)
ismissing(params) & !tableOptional && throw(MissingException("Non-optional table [$(tablename)] missing in configuration file."))
end
return params
end
"""
getValue(params::Dict,tablename::String,key::Sring;valueOptional::Bool=false)
Returns a the value specified by a `key` from the table named `tablename` from
the contents of a TOML file, which was previously parsed into the dictionary
`params`. If `valueOptional` is `true` the output will be either the value or
`missing`. If `valueOptional` is true the function will throw an error instead
of returning missing.
"""
function getValue(params::Dict,tablename::String,key::String;valueOptional::Bool=false)
params = getTable(params,tablename,tableOptional=valueOptional)
if ismissing(params)
return missing
else
value = get(params,key,missing)
ismissing(value) & !valueOptional && throw(MissingException("key $(key) expected in table [$(tablename)] but missing."))
return value
end
end
"""
getType(params::Dict,tablename::String)
Tries to parse the key "type" from the table named `tablename` from the
contents of a TOML file, which was previously parsed into the dictionary
`params` into an actual julia type. Returns missing if it fails to do so, e.g.
if the key is missing in the TOML file.
"""
getType(params::Dict,tablename::String) = eval(Symbol(getValue(params,tablename,"type",valueOptional=true)))
"""
initialize(T::Type,params::Dict,floatType::Type)
Tries to initialize the type `T` from the contents of a TOML file, which was
previously parsed into the dictionary `params`. To this end all values obtained
from the TOML are converted to the type `floatType` or arrays thereof. So `T`
needs to have a suitable constructor.
"""
function initialize(T::Type,tablename::String,params::Dict,floatType::Type)
fieldNamesT = map(string,fieldnames(T))
values = map(key->getValue(params,tablename,key),fieldNamesT)
fieldValues = []
for (i,value) in enumerate(values)
TField = fieldtype(T,i)
if TField <: Integer && isprimitivetype(TField)
push!(fieldValues,TField(value))
elseif typeof(value) <: Real
push!(fieldValues,floatType(value))
elseif typeof(value) <: Array{T} where {T<:Array}
push!(fieldValues,floatType.(hcat(value...)))
elseif typeof(value) <: Array{T} where {T<:Real}
push!(fieldValues,floatType.(value))
elseif typeof(value) <: Dict{String,Any}
if length(keys(value))==1
typeName = collect(keys(value))[1]
type = eval(Symbol(typeName))
push!(fieldValues,initialize(type,typeName,value,floatType))
else
throw(ErrorException("Recursive initialization failed. Dictionariy $value expected to have a single key only."))
end
else
throw(ErrorException("I do not know how to handle value $value when trying to initialize type $T from table $tablename"))
end
end
return T(fieldValues...)
end
"""
getTableName(T::Type)
Outputs the tablename which is expected to hold the data to `initialize` the
type `T` from the contents of a TOML file.
"""
function getTableName(T::Type)
out = String[]
while T != Any
typeString = string(T)
m = match(r"^(?:\w*\.)*(\w+)", typeString)
pushfirst!(out,m.captures[1])
T = supertype(T)
end
return join(out,".")
end