# HG changeset patch # User Claus Gittinger # Date 1139915134 -3600 # Node ID 17cc7c9aa82d0dc234de68bf7c9aad591e992872 # Parent 306e2edb75bf8b0398253ce7b2743a77cebfaa40 plugs can now inherit diff -r 306e2edb75bf -r 17cc7c9aa82d Plug.st --- a/Plug.st Mon Feb 13 09:55:37 2006 +0100 +++ b/Plug.st Tue Feb 14 12:05:34 2006 +0100 @@ -13,7 +13,7 @@ "{ Package: 'stx:libview2' }" Model subclass:#Plug - instanceVariableNames:'simulatedProtocol' + instanceVariableNames:'simulatedProtocol inheritedClasses' classVariableNames:'' poolDictionaries:'' category:'Kernel-Objects' @@ -39,7 +39,9 @@ " A Plug is an object which simulates a protocol and evaluates a corresponding block when receiving messages. - A plugs interface can be changed dynamically. + A plug's interface can be changed dynamically. + A plug can also be told to simulate inheriting messages from other classes, + even multiple inheritance is possible. Its main use is for the demo doIts, to play the role of a model, when no actual modelClass is available for the demonstration. @@ -60,55 +62,73 @@ examples " + a simple plug: [exBegin] - |plug| + |plug| - plug := Plug new. - plug respondTo:#foo with:[Transcript showCR:'received foo']. - plug respondTo:#foo: with:[:arg | Transcript showCR:'received foo: ', arg printString]. + plug := Plug new. + plug respondTo:#foo with:[Transcript showCR:'Plug received foo']. + plug respondTo:#foo: with:[:arg | Transcript showCR:'Plug received foo: ', arg printString]. - plug foo. - plug foo:'some argument' + plug foo. + plug foo:'some argument' [exEnd] using a plug as a generator (simulates a readStream): [exBegin] - |generator num| + |generator num| - num := 0. - generator := Plug new. - generator respondTo:#next - with:[num := num + 1. num]. - generator respondTo:#atEnd - with:[false]. + num := 0. + generator := Plug new. + generator respondTo:#next with:[num := num + 1. num]. + generator respondTo:#atEnd with:[false]. - 10 timesRepeat:[ - Transcript showCR:(generator next) - ] + 10 timesRepeat:[ + Transcript showCR:(generator next) + ] [exEnd] simulating ``instance variables'': (actually, this is somewhat expensive - the contexts locals are used for them ...) be careful with unintended variable sharing (if plugs are created in a loop ..) [exBegin] - |plug1 plug2 local1 local2| + |plug1 plug2 local1 local2| + + plug1 := Plug new. + plug1 respondTo:#get with:[local1]. + plug1 respondTo:#set: with:[:arg | local1 := arg]. - plug1 := Plug new. - plug1 respondTo:#get with:[local1]. - plug1 respondTo:#set: with:[:arg | local1 := arg]. + plug2 := Plug new. + plug2 respondTo:#get with:[local2]. + plug2 respondTo:#set: with:[:arg | local2 := arg]. + + Transcript show:'plug1''s value: '; showCR:plug1 get. + Transcript show:'plug2''s value: '; showCR:plug2 get. + + plug1 set:5. + plug2 set:17. - plug2 := Plug new. - plug2 respondTo:#get with:[local2]. - plug2 respondTo:#set: with:[:arg | local2 := arg]. + Transcript show:'plug1''s value: '; showCR:plug1 get. + Transcript show:'plug2''s value: '; showCR:plug2 get. + [exEnd] + + simulating a big list in a ListView + (real applications would read the lines from a database or file): + [exBegin] + |virtualList top lv| - Transcript show:'plug1''s value: '; showCR:plug1 get. - Transcript show:'plug2''s value: '; showCR:plug2 get. + virtualList := Plug new. + virtualList inheritFrom:SequenceableCollection. + virtualList respondTo:#size with:[ 1000000 ]. + virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ]. - plug1 set:5. - plug2 set:17. + top := StandardSystemView extent:200@200. - Transcript show:'plug1''s value: '; showCR:plug1 get. - Transcript show:'plug2''s value: '; showCR:plug2 get. + lv := ScrollableView for:ListView in:top. + lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. + lv list:virtualList expandTabs:false scanForNonStrings:false includesNonStrings:false. + + top open. [exEnd] " ! ! @@ -153,14 +173,30 @@ |block| block := simulatedProtocol at:(aMessage selector) ifAbsent:[]. - block isNil ifTrue:[ - ^ super doesNotUnderstand:aMessage + block notNil ifTrue:[ + ^ block valueWithArguments:(aMessage arguments) ]. - ^ block valueWithArguments:(aMessage arguments) + inheritedClasses notNil ifTrue:[ + inheritedClasses do:[:eachClass | + |method| + + method := eachClass lookupMethodFor:(aMessage selector). + method notNil ifTrue:[ + ^ method valueWithReceiver:self arguments:(aMessage arguments). + ]. + ]. + ]. + ^ super doesNotUnderstand:aMessage "Modified: 27.4.1996 / 16:15:34 / cg" ! +size + "catch this one - its so common" + + ^ self doesNotUnderstand:(Message selector:#size arguments:#()) +! + update:something with:aParameter from:changedObject "catch unhandled messages by looking in my simulated protocol definition; if there is some block for it, return its value. @@ -222,6 +258,21 @@ "Created: 27.4.1996 / 16:19:08 / cg" ! +inheritFrom:aClass + "very tricky - change the inheritance. + This cannot be done by changing my class directly, because the instance layout + must still be correct for Plugs instance variables. + Therefore, the inheritance is remembered, and done dynamically in the doesNotUnderstand + implementation." + + self assert:(aClass instSize == 0). + inheritedClasses isNil ifTrue:[ + inheritedClasses := Array with:aClass + ] ifFalse:[ + inheritedClasses := inheritedClasses copyWith:aClass + ]. +! + respondTo:aSelector with:aBlock "tell the receiver to respond to a message given by selector, with evaluating aBlock. The number of arguments as defined by the @@ -269,5 +320,5 @@ !Plug class methodsFor:'documentation'! version - ^ '$Header: /cvs/stx/stx/libview2/Plug.st,v 1.21 2005-05-04 08:16:17 cg Exp $' + ^ '$Header: /cvs/stx/stx/libview2/Plug.st,v 1.22 2006-02-14 11:05:34 cg Exp $' ! !