37 |
37 |
38 documentation |
38 documentation |
39 " |
39 " |
40 A Plug is an object which simulates a protocol and evaluates |
40 A Plug is an object which simulates a protocol and evaluates |
41 a corresponding block when receiving messages. |
41 a corresponding block when receiving messages. |
42 A plugs interface can be changed dynamically. |
42 A plug's interface can be changed dynamically. |
|
43 A plug can also be told to simulate inheriting messages from other classes, |
|
44 even multiple inheritance is possible. |
43 |
45 |
44 Its main use is for the demo doIts, to play the role of a model, |
46 Its main use is for the demo doIts, to play the role of a model, |
45 when no actual modelClass is available for the demonstration. |
47 when no actual modelClass is available for the demonstration. |
46 However, it can be used wherever some object is needed which responds to |
48 However, it can be used wherever some object is needed which responds to |
47 some protocol AND you do not want to add a class for it |
49 some protocol AND you do not want to add a class for it |
58 " |
60 " |
59 ! |
61 ! |
60 |
62 |
61 examples |
63 examples |
62 " |
64 " |
|
65 a simple plug: |
63 [exBegin] |
66 [exBegin] |
64 |plug| |
67 |plug| |
65 |
68 |
66 plug := Plug new. |
69 plug := Plug new. |
67 plug respondTo:#foo with:[Transcript showCR:'received foo']. |
70 plug respondTo:#foo with:[Transcript showCR:'Plug received foo']. |
68 plug respondTo:#foo: with:[:arg | Transcript showCR:'received foo: ', arg printString]. |
71 plug respondTo:#foo: with:[:arg | Transcript showCR:'Plug received foo: ', arg printString]. |
69 |
72 |
70 plug foo. |
73 plug foo. |
71 plug foo:'some argument' |
74 plug foo:'some argument' |
72 [exEnd] |
75 [exEnd] |
73 |
76 |
74 using a plug as a generator (simulates a readStream): |
77 using a plug as a generator (simulates a readStream): |
75 [exBegin] |
78 [exBegin] |
76 |generator num| |
79 |generator num| |
77 |
80 |
78 num := 0. |
81 num := 0. |
79 generator := Plug new. |
82 generator := Plug new. |
80 generator respondTo:#next |
83 generator respondTo:#next with:[num := num + 1. num]. |
81 with:[num := num + 1. num]. |
84 generator respondTo:#atEnd with:[false]. |
82 generator respondTo:#atEnd |
85 |
83 with:[false]. |
86 10 timesRepeat:[ |
84 |
87 Transcript showCR:(generator next) |
85 10 timesRepeat:[ |
88 ] |
86 Transcript showCR:(generator next) |
|
87 ] |
|
88 [exEnd] |
89 [exEnd] |
89 |
90 |
90 simulating ``instance variables'': |
91 simulating ``instance variables'': |
91 (actually, this is somewhat expensive - the contexts locals are used for them ...) |
92 (actually, this is somewhat expensive - the contexts locals are used for them ...) |
92 be careful with unintended variable sharing (if plugs are created in a loop ..) |
93 be careful with unintended variable sharing (if plugs are created in a loop ..) |
93 [exBegin] |
94 [exBegin] |
94 |plug1 plug2 local1 local2| |
95 |plug1 plug2 local1 local2| |
95 |
96 |
96 plug1 := Plug new. |
97 plug1 := Plug new. |
97 plug1 respondTo:#get with:[local1]. |
98 plug1 respondTo:#get with:[local1]. |
98 plug1 respondTo:#set: with:[:arg | local1 := arg]. |
99 plug1 respondTo:#set: with:[:arg | local1 := arg]. |
99 |
100 |
100 plug2 := Plug new. |
101 plug2 := Plug new. |
101 plug2 respondTo:#get with:[local2]. |
102 plug2 respondTo:#get with:[local2]. |
102 plug2 respondTo:#set: with:[:arg | local2 := arg]. |
103 plug2 respondTo:#set: with:[:arg | local2 := arg]. |
103 |
104 |
104 Transcript show:'plug1''s value: '; showCR:plug1 get. |
105 Transcript show:'plug1''s value: '; showCR:plug1 get. |
105 Transcript show:'plug2''s value: '; showCR:plug2 get. |
106 Transcript show:'plug2''s value: '; showCR:plug2 get. |
106 |
107 |
107 plug1 set:5. |
108 plug1 set:5. |
108 plug2 set:17. |
109 plug2 set:17. |
109 |
110 |
110 Transcript show:'plug1''s value: '; showCR:plug1 get. |
111 Transcript show:'plug1''s value: '; showCR:plug1 get. |
111 Transcript show:'plug2''s value: '; showCR:plug2 get. |
112 Transcript show:'plug2''s value: '; showCR:plug2 get. |
|
113 [exEnd] |
|
114 |
|
115 simulating a big list in a ListView |
|
116 (real applications would read the lines from a database or file): |
|
117 [exBegin] |
|
118 |virtualList top lv| |
|
119 |
|
120 virtualList := Plug new. |
|
121 virtualList inheritFrom:SequenceableCollection. |
|
122 virtualList respondTo:#size with:[ 1000000 ]. |
|
123 virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ]. |
|
124 |
|
125 top := StandardSystemView extent:200@200. |
|
126 |
|
127 lv := ScrollableView for:ListView in:top. |
|
128 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
129 lv list:virtualList expandTabs:false scanForNonStrings:false includesNonStrings:false. |
|
130 |
|
131 top open. |
112 [exEnd] |
132 [exEnd] |
113 " |
133 " |
114 ! ! |
134 ! ! |
115 |
135 |
116 !Plug class methodsFor:'instance creation'! |
136 !Plug class methodsFor:'instance creation'! |
151 Otherwise, fall into the real doesNotUnderstand error." |
171 Otherwise, fall into the real doesNotUnderstand error." |
152 |
172 |
153 |block| |
173 |block| |
154 |
174 |
155 block := simulatedProtocol at:(aMessage selector) ifAbsent:[]. |
175 block := simulatedProtocol at:(aMessage selector) ifAbsent:[]. |
156 block isNil ifTrue:[ |
176 block notNil ifTrue:[ |
157 ^ super doesNotUnderstand:aMessage |
177 ^ block valueWithArguments:(aMessage arguments) |
158 ]. |
178 ]. |
159 ^ block valueWithArguments:(aMessage arguments) |
179 inheritedClasses notNil ifTrue:[ |
|
180 inheritedClasses do:[:eachClass | |
|
181 |method| |
|
182 |
|
183 method := eachClass lookupMethodFor:(aMessage selector). |
|
184 method notNil ifTrue:[ |
|
185 ^ method valueWithReceiver:self arguments:(aMessage arguments). |
|
186 ]. |
|
187 ]. |
|
188 ]. |
|
189 ^ super doesNotUnderstand:aMessage |
160 |
190 |
161 "Modified: 27.4.1996 / 16:15:34 / cg" |
191 "Modified: 27.4.1996 / 16:15:34 / cg" |
|
192 ! |
|
193 |
|
194 size |
|
195 "catch this one - its so common" |
|
196 |
|
197 ^ self doesNotUnderstand:(Message selector:#size arguments:#()) |
162 ! |
198 ! |
163 |
199 |
164 update:something with:aParameter from:changedObject |
200 update:something with:aParameter from:changedObject |
165 "catch unhandled messages by looking in my simulated protocol |
201 "catch unhandled messages by looking in my simulated protocol |
166 definition; if there is some block for it, return its value. |
202 definition; if there is some block for it, return its value. |
218 p foo. |
254 p foo. |
219 " |
255 " |
220 |
256 |
221 "Modified: 27.4.1996 / 16:14:19 / cg" |
257 "Modified: 27.4.1996 / 16:14:19 / cg" |
222 "Created: 27.4.1996 / 16:19:08 / cg" |
258 "Created: 27.4.1996 / 16:19:08 / cg" |
|
259 ! |
|
260 |
|
261 inheritFrom:aClass |
|
262 "very tricky - change the inheritance. |
|
263 This cannot be done by changing my class directly, because the instance layout |
|
264 must still be correct for Plugs instance variables. |
|
265 Therefore, the inheritance is remembered, and done dynamically in the doesNotUnderstand |
|
266 implementation." |
|
267 |
|
268 self assert:(aClass instSize == 0). |
|
269 inheritedClasses isNil ifTrue:[ |
|
270 inheritedClasses := Array with:aClass |
|
271 ] ifFalse:[ |
|
272 inheritedClasses := inheritedClasses copyWith:aClass |
|
273 ]. |
223 ! |
274 ! |
224 |
275 |
225 respondTo:aSelector with:aBlock |
276 respondTo:aSelector with:aBlock |
226 "tell the receiver to respond to a message given by selector, |
277 "tell the receiver to respond to a message given by selector, |
227 with evaluating aBlock. The number of arguments as defined by the |
278 with evaluating aBlock. The number of arguments as defined by the |