From 4f178616784e701a7b93586556ffbf292dd173aa Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 10 Sep 2018 08:33:11 +0000 Subject: Tests and docs --- doc/define.n | 64 +++++++++++++++++++++++++++++++++++++++++++++++---- tests/oo.test | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/doc/define.n b/doc/define.n index 6353d00..1030096 100644 --- a/doc/define.n +++ b/doc/define.n @@ -426,7 +426,7 @@ Some of the configurable definitions of a class or object are \fIslotted definitions\fR. This means that the configuration is implemented by a slot object, that is an instance of the class \fBoo::Slot\fR, which manages a list of values (class names, variable names, etc.) that comprises the contents of -the slot. The class defines three operations (as methods) that may be done on +the slot. The class defines five operations (as methods) that may be done on the slot: .TP \fIslot\fR \fB\-append\fR ?\fImember ...\fR? @@ -437,6 +437,16 @@ This appends the given \fImember\fR elements to the slot definition. . This sets the slot definition to the empty list. .TP +\fIslot\fR \fB\-prepend\fR ?\fImember ...\fR? +.VS TIP516 +This prepends the given \fImember\fR elements to the slot definition. +.VE TIP516 +.TP +\fIslot\fR \fB\-remove\fR ?\fImember ...\fR? +.VS TIP516 +This removes the given \fImember\fR elements from the slot definition. +.VE TIP516 +.TP \fIslot\fR \fB\-set\fR ?\fImember ...\fR? . This replaces the slot definition with the given \fImember\fR elements. @@ -454,15 +464,53 @@ and these methods which provide the implementation interface: .TP \fIslot\fR \fBGet\fR . -Returns a list that is the current contents of the slot. This method must +Returns a list that is the current contents of the slot, but does not modify +the slot. This method must always be called from a stack frame created by a +call to \fBoo::define\fR or \fBoo::objdefine\fR. This method \fIshould not\fR +return an error unless it is called from outside a definition context or with +the wrong number of arguments. +.RS +.PP +.VS TIP516 +The elements of the list should be fully resolved, if that is a meaningful +concept to the slot. +.VE TIP516 +.RE +.TP +\fIslot\fR \fBResolve\fR \fIelementList\fR +.VS TIP516 +Returns a list that is the elements of \fIelementList\fR with a resolution +operation applied to each of them, but does not modify the slot. For slots of +simple strings, this is an operation that does nothing. For slots of classes, +this maps each class name to its fully qualified class name. This method must always be called from a stack frame created by a call to \fBoo::define\fR or -\fBoo::objdefine\fR. +\fBoo::objdefine\fR. This method \fIshould not\fR return an error unless it +is called from outside a definition context or with the wrong number of +arguments. +.RS +.PP +Implementations \fIshould not\fR reorder or filter elements in this operation; +uniqueness and ordering constraints should be enforced in the \fBSet\fR +method. This is because this method is not normally presented with the full +contents of the slot (except via the \fB\-set\fR slot operation). +.RE +.VE TIP516 .TP \fIslot\fR \fBSet \fIelementList\fR . Sets the contents of the slot to the list \fIelementList\fR and returns the empty string. This method must always be called from a stack frame created by -a call to \fBoo::define\fR or \fBoo::objdefine\fR. +a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an +error if it rejects the change to the slot contents (e.g., because of invalid +values) as well as if it is called from outside a definition context or with +the wrong number of arguments. +.RS +.PP +This method \fImay\fR reorder and filter the elements if this is necessary in +order to satisfy the underlying constraints of the slot. (For example, slots +of classes enforce a uniqueness constraint that places each element in the +earliest location in the slot that it can.) +.RE .PP The implementation of these methods is slot-dependent (and responsible for accessing the correct part of the class or object definition). Slots also have @@ -470,6 +518,14 @@ an unknown method handler to tie all these pieces together, and they hide their \fBdestroy\fR method so that it is not invoked inadvertently. It is \fIrecommended\fR that any user changes to the slot mechanism be restricted to defining new operations whose names start with a hyphen. +.PP +.VS TIP516 +Most slot operations will initially \fBResolve\fR their argument list, combine +it with the results of the \fBGet\fR method, and then \fBSet\fR the result. +Some operations omit one or both of the first two steps; omitting the third +would result in an idempotent read-only operation (but the standard mechanism +for reading from slots is via \fBinfo class\fR and \fBinfo object\fR). +.VE TIP516 .SH EXAMPLES This example demonstrates how to use both forms of the \fBoo::define\fR and \fBoo::objdefine\fR commands (they work in the same way), as well as diff --git a/tests/oo.test b/tests/oo.test index 2dc9e2a..1093f8d 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -13,13 +13,11 @@ if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } - # The foundational objects oo::object and oo::class are sensitive to reference # counting errors and are deallocated only when an interp is deleted, so in # this test suite, interp creation and interp deletion are often used in # leaktests in order to leverage this sensitivity. - testConstraint memory [llength [info commands memory]] if {[testConstraint memory]} { proc getbytes {} { @@ -3838,6 +3836,11 @@ proc SampleSlotSetup script { lappend ops [info level] Set $lst return } + method Resolve {lst} { + variable ops + lappend ops [info level] Resolve $lst + return $lst + } } } append script0 \n$script @@ -3872,7 +3875,7 @@ test oo-32.3 {TIP 380: slots - class test} -setup [SampleSlotSetup { [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} -}] -result {0 {} {a b c g h i} {1 Get 1 Set {a b c g h i}}} +}] -result {0 {} {a b c g h i} {1 Resolve {g h i} 1 Get 1 Set {a b c g h i}}} test oo-32.4 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { @@ -3880,7 +3883,7 @@ test oo-32.4 {TIP 380: slots - class test} -setup [SampleSlotSetup { [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} -}] -result {0 {} {d e f} {1 Set {d e f}}} +}] -result {0 {} {d e f} {1 Resolve {d e f} 1 Set {d e f}}} test oo-32.5 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { @@ -3888,7 +3891,23 @@ test oo-32.5 {TIP 380: slots - class test} -setup [SampleSlotSetup { [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} -}] -result {0 {} {} {d e f g h i} {1 Set {d e f} 1 Get 1 Set {d e f g h i}}} +}] -result {0 {} {} {d e f g h i} {1 Resolve {d e f} 1 Set {d e f} 1 Resolve {g h i} 1 Get 1 Set {d e f g h i}}} +test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup { + SampleSlot create sampleSlot +}] -body { + list [info level] [sampleSlot -prepend g h i] \ + [sampleSlot contents] [sampleSlot ops] +} -cleanup [SampleSlotCleanup { + rename sampleSlot {} +}] -result {0 {} {g h i a b c} {1 Resolve {g h i} 1 Get 1 Set {g h i a b c}}} +test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup { + SampleSlot create sampleSlot +}] -body { + list [info level] [sampleSlot -remove c a] \ + [sampleSlot contents] [sampleSlot ops] +} -cleanup [SampleSlotCleanup { + rename sampleSlot {} +}] -result {0 {} b {1 Resolve {c a} 1 Get 1 Set b}} test oo-33.1 {TIP 380: slots - defaulting} -setup [SampleSlotSetup { set s [SampleSlot new] @@ -3911,7 +3930,7 @@ test oo-33.3 {TIP 380: slots - defaulting} -setup [SampleSlotSetup { list [$s destroy; $s unknown] [$s contents] [$s ops] } -cleanup [SampleSlotCleanup { rename $s {} -}] -result {{} unknown {1 Set destroy 1 Set unknown}} +}] -result {{} unknown {1 Resolve destroy 1 Set destroy 1 Resolve unknown 1 Set unknown}} test oo-33.4 {TIP 380: slots - errors} -setup [SampleSlotSetup { set s [SampleSlot new] }] -body { @@ -3969,6 +3988,49 @@ test oo-34.8 {TIP 380: slots - presence} { test oo-34.9 {TIP 380: slots - presence} { getMethods oo::objdefine::variable } {{-append -clear -prepend -remove -set} {Get Set}} +test oo-34.10 {TIP 516: slots - resolution} -setup { + oo::class create parent + set result {} + oo::class create 516a { superclass parent } + oo::class create 516b { superclass parent } + oo::class create 516c { superclass parent } + namespace eval 516test { + oo::class create 516a { superclass parent } + oo::class create 516b { superclass parent } + oo::class create 516c { superclass parent } + } +} -body { + # Must find the right classes when making the mixin + namespace eval 516test { + oo::define 516a { + mixin 516b 516c + } + } + lappend result [info class mixin 516test::516a] + # Must not remove class with just simple name match + oo::define 516test::516a { + mixin -remove 516b + } + lappend result [info class mixin 516test::516a] + # Must remove class with resolved name match + oo::define 516test::516a { + mixin -remove 516test::516c + } + lappend result [info class mixin 516test::516a] + # Must remove class with resolved name match even after renaming, but only + # with the renamed name; it is a slot of classes, not strings! + rename 516test::516b 516test::516d + oo::define 516test::516a { + mixin -remove 516test::516b + } + lappend result [info class mixin 516test::516a] + oo::define 516test::516a { + mixin -remove 516test::516d + } + lappend result [info class mixin 516test::516a] +} -cleanup { + parent destroy +} -result {{::516test::516b ::516test::516c} {::516test::516b ::516test::516c} ::516test::516b ::516test::516d {}} test oo-35.1 {Bug 9d61624b3d: Empty superclass must not cause crash} -setup { oo::class create fruit { -- cgit v0.12