Trapped-Backend.st 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. Smalltalk current createPackage: 'Trapped-Backend' properties: #{}!
  2. Object subclass: #EavModel
  3. instanceVariableNames: 'getBlock putBlock'
  4. package: 'Trapped-Backend'!
  5. !EavModel commentStamp!
  6. External actor value model.!
  7. !EavModel methodsFor: 'accessing'!
  8. getBlock: aBlock
  9. getBlock := aBlock
  10. !
  11. on: anObject
  12. "Returns value of model applied on object"
  13. ^getBlock value: anObject
  14. !
  15. on: anObject put: anObject2
  16. "Puts a value via model applied on object"
  17. ^putBlock value: anObject value: anObject2
  18. !
  19. putBlock: aBlock
  20. putBlock := aBlock
  21. ! !
  22. !EavModel methodsFor: 'initialization'!
  23. initialize
  24. super initialize.
  25. getBlock := [ self error: 'No getter block.' ].
  26. putBlock := [ self error: 'No putter block.' ].
  27. ! !
  28. Object subclass: #Isolator
  29. instanceVariableNames: 'root'
  30. package: 'Trapped-Backend'!
  31. !Isolator methodsFor: 'accessing'!
  32. root
  33. ^root
  34. !
  35. root: anObject
  36. root := anObject
  37. ! !
  38. !Isolator methodsFor: 'action'!
  39. model: anEavModel modify: aBlock
  40. | newValue |
  41. newValue := aBlock value: (anEavModel on: self).
  42. anEavModel on: self put: newValue deepCopy
  43. !
  44. model: anEavModel read: aBlock
  45. aBlock value: (anEavModel on: self) deepCopy
  46. ! !
  47. !Isolator class methodsFor: 'instance creation'!
  48. on: anObject
  49. ^self new root: anObject
  50. ! !
  51. Object subclass: #KeyedPubSubBase
  52. instanceVariableNames: ''
  53. package: 'Trapped-Backend'!
  54. !KeyedPubSubBase methodsFor: 'action'!
  55. changed: key
  56. | needsToRun |
  57. needsToRun := false.
  58. self do: [ :each |
  59. (each accepts: key) ifTrue: [
  60. each flag.
  61. needsToRun := true.
  62. ]
  63. ].
  64. self dirty: needsToRun
  65. !
  66. dirty: aBoolean
  67. aBoolean ifTrue: [[ self run ] fork]
  68. !
  69. on: key hook: aBlock
  70. self add: (self subscriptionKey: key block: aBlock) flag.
  71. self dirty: true
  72. !
  73. run
  74. | needsClean |
  75. needsClean := false.
  76. self do: [ :each |
  77. each isFlagged ifTrue: [
  78. each run.
  79. each isEnabled ifFalse: [ needsClean := true ]
  80. ]
  81. ].
  82. needsClean ifTrue: [ self clean ]
  83. !
  84. subscriptionKey: key block: aBlock
  85. "Should return subclass of KeyedSubscriptionBase"
  86. self subclassReponsibility
  87. ! !
  88. Error subclass: #KeyedPubSubUnsubscribe
  89. instanceVariableNames: ''
  90. package: 'Trapped-Backend'!
  91. !KeyedPubSubUnsubscribe commentStamp!
  92. SIgnal me from the subscription block to unsubscribe it.!
  93. Object subclass: #KeyedSubscriptionBase
  94. instanceVariableNames: 'key actionBlock flagged'
  95. package: 'Trapped-Backend'!
  96. !KeyedSubscriptionBase methodsFor: 'accessing'!
  97. flag
  98. flagged := true
  99. !
  100. key: anObject block: aBlock
  101. key := anObject.
  102. actionBlock := aBlock
  103. ! !
  104. !KeyedSubscriptionBase methodsFor: 'action'!
  105. run
  106. [[ actionBlock value ] ensure: [ flagged := false ]]
  107. on: KeyedPubSubUnsubscribe do: [ actionBlock := nil ]
  108. ! !
  109. !KeyedSubscriptionBase methodsFor: 'initialization'!
  110. initialize
  111. super initialize.
  112. key := nil.
  113. actionBlock := nil.
  114. flagged := false.
  115. ! !
  116. !KeyedSubscriptionBase methodsFor: 'testing'!
  117. accepts: aKey
  118. "Should return true if change for aKey is relevant for this subscription"
  119. self subclassResponsibility
  120. !
  121. isEnabled
  122. ^actionBlock notNil
  123. !
  124. isFlagged
  125. ^flagged
  126. ! !
  127. !Object methodsFor: '*Trapped-Backend'!
  128. reverseTrapAt: anObject
  129. ^nil
  130. !
  131. reverseTrapAt: anObject put: value
  132. self error: 'Trapped cannot put at ', self class name, ' type key.'
  133. ! !
  134. !SequenceableCollection methodsFor: '*Trapped-Backend'!
  135. asEavModel
  136. | model |
  137. model := EavModel new.
  138. model getBlock: [ :anObject |
  139. self inject: anObject into: [ :soFar :segment |
  140. soFar ifNotNil: [ segment reverseTrapAt: soFar ]]].
  141. self isEmpty ifFalse: [
  142. model putBlock: [ :anObject :value | | penultimate |
  143. penultimate := self allButLast inject: anObject into: [ :soFar :segment |
  144. soFar ifNotNil: [ segment reverseTrapAt: soFar ]].
  145. self last reverseTrapAt: penultimate put: value ]].
  146. ^model
  147. ! !
  148. !String methodsFor: '*Trapped-Backend'!
  149. reverseTrapAt: anObject
  150. ^anObject at: self ifAbsent: [nil]
  151. !
  152. reverseTrapAt: anObject put: value
  153. ^anObject at: self put: value
  154. ! !
  155. !Symbol methodsFor: '*Trapped-Backend'!
  156. reverseTrapAt: anObject
  157. ^[anObject perform: self] on: MessageNotUnderstood do: [^nil]
  158. !
  159. reverseTrapAt: anObject put: value
  160. ^anObject perform: (self, ':') asSymbol withArguments: { value }
  161. ! !
  162. !Number methodsFor: '*Trapped-Backend'!
  163. reverseTrapAt: anObject
  164. ^anObject at: self ifAbsent: [nil]
  165. !
  166. reverseTrapAt: anObject put: value
  167. ^anObject at: self put: value
  168. ! !