--- 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 $'
! !