Tcllib's ::huddle
is a native serialization format and is part of its YAML package.
::huddle
's function is the same as of JSON or YAML; that is to augment commond data
types along with the data. When JSON or YAML get parsed into an interpretter, individual
data get represented by its native type; that is, string becomes a string, list becomes a list,
map becomes a map/hash/dictionary, etc.
In Tcl, the problem is that all these types are mostly interchangeble (which is normally considered a feature) and cannot be distinguished. That is, by de-serializing a JSON or YAML to Tcl's native representation would lose the type information that is critical for serializing the structure again.
... TODO: example
... TODO: alternatives ton
, Alternative JSON, likely more ... huddle provides type customization
Surprisingly there are not many examples besides those in Tcllib's manual.
... TODO more examples
Creating data types is as simple as calling huddle <typename> <value>
. This comes from how the huddle::addType
works, which creates an ensemble command <typename>
under the huddle namespace
. Hence creating huddle objects looks like:
# Creating scalar data types set hstring [huddle string "foo bar"] set hnum [huddle number 1.23] set hbool [huddle boolean true] set hnull [huddle null] # creating empty list set hlist [huddle list] # creating empty dict set hdict [huddle create] #set hdict [huddle dict]; # ERROR, `dict` is not an ensemble command
Creating data types using huddle compile
:
# Creating various scalar data types set hstring [huddle compile string "foo bar"] set hnum [huddle compile number 1.23] set hbool [huddle compile boolean true] set hnull [huddle compile null ""] # Note: For the `boolean` type, one can use any of the usual boolean # representations. E.g. true can be expressed as `true`, `True`, `yes`, # `1`, etc. # Creating lists set hstring_list [huddle compile list {foo bar}] set hstring_list [huddle comile {list string} {foo bar}] set hnum_list [huddle compile {list number} {1 2 3}] set hbool_list [huddle compile {list boolean} {0 0 1 0}] # Creating dictionaries # Note: The dictionary type specification (i.e. the 2nd argument to # `huddle compile <spec> <val>`) represents a map of key-type pairs, # where key is a glob pattern for keys. Normally one uses `*` for # dictionary where all values have the same type. The `<spec>` then # looks like `{dict <key1> <type1> ... <keyN> <typeN>}`. set hstring_dict [huddle compile {dict * string} {a foo b bar}] set hnum_dict [huddle compile {dict * number} {a 1 b 2 c 3}] set hbool_dict [huddle compile {dict * boolean} {a 0 b true c NO}] # Creating more complex structures set hstruct [huddle compile {list list string} {{foo bar} {a b c}}]; # list of string lists set hstruct [huddle compile {list list number} {{1 2} {1.1 1.2 1.3}}]; # list of number lists set hstruct [huddle compile {dict * {list number}} {a {1 2} b {1.1 1.2 1.3}}]; # dict of number lists set hstruct [huddle compile {dict b number c {list boolean} * string} {a "foo bar" b 1 c {0 0 1 0} d "hello world"}];
Buidling a huddle structure bottom up:
# create individual leaf types set hstring ... set hnum ... set hbool ... # create a list object set hlist {HUDDLE {L {}}}; # manually create an empty list (may use `huddle compile` or `huddle list`) huddle append hlist $hstring huddle append hlist $hnum ... huddle set hlist 1 $hstring; # overwrite the item at index 1 ... ${huddle::types(callback:L)} llength $hlist; # gets the length of `hlist` # create a dict object set hdict [huddle create]; # create an empty dict huddle append hdict a $hstring b $hnum huddle append hdict c $hlist ... huddle append hdict a $hnum; # ovewrites key `a` huddle set hdict a $hlist; # another way to overwrite key `a` ...
The following example shows how to define a custom path
type. For simplicity,
our path
is merely another string. For other examples refer to huddle.test
testsuite.
Warning
::huddle
v.0.3 has a bug in jsondump
and the following code
and the serialization would fail there. For details see tcllib's bug report
https://core.tcl-lang.org/tcllib/tktview?name=d0e1cf6be1 This has been fixed
in v.0.4.
package require huddle; namespace eval ::myspc { namespace export *; namespace eval path { variable settings; set settings { publicMethods {path} tag p isContainer no }; proc path {src} { return [::huddle::wrap [list p $src]]; } proc equal {p1 p2} { return [expr {$p1 eq $p2}]; } proc jsondump {data {offset " "} {newline "\n"} {begin ""}} { # JSON permits only oneline string set data [string map { \n \\n \t \\t \r \\r \b \\b \f \\f \\ \\\\ \" \\\" / \\/ } $data ]; return "\"$data\"" } } } # create a simple map with one string and one path set h {HUDDLE {D {str {s foo} pth {p bar}}}}; puts "\nh=$h"; huddle addType ::myspc::path puts "jsondump(h)=[huddle jsondump $h]";