|
Class: Plug
Object
|
+--Model
|
+--Plug
- Package:
- stx:libview2
- Category:
- Kernel-Objects
- Version:
- rev:
1.30
date: 2021/04/27 18:51:47
- user: cg
- file: Plug.st directory: libview2
- module: stx stc-classLibrary: libview2
A Plug is an object which simulates a protocol and evaluates
a corresponding block when receiving messages.
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.
However, it can be used wherever some object is needed which responds to
some protocol AND you do not want to add a class for it
(lightWeight objects, mock objects, proxies, wrappers etc.).
There is a slight performance penalty - compared to `normal' objects,
getting `normal' messages, though.
[caveat:]
The name 'plug' was chosen because instances can be 'plugged' in anywhere.
That name was invented way before the name 'mock' became popular;
nowadays, it would probably be called 'PluggableMock'...
copyrightCOPYRIGHT (c) 1995 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
instance creation
-
new
-
(comment from inherited method)
return an instance of myself without indexed variables
initialization
-
privateInitialize
-
this method is NOT called `#initialize' to allow plugging that
selector ...
message sending
-
at: key
-
catch this one - its so common
-
at: key ifAbsent: exceptionValue
-
catch this one - its so common
-
at: key put: value
-
(comment from inherited method)
store the 2nd arg, anObject as indexed instvar with index, anInteger.
this method can be redefined in subclasses. Returns anObject (sigh)
-
doesNotUnderstand: aMessage
-
catch unhandled messages by looking in my simulated protocol
definition; if there is some block for it, return its value.
Otherwise, fall into the real doesNotUnderstand error.
-
isSequenceable
-
return true, if the receiver is some kind of sequenceableCollection,
i.e. if its elements are accessible by at:/at:put: and an integer index,
and support the do:-protocol.
-
size
-
catch this one - its so common
-
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.
Otherwise, fall into the real update.
-
value
-
catch this one - its so common
-
value: arg
-
catch this one - its so common
protocol definition
-
forgetAbout: aSelector
-
tell the receiver to forget about how to respond to the given by selector
Usage example(s):
|p|
p := Plug new.
p respondTo:#foo with:[Transcript showCR:'foo'].
p respondTo:#foo: with:[:arg | Transcript show:'foo:'; showCR:arg].
p foo.
p foo:'hello'.
p forgetAbout:#foo.
p foo.
|
-
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.
-
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
selector must match the number of blockArsg expected by the block.
The value returned from aBlock will be the value returned from the
message.
Usage example(s):
|p|
p := Plug new.
p respondTo:#foo with:[Transcript showCR:'foo'].
p respondTo:#foo: with:[:arg | Transcript show:'foo:'; showCR:arg].
p foo.
p foo:'hello'
|
queries
-
respondsTo: aSelector
-
return true, if the receiver responds to a message
a simple plug:
|plug|
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'
|
using a plug as a generator (simulates a readStream):
|generator num|
num := 0.
generator := Plug new.
generator respondTo:#next with:[num := num + 1. num].
generator respondTo:#atEnd with:[false].
10 timesRepeat:[
Transcript showCR:(generator next)
]
|
simulating a big collection:
|virtualList|
virtualList := Plug new.
virtualList inheritFrom:SequenceableCollection.
virtualList respondTo:#size with:[ 1000000 ].
virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ].
virtualList inspect.
|
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 ..)
|plug1 plug2 local1 local2|
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.
Transcript show:'plug1''s value: '; showCR:plug1 get.
Transcript show:'plug2''s value: '; showCR:plug2 get.
|
simulating a big list in a ListView
(real applications would read the lines from a database or file):
|virtualList top lv|
virtualList := Plug new.
virtualList inheritFrom:SequenceableCollection.
virtualList respondTo:#size with:[ 1000000 ].
virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ].
top := StandardSystemView extent:200@200.
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.
|
|