SystemOrganization addCategory: #Generator! Stream subclass: #Generator instanceVariableNames: 'block next continue' classVariableNames: '' poolDictionaries: '' category: 'Generator'! !Generator class methodsFor: 'instance-creation' stamp: 'lr 1/8/2009 15:54'! on: aBlock ^ self basicNew initializeOn: aBlock! ! !Generator methodsFor: 'testing' stamp: 'lr 1/8/2009 16:42'! atEnd ^ continue isNil! ! !Generator methodsFor: 'accessing' stamp: 'lr 4/26/2009 11:50'! contents "Answer the contents of this generator. Do not call this method on infinite generators." | stream | stream := (Array new: 10) writeStream. [ self atEnd ] whileFalse: [ stream nextPut: self next ]. ^ stream contents! ! !Generator methodsFor: 'private' stamp: 'lr 1/8/2009 16:41'! fork | result | block reentrant value: self. thisContext swapSender: continue. result := next. continue := next := nil. ^ result! ! !Generator methodsFor: 'initialization' stamp: 'lr 1/8/2009 16:18'! initializeOn: aBlock block := aBlock. self reset! ! !Generator methodsFor: 'accessing' stamp: 'lr 1/8/2009 16:42'! next self atEnd ifTrue: [ ^ nil ]. continue := thisContext swapSender: continue! ! !Generator methodsFor: 'accessing' stamp: 'lr 4/26/2009 11:51'! nextPut: anObject | previous | previous := next. next := anObject. continue := thisContext swapSender: continue. ^ previous! ! !Generator methodsFor: 'accessing' stamp: 'lr 1/8/2009 16:44'! peek ^ next! ! !Generator methodsFor: 'printing' stamp: 'lr 1/8/2009 16:21'! printOn: aStream aStream nextPutAll: self class name; nextPutAll: ' on: '; print: block! ! !Generator methodsFor: 'public' stamp: 'lr 1/8/2009 16:39'! reset next := nil. continue := thisContext. [ self fork ] value! ! !Generator methodsFor: 'accessing' stamp: 'lr 1/8/2009 16:32'! size ^ self shouldNotImplement! ! !Generator methodsFor: 'public' stamp: 'lr 4/26/2009 11:52'! yield: anObject ^ self nextPut: anObject! ! TestCase subclass: #GeneratorTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Generator'! !GeneratorTest methodsFor: 'generators' stamp: 'lr 1/8/2009 16:29'! fibonacciSequence "Yields an infinite sequence of fibonacci numbers." ^ Generator on: [ :generator | | a b | a := 0. b := 1. [ a := b + (b := a). generator yield: a ] repeat ]! ! !GeneratorTest methodsFor: 'generators' stamp: 'lr 1/8/2009 15:49'! numbersBetween: aStartInteger and: aStopInteger "Yields the nubmers between aStartInteger and aStopInteger." ^ Generator on: [ :generator | aStartInteger to: aStopInteger do: [ :value | generator yield: value ] ]! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:33'! testAtEnd | generator | generator := self numbersBetween: 1 and: 3. self deny: generator atEnd. generator next. self deny: generator atEnd. generator next. self deny: generator atEnd. generator next. self assert: generator atEnd! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 4/26/2009 11:51'! testContents | generator | generator := self numbersBetween: 1 and: 3. self assert: generator contents = #(1 2 3)! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:45'! testEmpty | generator | generator := Generator on: [ :g | ]. self assert: generator atEnd. self assert: generator peek isNil. self assert: generator next isNil! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:50'! testFibonacci | generator | generator := self fibonacciSequence. self assert: (generator next: 10) asArray = #( 1 1 2 3 5 8 13 21 34 55 )! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:33'! testNext | generator | generator := self numbersBetween: 1 and: 3. self assert: generator next = 1. self assert: generator next = 2. self assert: generator next = 3. self assert: generator next isNil! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:45'! testPeek | generator | generator := self numbersBetween: 1 and: 3. self assert: generator peek = 1. self assert: generator peek = 1. generator next. self assert: generator peek = 2! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:35'! testReset | generator | generator := self numbersBetween: 1 and: 3. self assert: generator next = 1. self assert: generator next = 2. generator reset. self assert: generator next = 1. self assert: generator next = 2. self assert: generator next = 3. self assert: generator next = nil. generator reset. self assert: generator next = 1! ! !GeneratorTest methodsFor: 'testing' stamp: 'lr 1/8/2009 16:46'! testSimple | generator | generator := Generator on: [ :g | g yield: 1; yield: 2 ]. self assert: generator upToEnd asArray = #( 1 2 )! !