eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Plug':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: Plug


Inheritance:

   Object
   |
   +--Model
      |
      +--Plug

Package:
stx:libview2
Category:
Kernel-Objects
Version:
rev: 1.24 date: 2017/03/09 23:23:00
user: cg
file: Plug.st directory: libview2
module: stx stc-classLibrary: libview2
Author:
Claus Gittinger

Description:


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).

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'...
    


Related information:

    Model

Class protocol:

instance creation
o  new
(comment from inherited method)
return an instance of myself without indexed variables


Instance protocol:

initialization
o  privateInitialize
this method is NOT called `#initialize' to allow plugging that
selector ...

message sending
o  at: key
catch this one - its so common

o  at: key put: value

o  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.

o  isSequenceable
catch this one - its so common

o  size
catch this one - its so common

o  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.

o  value
catch this one - its so common

o  value: arg
catch this one - its so common

protocol definition
o  forgetAbout: aSelector
tell the receiver to forget about how to respond to the given by selector

o  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.

o  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.

queries
o  respondsTo: aSelector
return true, if the receiver responds to a message


Examples:


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.


ST/X 7.1.0.0; WebServer 1.663 at exept.de:8081; Sun, 22 Jul 2018 16:46:47 GMT