1# map.tcl -- 2# Copyright (c) 2009-2019 Andreas Kupries <andreas_kupries@sourceforge.net> 3# 4# Object wrapper around array/dict. Useful as key/value store in 5# larger systems. 6# 7# Examples: 8# - configuration mgmt in doctools v2 import/export managers 9# - pt import/export managers 10# 11# Each object manages a key/value map. 12 13# ### ### ### ######### ######### ######### 14## Requisites 15 16package require Tcl 8.4 17package require snit 18 19# ### ### ### ######### ######### ######### 20## API 21 22# ATTENTION: 23## 24# From an API point of view the code below is equivalent to the much 25# shorter `snit::type struct::map { ... }`. 26# 27# Then why the more complex form ? 28# 29# When snit compiles the class to Tcl code, and later on when methods 30# are executed it will happen in the `struct` namespace. The moment 31# this package is used together with `struct::set` all unqualified 32# `set` statements will go bonkers, eiter in snit, or, here, in method 33# `set`, because they get resolved to the `struct::set` dispatcher 34# instead of `::set`. Moving the implementation a level deeper makes 35# the `struct::map` namespace the context, with no conflict. 36 37# Future / TODO: Convert all the OO stuff here over to TclOO, as much 38# as possible (snit configure/cget support is currently still better, 39# ditto hierarchical methods). 40 41namespace eval ::struct {} 42 43proc ::struct::map {args} { 44 uplevel 1 [linsert $args 0 struct::map::I] 45} 46 47snit::type ::struct::map::I { 48 49 # ### ### ### ######### ######### ######### 50 ## Options :: None 51 52 # ### ### ### ######### ######### ######### 53 ## Creating, destruction 54 55 # Default constructor. 56 # Default destructor. 57 58 # ### ### ### ######### ######### ######### 59 ## Public methods. Reading and writing the map. 60 61 method names {} { 62 return [array names mymap] 63 } 64 65 method get {} { 66 return [array get mymap] 67 } 68 69 method set {name {value {}}} { 70 # 7 instead of 3 in the condition below, because of the 4 71 # implicit arguments snit is providing to each method. 72 if {[llength [info level 0]] == 7} { 73 ::set mymap($name) $value 74 } elseif {![info exists mymap($name)]} { 75 return -code error "can't read \"$name\": no such variable" 76 } 77 return $mymap($name) 78 } 79 80 method unset {args} { 81 if {![llength $args]} { lappend args * } 82 foreach pattern $args { 83 array unset mymap $pattern 84 } 85 return 86 } 87 88 # ### ### ### ######### ######### ######### 89 ## Internal methods :: None. 90 91 # ### ### ### ######### ######### ######### 92 ## State :: Map data, Tcl array 93 94 variable mymap -array {} 95 96 ## 97 # ### ### ### ######### ######### ######### 98} 99 100# ### ### ### ######### ######### ######### 101## Ready 102 103package provide struct::map 1 104return 105