Axon.st 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. Smalltalk createPackage: 'Axon'!
  2. Object subclass: #AxonBase
  3. instanceVariableNames: 'factory'
  4. package: 'Axon'!
  5. !AxonBase commentStamp!
  6. I represent a pub-sub based on a key (called 'aspect').
  7. I manage aspect-block subscriptions (called 'interests') as well as run blocks of dirtied interests.
  8. The interest objects are responsible of decision if the change of an aspect is relevant for them.
  9. Interest object must be subclasses of `AxonInterestBase`.
  10. My subclasses must provide implementation for:
  11. - add:
  12. - do:
  13. - clean
  14. - (optionally) run
  15. and issue this call before actual use:
  16. interestFactory: [ :description :block | ... factory that creates appropriate AxonInterest ... ]!
  17. !AxonBase methodsFor: 'action'!
  18. changed: anAspect
  19. | needsToRun |
  20. needsToRun := false.
  21. self do: [ :each |
  22. (each accepts: anAspect) ifTrue: [
  23. each flag.
  24. needsToRun := true.
  25. ]
  26. ].
  27. self dirty: needsToRun
  28. !
  29. dirty: aBoolean
  30. aBoolean ifTrue: [[ self run ] fork]
  31. !
  32. interestFactory: aBlock
  33. factory := aBlock
  34. !
  35. on: description hook: aBlock
  36. self add: (factory value: description value: aBlock) flag.
  37. self dirty: true
  38. !
  39. run
  40. [
  41. | needsClean |
  42. needsClean := false.
  43. self do: [ :each |
  44. each isFlagged ifTrue: [ each run ].
  45. each isEnabled ifFalse: [ needsClean := true ]
  46. ].
  47. needsClean ifTrue: [ self clean ]
  48. ] on: Error do: [ self dirty: true ]
  49. ! !
  50. AxonBase subclass: #SimpleAxon
  51. instanceVariableNames: 'queue'
  52. package: 'Axon'!
  53. !SimpleAxon methodsFor: 'accessing'!
  54. add: aSubscription
  55. queue add: aSubscription.
  56. ! !
  57. !SimpleAxon methodsFor: 'bookkeeping'!
  58. clean
  59. queue := queue select: [ :each | each isEnabled ]
  60. ! !
  61. !SimpleAxon methodsFor: 'enumeration'!
  62. do: aBlock
  63. queue do: aBlock
  64. ! !
  65. !SimpleAxon methodsFor: 'initialization'!
  66. initialize
  67. super initialize.
  68. queue := OrderedCollection new
  69. ! !
  70. Object subclass: #AxonInterestBase
  71. instanceVariableNames: 'aspect actionBlock flagged'
  72. package: 'Axon'!
  73. !AxonInterestBase methodsFor: 'accessing'!
  74. aspect: anAspect block: aBlock
  75. aspect := anAspect.
  76. actionBlock := aBlock
  77. !
  78. flag
  79. flagged := true
  80. ! !
  81. !AxonInterestBase methodsFor: 'action'!
  82. run
  83. [ flagged := false. actionBlock value ]
  84. on: AxonOff do: [ actionBlock := nil ]
  85. ! !
  86. !AxonInterestBase methodsFor: 'initialization'!
  87. initialize
  88. super initialize.
  89. aspect := nil.
  90. actionBlock := nil.
  91. flagged := false.
  92. ! !
  93. !AxonInterestBase methodsFor: 'testing'!
  94. accepts: anAspect
  95. "Should return true if change for anAspect is relevant for this AxonInterest"
  96. self subclassResponsibility
  97. !
  98. isEnabled
  99. ^actionBlock notNil
  100. !
  101. isFlagged
  102. ^flagged
  103. ! !
  104. AxonInterestBase subclass: #InterestedInEqual
  105. instanceVariableNames: ''
  106. package: 'Axon'!
  107. !InterestedInEqual methodsFor: 'testing'!
  108. accepts: anAspect
  109. ^ anAspect = aspect
  110. ! !
  111. Error subclass: #AxonOff
  112. instanceVariableNames: ''
  113. package: 'Axon'!
  114. !AxonOff commentStamp!
  115. SIgnal me from the subscription block to unsubscribe it.!
  116. Object subclass: #AxonizedObject
  117. instanceVariableNames: 'axon'
  118. package: 'Axon'!
  119. !AxonizedObject commentStamp!
  120. I am base class for object using Axon changed:
  121. for event / change logistics,
  122. Set AxonBase instance with `axon:` and then use
  123. `self changed: anAspect` to trigger axon's `changed:`.!
  124. !AxonizedObject methodsFor: 'accessing'!
  125. axon
  126. ^ axon
  127. !
  128. axon: anAxon
  129. axon := anAxon
  130. ! !
  131. !AxonizedObject methodsFor: 'action'!
  132. changed: anAspect
  133. self axon changed: anAspect
  134. ! !