You would like the framework to let you chain the streams, aren't you? So that you have a stream which interact with another stream.
Yes, pipes of streams.
I've just created a decoder in a trait and it is highly pluggable :-) Let's see an example:
testCombineWithNumberReader | stream | stream := NSSelectStream selectBlock: [:each | each even] inputStream: (NSNumberReader inputStream: (NSReadableCollectionStream on: '1420 245 211 12')). self deny: stream atEnd. self assert: stream peek = 1420. self assert: stream next = 1420. self deny: stream atEnd. self assert: stream peek = 12. self assert: stream next = 12. self assert: stream atEnd
This code uses three stream: - NSSelectStream reads its input and only returns elements matching the selectBlock (http://wiki.cs.uiuc.edu/PatternStories/SelectStream) - NSNumberReader is waiting for characters on its input and converts them to numbers. Spaces separate numbers. - NSReadableCollectionStream is equivalent to ReadStream.
The implementation part is really cool. NSNumberReader is made of:
- a constructor - 3 getters and 3 setters - a #realNext method: NSNumberReader>>realNext |number| [self inputStream peekFor: Character space] whileTrue. self inputStream atEnd ifTrue: [NSStreamAtEndError signal]. number := (self inputStream upTo: Character space) asNumber. ^ number
That's all. Nothing more is needed to create NSNumberReader. The other methods come from a trait.
NSSelectBlock is implemented in exactly the same way. It's #realNext is:
NSSelectBlock>>realNext self inputStream do: [:each | (selectBlock value: each) ifTrue: [^ each]]. NSStreamAtEndError signal.
What do you think?