Index: library/nx/nx.tcl =================================================================== diff -u -r65d13b7b37bf2ee5dabe0392eb1e7af3a0cc85fe -r83355de2812519cf29dc92cfdc2fc4892303f6ab --- library/nx/nx.tcl (.../nx.tcl) (revision 65d13b7b37bf2ee5dabe0392eb1e7af3a0cc85fe) +++ library/nx/nx.tcl (.../nx.tcl) (revision 83355de2812519cf29dc92cfdc2fc4892303f6ab) @@ -2130,17 +2130,36 @@ set args [list obj var [:namedParameterSpec {} value $options]] :public object method value=set $args {::nsf::var::set $obj $var $value} } - if {[:isMultivalued] && [:info lookup method value=add] eq "::nsf::classes::nx::VariableSlot::value=add"} { - set slotObj "slot=[::nsf::self]" - # lappend options_single slot=[::nsf::self] - if {$slotObj ni $options_single} {lappend options_single $slotObj} - set vspec [:namedParameterSpec {} value $options_single] - set addArgs [list obj prop $vspec {pos 0}] - :public object method value=add $addArgs {::nsf::next [list $obj $prop $value $pos]} - set delArgs [list obj prop -nocomplain:switch $vspec] - :public object method value=delete $delArgs {::nsf::next [list $obj $prop -nocomplain=$nocomplain $value]} - } else { - # TODO should we deactivate add/delete? + + if {[:isMultivalued]} { + set baseMethods [lmap m {value=add value=delete} { + set mh [:info lookup method $m] + if {[string match "::nsf::classes::nx::VariableSlot::*" $mh]} { + set m + } else { + continue + } + }] + + if {[llength $baseMethods]} { + set slotObj "slot=[::nsf::self]" + # lappend options_single slot=[::nsf::self] + if {$slotObj ni $options_single} {lappend options_single $slotObj} + set vspec [:namedParameterSpec {} value $options_single] + if {"value=add" in $baseMethods} { + set addArgs [list obj prop $vspec {pos 0}] + :public object method value=add $addArgs {::nsf::next [list $obj $prop $value $pos]} + } + + if {"value=delete" in $baseMethods} { + set delArgs [list obj prop -nocomplain:switch $vspec] + :public object method value=delete $delArgs \ + {::nsf::next [list $obj $prop -nocomplain=$nocomplain $value]} + } + } else { + # TODO should we deactivate add/delete? + } + } } @@ -2300,6 +2319,9 @@ } ::nx::VariableSlot public method value=delete {obj prop -nocomplain:switch value} { + if {![:isMultivalued]} { + return -code error "property $prop of [set :domain] is not multivalued" + } set old [::nsf::var::get $obj $prop] set p [lsearch -glob $old $value] if {$p > -1} { Index: tests/accessor.test =================================================================== diff -u -r226d979a835578dbde618f73c37b22f65dafd238 -r83355de2812519cf29dc92cfdc2fc4892303f6ab --- tests/accessor.test (.../accessor.test) (revision 226d979a835578dbde618f73c37b22f65dafd238) +++ tests/accessor.test (.../accessor.test) (revision 83355de2812519cf29dc92cfdc2fc4892303f6ab) @@ -6,80 +6,228 @@ nx::test configure -count 1 nx::test case setter-variants { - nx::Class create C { - :property {p1a 1} - :property {p1b 1} { - :public object method value=set {obj prop value} { - nx::var::set $obj $prop [incr value] - } - } - :property -accessor public {p2a 2} - :property -accessor public {p2b 2} { - :public object method value=set {obj prop value} { - nx::var::set $obj $prop [incr value] - } - } + nx::Class create C { + :property {p1a 1} + :property {p1b 1} { + :public object method value=set {obj prop value} { + nx::var::set $obj $prop [incr value] + } + } + :property -accessor public {p2a 2} + :property -accessor public {p2b 2} { + :public object method value=set {obj prop value} { + nx::var::set $obj $prop [incr value] + } + } - :property -incremental {p3a 3} - :property -incremental {p3b 3} { - :public object method value=set {obj prop value} { - nx::var::set $obj $prop [incr value] - } - } + :property -incremental {p3a 3} + :property -incremental {p3b 3} { + :public object method value=set {obj prop value} { + nx::var::set $obj $prop [incr value] + } + } - :create c1 + :create c1 + } + + puts [C info method definition p1a] + ? {c1 cget -p1a} 1 + ? {c1 configure -p1a 1} "" + + puts [C info method definition p1b] + ? {c1 cget -p1b} 2 + ? {c1 configure -p1b 3} "" + ? {c1 cget -p1b} 4 + + puts [C info method definition p2a] + ? {c1 cget -p2a} 2 + ? {c1 p2a get} 2 + ? {c1 configure -p2a 2} "" + ? {c1 p2a set 2} 2 + ? {c1 p2a unset} "" + ? {c1 cget -p2a} {can't read "p2a": no such variable} + ? {c1 p2a unset} {can't unset "p2a": no such variable} + ? {c1 p2a unset -nocomplain} "" + + puts [C info method definition p2b] + ? {c1 cget -p2b} 3 + ? {c1 p2b get} 3 + ? {c1 configure -p2b 2} "" + ? {c1 p2b set 2} 3 + ? {c1 p2b unset} "" + ? {c1 cget -p2b} {can't read "p2b": no such variable} + + puts [C info method definition p3a] + + ? {c1 cget -p3a} 3 + ? {c1 p3a get} 3 + ? {c1 configure -p3a 3} "" + ? {c1 p3a get 3} {invalid argument '3', maybe too many arguments; should be "value=get ?-array? ?-notrace? /object/ /varName/"} + ? {c1 p3a set 3} 3 + ? {c1 p3a unset} "" + ? {c1 cget -p3a} {can't read "p3a": no such variable} + + puts [C info method definition p3b] + + ? {c1 cget -p3b} 4 + ? {c1 p3b get} 4 + ? {c1 configure -p3b 4} "" + ? {c1 p3b get} 5 + ? {c1 p3b set 4} 5 + ? {c1 p3b get} 5 + ? {c1 p3b set 4} 5 + ? {c1 p3b get} 5 + + ? {c1 p3b unset} "" + ? {c1 cget -p3b} {can't read "p3b": no such variable} + +} + +nx::test case incremental-slot-override-wo-type { + nx::Class create C { + :property -accessor public c1a + :property -incremental c1b + :property -incremental c1c { + :public object method value=set {obj args} { + $obj eval [list lappend :trace [nx::current method]] + next + } + :public object method value=add {obj args} { + $obj eval [list lappend :trace [nx::current method]] + next + } + :public object method value=delete {obj args} { + $obj eval [list lappend :trace [nx::current method]] + next + } } - puts [C info method definition p1a] - ? {c1 cget -p1a} 1 - ? {c1 configure -p1a 1} "" + :create c2 + } - puts [C info method definition p1b] - ? {c1 cget -p1b} 2 - ? {c1 configure -p1b 3} "" - ? {c1 cget -p1b} 4 + # WITHOUT incremental being set: add + delete from base class are present, but CANNOT be called; + set slotObj1 [c2 info lookup variables c1a] + foreach m {value=set value=add value=delete value=get value=unset value=exists} { + ? [list $slotObj1 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? {c2 c1a add 0} "property c1a of ::C is not multivalued" + ? {c2 c1a delete 0} "property c1a of ::C is not multivalued" - puts [C info method definition p2a] - ? {c1 cget -p2a} 2 - ? {c1 p2a get} 2 - ? {c1 configure -p2a 2} "" - ? {c1 p2a set 2} 2 - ? {c1 p2a unset} "" - ? {c1 cget -p2a} {can't read "p2a": no such variable} - ? {c1 p2a unset} {can't unset "p2a": no such variable} - ? {c1 p2a unset -nocomplain} "" + # WITH incremental being set: add + delete from base class are present, and CAN be called; + set slotObj2 [c2 info lookup variables c1b] + foreach m {value=set value=add value=delete value=get value=unset value=exists} { + ? [list $slotObj2 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? {c2 c1b add 1} "1" + ? {c2 c1b get} "1" + ? {c2 c1b delete 1} "" + ? {c2 c1b get} "" + ? {c2 c1b unset} "" - puts [C info method definition p2b] - ? {c1 cget -p2b} 3 - ? {c1 p2b get} 3 - ? {c1 configure -p2b 2} "" - ? {c1 p2b set 2} 3 - ? {c1 p2b unset} "" - ? {c1 cget -p2b} {can't read "p2b": no such variable} + # WITH incremental being set: add + delete from slot are present, override base methods, and CAN be called; + set slotObj3 [c2 info lookup variables c1c] + foreach m {value=set value=add value=delete} { + ? [list $slotObj3 info lookup method $m] ${slotObj3}::$m + } + foreach m {value=get value=unset value=exists} { + ? [list $slotObj3 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? {c2 info vars} "" + ? {c2 c1c add 1} "1" + ? {c2 c1c get} "1" + ? {c2 c1c delete 1} "" + ? {c2 c1c get} "" + ? {c2 c1c unset} "" + ? {c2 info vars} "trace" + ? {c2 eval {expr {"value=add" in ${:trace}}}} 1 + ? {c2 eval {expr {"value=delete" in ${:trace}}}} 1 + ? {c2 eval {expr {"value=set" in ${:trace}}}} 0 - puts [C info method definition p3a] + +} - ? {c1 cget -p3a} 3 - ? {c1 p3a get} 3 - ? {c1 configure -p3a 3} "" - ? {c1 p3a get 3} {invalid argument '3', maybe too many arguments; should be "value=get ?-array? ?-notrace? /object/ /varName/"} - ? {c1 p3a set 3} 3 - ? {c1 p3a unset} "" - ? {c1 cget -p3a} {can't read "p3a": no such variable} +nx::test case incremental-slot-override-with-type { + nx::Class create C { + :property -accessor public c1a:object + :property -incremental c1b:object + :property -incremental c1c:object { + :public object method value=set {obj prop value:object args} { + $obj eval [list lappend :trace [nx::current method]] + next + } + :public object method value=add {obj prop value:object args} { + $obj eval [list lappend :trace [nx::current method]] + next + } + :public object method value=delete {obj prop value:object args} { + $obj eval [list lappend :trace [nx::current method]] + next + } + } - puts [C info method definition p3b] + :create c3 + } + + # WITHOUT incremental being set: set is overriden internally and becomes type-aware; add + delete + # from base class are present, but CANNOT be called; + set slotObj1 [c3 info lookup variables c1a] + foreach m {value=add value=delete value=get value=unset value=exists} { + ? [list $slotObj1 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? [list $slotObj1 info lookup method value=set] ${slotObj1}::value=set - ? {c1 cget -p3b} 4 - ? {c1 p3b get} 4 - ? {c1 configure -p3b 4} "" - ? {c1 p3b get} 5 - ? {c1 p3b set 4} 5 - ? {c1 p3b get} 5 - ? {c1 p3b set 4} 5 - ? {c1 p3b get} 5 + ? {c3 c1a add 0} "property c1a of ::C is not multivalued" + ? {c3 c1a delete 0} "property c1a of ::C is not multivalued" + ? {c3 c1a set 0} {expected object but got "0" for parameter "value"} + ? {c3 c1a set [c3]} [c3] + ? {c3 c1a unset} "" - ? {c1 p3b unset} "" - ? {c1 cget -p3b} {can't read "p3b": no such variable} + # WITH incremental being set: set + add + delete are overriden INTERNALLY to make them type-aware; + set slotObj2 [c3 info lookup variables c1b] + foreach m {value=set value=add value=delete} { + ? [list $slotObj2 info lookup method $m] ${slotObj2}::$m + } + foreach m {value=get value=unset value=exists} { + ? [list $slotObj2 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? {c3 c1b add 1} {expected object but got "1" for parameter "value"} + ? {c3 c1b delete 1} {expected object but got "1" for parameter "value"} + ? {c3 c1b set 1} {invalid value in "1": expected object but got "1" for parameter "value"} + ? {c3 c1b add [c3]} [c3] + ? {c3 c1b delete [c3]} "" + ? {c3 c1b get} "" + ? {c3 c1b unset} "" + + # WITH incremental being set: set + add + delete are overriden by + # the slot (Note: type-awareness must be taken care of explicitly, lost otherwise); + set slotObj3 [c3 info lookup variables c1c] + foreach m {value=set value=add value=delete} { + ? [list $slotObj3 info lookup method $m] ${slotObj3}::$m + } + foreach m {value=get value=unset value=exists} { + ? [list $slotObj3 info lookup method $m] ::nsf::classes::nx::VariableSlot::$m + } + ? {c3 info vars} "" + ? {c3 c1c add 1} {expected object but got "1" for parameter "value"} + ? {c3 c1c delete 1} {expected object but got "1" for parameter "value"} + ? {c3 c1c set 1} {expected object but got "1" for parameter "value"} + ? {c3 c1c add [c3]} [c3] + ? {c3 c1c delete [c3]} "" + ? {c3 c1c get} "" + ? {c3 c1c unset} "" + ? {c3 info vars} "trace" + + ? {c3 eval {expr {"value=add" in ${:trace}}}} 1 + ? {c3 eval {expr {"value=delete" in ${:trace}}}} 1 + ? {c3 eval {expr {"value=set" in ${:trace}}}} 0 + ? {c3 c1c set [c3]} [c3] + ? {c3 eval {expr {"value=set" in ${:trace}}}} 1 } + +# Local variables: +# mode: tcl +# tcl-indent-level: 2 +# indent-tabs-mode: nil +# End: Index: tests/properties.test =================================================================== diff -u -r13ac2740ff99a0438d547250401ac9ed981c58bf -r83355de2812519cf29dc92cfdc2fc4892303f6ab --- tests/properties.test (.../properties.test) (revision 13ac2740ff99a0438d547250401ac9ed981c58bf) +++ tests/properties.test (.../properties.test) (revision 83355de2812519cf29dc92cfdc2fc4892303f6ab) @@ -163,9 +163,11 @@ set unknowns "valid are: {assign definition destroy get getParameterSpec getPropertyDefinitionOptions onError parameter reconfigure setCheckedInstVar}" ? {c1 b add x} {property b of ::C is not multivalued} + ? {c1 b delete x} {property b of ::C is not multivalued} #? {c1 b add x} "method 'add' unknown for slot ::C::slot::b; $unknowns" ? {c1 c add x} {::c1: unable to dispatch method 'c'} ? {c1 eval {:c add x}} {property c of ::C is not multivalued} + ? {c1 eval {:c delete x}} {property c of ::C is not multivalued} #? {c1 eval {:c add x}} "method 'add' unknown for slot ::C::slot::c; $unknowns" ? {c1 d add x} {::c1: unable to dispatch method 'd'} ? {c1 eval {:d add x}} {::c1: unable to dispatch method 'd'} @@ -178,9 +180,11 @@ ? {c1 va add x} {::c1: unable to dispatch method 'va'} ? {c1 vb add x} {property vb of ::C is not multivalued} + ? {c1 vb delete x} {property vb of ::C is not multivalued} #? {c1 vb add x} "method 'add' unknown for slot ::C::slot::vb; $unknowns" ? {c1 vc add x} {::c1: unable to dispatch method 'vc'} ? {c1 eval {:vc add x}} {property vc of ::C is not multivalued} + ? {c1 eval {:vc delete x}} {property vc of ::C is not multivalued} #? {c1 eval {:vc add x}} "method 'add' unknown for slot ::C::slot::vc; $unknowns" ? {c1 vd add x} {::c1: unable to dispatch method 'vd'} ? {c1 eval {:vd add x}} {::c1: unable to dispatch method 'vd'}