Sujet : Re: how to create a simple closure to create validators
De : mark (at) *nospam* qtrac.eu (Mark Summerfield)
Groupes : comp.lang.tclDate : 21. Jun 2024, 10:43:00
Autres entêtes
Message-ID : <RJ-dnbImWOe51uj7nZ2dnZfqnPWdnZ2d@brightview.co.uk>
References : 1 2
User-Agent : Pan/0.154 (Izium; 517acf4)
On Thu, 20 Jun 2024 11:59:38 -0700, et99 wrote:
On 6/20/2024 12:59 AM, Mark Summerfield wrote:
I can make a variable that has a specific validator quite easily using
trace add.
But I can't work out how to create a validator maker (i.e., a simple
closure).
I am using Tcl/Tk 9.0b2.
Here is the code:
#!/usr/bin/env tclsh9
proc valid_percent {varname elemname op} {
upvar 1 $varname var if {$op eq "write"} {
if {$var < 0} {
set var 0
} elseif {$var > 100} {
set var 100
}
}
}
proc check {expected actual} {
if {$expected != $actual} {
puts "ERROR $expected != $actual"
} else {
puts "OK $expected == $actual"
}
}
trace add variable percent write valid_percent
set percent 50 check 50 $percent set percent -5 check 0 $percent set
percent 492 check 100 $percent
# All the above works correctly; what's below fails with:
# can't read "min": no such variable
proc clamper {min max} {
proc clamp {varname elemname op} {
upvar 1 $varname var if {$op eq "write"} {
if {$var < $min} {
set var $min
} elseif {$var > $max} {
set var $max
}
}
}
return clamp
}
trace add variable score write [clamper 0 20]
set score 15 check 15 $score set score -5 check 0 $score set score 25
check 20 $score
Here's how I might do this:
proc validateRange {min max name1 name2 op} {
if { $name2 eq "" } { ;# scalar
upvar 1 $name1 newValue if { $newValue < $min } {
set newValue $min
} elseif { $newValue > $max } {
set newValue $max
}
} else { ;# array - left as exercise for reader
}
}
trace add variable my_percent write {validateRange 0 20 }
set my_percent 10 puts "my_percent= |$my_percent| was 10"
set my_percent 50 puts "my_percent= |$my_percent| was 50"
set my_percent -50 puts "my_percent= |$my_percent| was -50"
trace add variable my_percent100 write {validateRange 5 100 }
set my_percent100 10 puts "my_percent100= |$my_percent100| was 10"
set my_percent100 500 puts "my_percent100= |$my_percent100| was 500"
set my_percent100 -50 puts "my_percent100= |$my_percent100| was -50"
output:
my_percent= |10| was 10 my_percent= |20| was 50 my_percent= |0| was -50
my_percent100= |10| was 10 my_percent100= |100| was 500 my_percent100=
|5| was -50
Ah, get that, v. clever. In the end I used this simple variation:
proc clamp {min max varname elemname op} {
upvar 1 $varname var
if {$op eq "write"} {
if {$var < $min} {
set var $min
} elseif {$var > $max} {
set var $max
}
}
}
trace add variable score write {clamp 0 20}
Thank you.