Documentation generated from fossil trunk
huddle -
Create and manipulate huddle object
package require Tcl 8.4 package require huddle ? 0.1.5 ? huddle create key value ? key value ... ? huddle list ? value value ... ? huddle get object key ? key ... ? huddle gets object key ? key ... ? huddle set objectVar key ? key ... ? value huddle remove object key ? key ... ? huddle combine object1 object2 ? object3 ... ? huddle equal object1 object2 huddle append objectVar key value ? key value ... ? huddle append objectVar value ? value ... ? huddle keys object huddle llength object huddle type object ? key key... ? huddle strip object huddle jsondump object ? offset ? ? newline ? ? begin_offset ? huddle compile spec data huddle isHuddle object huddle checkHuddle object huddle to_node object ? tag ? huddle wrap tag src huddle call tag command args huddle addType callback callback command ? args ? setting get_sub src key strip src set src key value remove src key value
Huddle provides a generic Tcl-based serialization/intermediary format. Currently, each node is wrapped in a tag with simple type information.
When converting huddle-notation to other serialization formats like JSON or YAML this type information is used to select the proper notation. And when going from JSON/YAML/... to huddle their notation can be used to select the proper huddle type.
In that manner huddle can serve as a common intermediary format.
huddle-format: > {HUDDLE {huddle-node}} huddle-node: > {tag content} each content of tag means: s: (content is a) string L: list, each sub node is a huddle-node D: dict, each sub node is a huddle-node confirmed: - JSON - YAML(generally, but cannot discribe YAML-tags) limitation: - cannot discribe aliases from a node to other node.
The huddle package returns data as a Tcl dict. Either the dict package or Tcl 8.5 is required for use.
% set aa [huddle create a b c d] HUDDLE {D {a {s b} c {s d}}} % set bb [huddle create a k l m] HUDDLE {D {a {s k} l {s m}}} % huddle combine $aa $bb HUDDLE {D {a {s k} c {s d} l {s m}}}
% set aa [huddle create a b c d] HUDDLE {D {a {s b} c {s d}}} % set bb [huddle create c d a b] HUDDLE {D {c {s d} a {s b}}} % huddle equal $aa $bb 1
% set aa [huddle create a b c d] HUDDLE {D {a {s b} c {s d}}} % huddle append aa a k l m HUDDLE {D {a {s k} c {s d} l {s m}}} % set bb [huddle list i j k l] HUDDLE {L {{s i} {s j} {s k} {s l}}} % huddle append bb g h i HUDDLE {L {{s i} {s j} {s k} {s l} {s g} {s h} {s i}}}
% huddle type {HUDDLE {s str}} string % huddle type {HUDDLE {L {{s a} {s b} {s c}}}} list % huddle type {HUDDLE {D {aa {s b} cc {s d}}}} cc string
# normal output has some indents. some strings are escaped. % huddle jsondump {HUDDLE {L {{L {{s i} {s baa} {s \\k} {L {{s 1.0} {s true} {s /g} {s h}}} {L {{s g}}}}} {s t}}}} [ [ "i", "baa", "\\k", [ 1.0, true, "\/g", "h" ], ["g"] ], "t" ] # stripped output % huddle jsondump {HUDDLE {D {dd {D {bb {D {a {s baa} c {s {d a}}}} cc {D {g {s h}}}}} ee {D {i {s j} k {s 1} j {s { m\a}}}}}}} "" "" {"dd": {"bb": {"a": "baa","c": "d\na"},"cc": {"g": "h"}},"ee": {"i": "j","k": 1,"j": " m\\a"}}
% huddle compile {dict * list} {a {1 2 3} b {4 5}} HUDDLE {D {a {L {{s 1} {s 2} {s 3}}} b {L {{s 4} {s 5}}}}} % huddle compile {dict * {list {dict d list}}} {a {{c 1} {d {2 2 2} e 3}} b {{f 4 g 5}}} HUDDLE {D {a {L {{D {c {s 1}}} {D {d {L {{s 2} {s 2} {s 2}}} e {s 3}}}}} b {L {{D {f {s 4} g {s 5}}}}}}}
% huddle to_node str s str % huddle to_node str !!str !!str str % huddle to_node {HUDDLE {s str}} s str % huddle to_node {HUDDLE {l {a b c}}} l {a b c}
% huddle wrap "" str HUDDLE str % huddle wrap s str HUDDLE {s str}
The definition of callback for user-type.
The callback procedure shuould reply the following subcommands.
strip must be defined at all types. get_sub must be defined at container types. set/remove shuould be defined, if you call them.
# callback sample for my-dict proc my_dict_setting {command args} { switch -- $command { setting { ; # type definition return { type dict method {create keys} tag {d child D parent} constructor create str s } # type: the type-name # method: add methods to huddle's subcommand. # "get_sub/strip/set/remove/equal/append" called by huddle module. # "strip" must be defined at all types. # "get_sub" must be defined at container types. # "set/remove/equal/append" shuould be defined, if you call them. # tag: tag definition("child/parent" word is maybe obsoleted) } get_sub { ; # get a sub-node specified by "key" from the tagged-content foreach {src key} $args break return [dict get $src $key] } strip { ; # strip from the tagged-content foreach {src nop} $args break foreach {key val} $src { lappend result $key [huddle strip $val] } return $result } set { ; # set a sub-node from the tagged-content foreach {src key value} $args break dict set src $key $value return $src } remove { ; # remove a sub-node from the tagged-content foreach {src key value} $args break return [dict remove $src $key] } equal { ; # check equal for each node foreach {src1 src2} $args break if {[llength $src1] != [llength $src2]} {return 0} foreach {key1 val1} $src1 { if {![dict exists $src2 $key1]} {return 0} if {![huddle _equal_subs $val1 [dict get $src2 $key1]]} {return 0} } return 1 } append { ; # append nodes foreach {str src list} $args break if {[llength $list] % 2} {error {wrong # args: should be "huddle append objvar ?key value ...?"}} set resultL $src foreach {key value} $list { if {$str ne ""} { lappend resultL $key [huddle to_node $value $str] } else { lappend resultL $key $value } } return [eval dict create $resultL] } create { ; # $args: all arguments after "huddle create" if {[llength $args] % 2} {error {wrong # args: should be "huddle create ?key value ...?"}} set resultL {} foreach {key value} $args { lappend resultL $key [huddle to_node $value] } return [huddle wrap D $resultL] } keys { foreach {src nop} $args break return [dict keys [lindex [lindex $src 1] 1]] } default { error "$command is not callback for dict" } } }
# inheritance sample from default dict-callback proc ::yaml::_huddle_mapping {command args} { switch -- $command { setting { ; # type definition return { type dict method {mapping} tag {!!map parent} constructor mapping str !!str } } mapping { ; # $args: all arguments after "huddle mapping" if {[llength $args] % 2} {error {wrong # args: should be "huddle mapping ?key value ...?"}} set resultL {} foreach {key value} $args { lappend resultL $key [huddle to_node $value !!str] } return [huddle wrap !!map $resultL] } default { ; # devolving to default dict-callback return [huddle call D $command $args] } } }
You can add huddle-node types e.g. ::struct::tree. To do so, first, define a callback-procedure for additional tagged-type. The proc get argments as command and ? args ? . It has some switch-sections.
And, addType subcommand will called.
huddle addType my_dict_setting
# create as a dict % set bb [huddle create a b c d] HUDDLE {D {a {s b} c {s d}}} # create as a list % set cc [huddle list e f g h] HUDDLE {L {{s e} {s f} {s g} {s h}}} % set bbcc [huddle create bb $bb cc $cc] HUDDLE {D {bb {D {a {s b} c {s d}}} cc {L {{s e} {s f} {s g} {s h}}}}} % set folding [huddle list $bbcc p [huddle list q r] s] HUDDLE {L {{D {bb {D {a {s b} c {s d}}} cc {L {{s e} {s f} {s g} {s h}}}}} {s p} {L {{s q} {s r}}} {s s}}} # normal Tcl's notation % huddle strip $folding {bb {a b c d} cc {e f g h}} p {q r} s # get a sub node % huddle get $folding 0 bb HUDDLE {D {a {s b} c {s d}}} % huddle gets $folding 0 bb a b c d # overwrite a node % huddle set folding 0 bb c kkk HUDDLE {L {{D {bb {D {a {s b} c {s kkk}}} cc {L {{s e} {s f} {s g} {s h}}}}} {s p} {L {{s q} {s r}}} {s s}}} # remove a node % huddle remove $folding 2 1 HUDDLE {L {{D {bb {D {a {s b} c {s kkk}}} cc {L {{s e} {s f} {s g} {s h}}}}} {s p} {L {{s q}}} {s s}}} % huddle strip $folding {bb {a b c kkk} cc {e f g h}} p {q r} s # dump as a JSON stream % huddle jsondump $folding [ { "bb": { "a": "b", "c": "kkk" }, "cc": [ "e", "f", "g", "h" ] }, "p", [ "q", "r" ], "s" ]
now printing.
yaml
huddle, yaml, json, text processing, parsing, data exchange, exchange format