Install with:
]add StructC14N
This package exports the canonicalize
function which allows canonicalization of structures and named tuples according to a template structure or named tuple.
The signature is as follows:
canonicalize(template, input)
template
can be either a structure or a named tuple. Return value has the same type as template
. input
can be a structure, a named tuple or a tuple. In the latter case the tuple must contains the same number of items as the template
.
Type ? canonicalize
in the REPL to see the documentation for individual methods.
-
output keys are the same as in
template
; -
if
input
contains less items thantemplate
, the default values intemplate
will be used to fill unspecified values; -
output default values are determined as follows:
- if
template
is a named tuple and if one of its value is a TypeT
, the corresponding default value isMissing
; - if
template
is not a named tuple, or if one of its value is of TypeT
, the corresponging default value is the value itself;
- if
-
output default values are overridden by values in
input
if a key ininput
is the same, or it is an unambiguous abbreviation, of one of the keys intemplate
; -
output override occurs regardless of the order of items in
template
andinput
; -
if a key in
input
is not an abbreviation of the keys intemplate
, or if the abbreviation is ambiguous, an error is raised; -
values in output are deep copied from
input
, and converted to the appropriate type. If conversion is not possible an error is raised.
using StructC14N
# Create a template
template = (xrange=NTuple{2,Number},
yrange=NTuple{2,Number},
title="A string")
# Create input named tuple...
nt = (xr=(1,2), tit="Foo")
# Dump canonicalized version
dump(canonicalize(template, nt))
will result in
NamedTuple{(:xrange, :yrange, :title),Tuple{Tuple{Int64,Int64},Missing,String}}
xrange: Tuple{Int64,Int64}
1: Int64 1
2: Int64 2
yrange: Missing missing
title: String "Foo"
One of the main use of canonicalize
is to call functions using abbreviated keyword names (i.e. it can be used as a replacement for AbbrvKW.jl). Consider the following function:
function Foo(; OptionalKW::Union{Missing,Bool}=missing, Keyword1::Int=1,
AnotherKeyword::Float64=2.0, StillAnotherOne=3, KeyString::String="bar")
@show OptionalKW
@show Keyword1
@show AnotherKeyword
@show StillAnotherOne
@show KeyString
end
The only way to use the keywords is to type their entire names, resulting in very long code lines, i.e.:
Foo(Keyword1=10, AnotherKeyword=20.0, StillAnotherOne=30, KeyString="baz")
By using canonicalize
we may re-implement the function as follows
function Foo(; kwargs...)
template = (; OptionalKW=Bool, Keyword1=1,
AnotherKeyword=2.0, StillAnotherOne=3, KeyString="bar")
kw = StructC14N.canonicalize(template; kwargs...)
@show kw.OptionalKW
@show kw.Keyword1
@show kw.AnotherKeyword
@show kw.StillAnotherOne
@show kw.KeyString
end
And call it using abbreviated keyword names:
Foo(Keyw=10, A=20.0, S=30, KeyS="baz") # Much shorter, isn't it?
A wrong abbreviation or a wrong type will result in errors:
Foo(aa=1)
Foo(Keyw="abc")
Another common use of StructC14N
is in parsing configuration files, e.g.:
configtemplate = (optStr=String,
optInt=Int,
optFloat=Float64)
# Parse a tuple
configentry = "aa, 1, 2"
c = canonicalize(configtemplate, (split(configentry, ",")...,))
# Parse a named tuple
configentry = "optFloat=20, optStr=\"aaa\", optInt=10"
c = canonicalize(configtemplate, eval(Meta.parse("($configentry)")))
# Use a custom conversion routine
function myparse(input)
if input == "ten"
return 10
end
return 1
end
configentry = "optFloat=20, optStr=\"aaa\", optInt=\"ten\""
c = canonicalize(configtemplate, eval(Meta.parse("($configentry)")), Dict(:optInt=>myparse))