Metakit backend for tie

CMcC 20050303 - a backend for the tie tcllib package. Persists an array in a metakit.

In conjunction with the remote array backend, this might have similar functionality to tequila

 package provide mktie 1.0
 
 package require Mk4tcl
 package require tie
 package require snit
 
 snit::type mktie {
     option -var ""     ;# variable name in metakit
     option -vtype S    ;# set the variable value type
     option -layout {}  ;# additional layout elements
 
     constructor {args} {
        foreach {name val} [::cmdline::getKnownOptions args [subst {
            {var.arg [list $options(-var)]
                "variable name"}
            {vtype.arg [list $options(-vtype)]
                "variable type"}
            {layout.arg [list $options(-layout)]
                "addiditional elements of metakit layout"}
        }]] {
            set options(-$name) $val
        }
        if {$options(-var) eq ""} {
            # no variable name supplied - use the caller's name
            upvar 3 avar rv     ;# skip some snit nesting
            #puts stderr "using $rv"
            set options(-var) $rv
        }
        #puts stderr "$self - [array get options]"
        set layout [concat [list name text:$options(-vtype)] $options(-layout)]
        mk::view layout tqs.$options(-var) $layout
     }
 
     # return a list containing the names of all keys found in the metakit
     method names {} {
         mk::loop c tqs.$options(-var) {
             lappend result [mk::get $c name]
         }
     }
 
     # return an integer number specifying the number of keys found in the metakit
     method size {} {
        return [mk::view size tqs.$options(-var)]
     }
 
     # return  a dictionary containing the data found in the metakit
     method get {} {
        set dict [dict create]
        mk::loop c tqs.$options(-var) {
            set val [mk::get $c name text]
            #puts stderr "get $options(-var)(\#$c) - $val"
            dict set dict {*}$val
        }
        return $dict
     }
 
     # takes a dictionary and adds its contents to the metakit
     method set {dict} {
        dict for {key value} $dict {
            $self setv $key $value
        }
     }
 
     # removes all elements whose keys match pattern
     method unset {pattern} {
        set matches [mk::select tqs.$options(-var) -glob name $pattern]
        foreach n [lsort -integer -decreasing $matches] {
            mk::row delete tqs.$options(-var)!$n
        }
     }
 
     # save value under key
     method setv {key value} {
        set n [mk::select tqs.$options(-var) name $key]
        if {[llength $n] == 0} {
            set n [mk::view size tqs.$options(-var)]
        } elseif {[mk::get tqs.$options(-var)!$n text] == $value} {
            return ;# no change, ignore
        }
        #puts stderr "set $options(-var)($key) to $value / $n"
        mk::set tqs.$options(-var)!$n name $key text $value
     }
 
     # remove the value under key
     method unsetv {key} {
         set n [mk::select tqs.$options(-var) name $key]
         if {[llength $n] == 0} {
            error "can't unset \"$options(-var)($key)\": no such element in array"
            return
         }
         mk::row delete tqs.$options(-var)!$n
     }
 
     # return the value for key
     method getv {key} {
         set n [mk::select tqs.$options(-var) name $key]
         if {[llength $n] == 0} {
            error "can't read \"$options(-var)($key)\": no such element in array"
            return
         }
         return [mk::get tqs.$options(-var)!$n text]
     }
 }
 
 mk::file open tqs tie.dat -nocommit
 ::tie::register ::mktie as metakit
 
 if {[info script] eq $argv0} {
     unset -nocomplain av
     array set av {}
     tie::tie av metakit
     set av(x) blah
     array set av {a 1 b 2 c 3 z 26}
     ::tie::untie av
 
     puts "second pass"
     unset av
     array set av {}
     tie::tie av metakit
     puts [array size av]
     puts [array get av]
 }