Smalltalk createPackage: 'Axxord-Axon'! Object subclass: #Axon instanceVariableNames: 'factory' package: 'Axxord-Axon'! !Axon commentStamp! I represent a pub-sub based on a key (called 'aspect'). I manage aspect-block subscriptions (called 'interests') as well as run blocks of dirtied interests. The interest objects are responsible of decision if the change of an aspect is relevant for them. Interest object must be subclasses of `AxonInterest`. My subclasses must provide implementation for: - add: - do: - clean! !Axon methodsFor: 'accessing'! addInterest: anInterest self add: (anInterest flag; yourself); dirty: true ! ! !Axon methodsFor: 'change-update'! changed: anAspect | needsToRun | needsToRun := false. self do: [ :each | (each accepts: anAspect) ifTrue: [ each flag. needsToRun := true ]]. self dirty: needsToRun ! changedAll | needsToRun | needsToRun := false. self do: [ :each | each flag. needsToRun := true ]. self dirty: needsToRun ! ! !Axon methodsFor: 'primitive ops'! add: anInterest self subclassResponsibility ! clean self subclassResponsibility ! do: aBlock self subclassResponsibility ! ! !Axon methodsFor: 'private'! dirty: aBoolean aBoolean ifTrue: [[ self run ] fork] ! run [ | needsClean | needsClean := false. self do: [ :each | each isFlagged ifTrue: [ each run ]. each isClosed ifTrue: [ needsClean := true ] ]. needsClean ifTrue: [ self clean ] ] on: Error do: [ self dirty: true ] ! ! Axon subclass: #SimpleAxon instanceVariableNames: 'queue' package: 'Axxord-Axon'! !SimpleAxon methodsFor: 'initialization'! initialize super initialize. queue := OrderedCollection new ! ! !SimpleAxon methodsFor: 'primitive ops'! add: aSubscription queue add: aSubscription. ! clean queue := queue reject: [ :each | each isClosed ] ! do: aBlock queue do: aBlock ! ! Object subclass: #AxonInterest instanceVariableNames: 'flagged' package: 'Axxord-Axon'! !AxonInterest methodsFor: 'accessing'! flag flagged := true ! ! !AxonInterest methodsFor: 'action'! close self subclassResponsibility ! enact self subclassResponsibility ! run [ flagged := false. self enact ] on: AxonOff do: [ self close ] ! ! !AxonInterest methodsFor: 'initialization'! initialize super initialize. flagged := false. ! ! !AxonInterest methodsFor: 'testing'! accepts: anAspect "Should return true if change for anAspect is relevant for this AxonInterest" self subclassResponsibility ! isClosed self subclassResponsibility ! isFlagged ^flagged ! ! AxonInterest subclass: #PluggableInterest instanceVariableNames: 'acceptBlock enactBlock' package: 'Axxord-Axon'! !PluggableInterest methodsFor: 'accessing'! accept: aBlock enact: anotherBlock acceptBlock := aBlock. enactBlock := anotherBlock ! ! !PluggableInterest methodsFor: 'action'! close acceptBlock := nil. enactBlock := nil ! enact enactBlock value ! ! !PluggableInterest methodsFor: 'initialization'! initialize super initialize. self close ! ! !PluggableInterest methodsFor: 'testing'! accepts: anAspect ^ acceptBlock value: anAspect ! isClosed ^ acceptBlock isNil ! ! Error subclass: #AxonOff instanceVariableNames: '' package: 'Axxord-Axon'! !AxonOff commentStamp! Signal me from the subscription block to unsubscribe it.!