Trapped-Backend.st 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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: #TrappedDispatcher
  52. instanceVariableNames: ''
  53. package: 'Trapped-Backend'!
  54. !TrappedDispatcher commentStamp!
  55. I am base class for change event dispatchers.
  56. I manage changed path - action block subscriptions.
  57. These subscription must be three-element arrays
  58. { dirty. path. block }
  59. My subclasses need to provide implementation for:
  60. add:
  61. do:
  62. clean
  63. (optionally) run!
  64. !TrappedDispatcher methodsFor: 'action'!
  65. changed: path
  66. | needsToRun |
  67. needsToRun := false.
  68. self do: [ :each |
  69. (each accepts: path) ifTrue: [
  70. each flag.
  71. needsToRun := true.
  72. ]
  73. ].
  74. self dirty: needsToRun
  75. !
  76. dirty: aBoolean
  77. aBoolean ifTrue: [[ self run ] fork]
  78. !
  79. on: path hook: aBlock
  80. self add: (TrappedSubscription path: path action: aBlock) flag.
  81. self dirty: true
  82. !
  83. run
  84. | needsClean |
  85. needsClean := false.
  86. self do: [ :each |
  87. each isFlagged ifTrue: [
  88. each run.
  89. each isEnabled ifFalse: [ needsClean := true ]
  90. ]
  91. ].
  92. needsClean ifTrue: [ self clean ]
  93. ! !
  94. Object subclass: #TrappedSubscription
  95. instanceVariableNames: 'path actionBlock flagged'
  96. package: 'Trapped-Backend'!
  97. !TrappedSubscription methodsFor: 'accessing'!
  98. flag
  99. flagged := true
  100. !
  101. path: anArray actionBlock: aBlock
  102. path := anArray.
  103. actionBlock := aBlock
  104. ! !
  105. !TrappedSubscription methodsFor: 'action'!
  106. run
  107. [[ actionBlock value ] ensure: [ flagged := false ]]
  108. on: TrappedUnwatch do: [ actionBlock := nil ]
  109. ! !
  110. !TrappedSubscription methodsFor: 'initialization'!
  111. initialize
  112. super initialize.
  113. path := nil.
  114. actionBlock := nil.
  115. flagged := false.
  116. ! !
  117. !TrappedSubscription methodsFor: 'testing'!
  118. accepts: aPath
  119. ^aPath size <= path size and: [aPath = (path copyFrom: 1 to: aPath size)]
  120. !
  121. isEnabled
  122. ^actionBlock notNil
  123. !
  124. isFlagged
  125. ^flagged
  126. ! !
  127. !TrappedSubscription class methodsFor: 'instance creation'!
  128. new
  129. self shouldNotImplement
  130. !
  131. path: anArray action: aBlock
  132. ^super new path: anArray actionBlock: aBlock
  133. ! !
  134. Error subclass: #TrappedUnwatch
  135. instanceVariableNames: ''
  136. package: 'Trapped-Backend'!
  137. !TrappedUnwatch commentStamp!
  138. SIgnal me from the watch: block to unwatch it.!
  139. !Object methodsFor: '*Trapped-Backend'!
  140. reverseTrapAt: anObject
  141. ^nil
  142. !
  143. reverseTrapAt: anObject put: value
  144. self error: 'Trapped cannot put at ', self class name, ' type key.'
  145. ! !
  146. !SequenceableCollection methodsFor: '*Trapped-Backend'!
  147. asEavModel
  148. | model |
  149. model := EavModel new.
  150. model getBlock: [ :anObject |
  151. self inject: anObject into: [ :soFar :segment |
  152. soFar ifNotNil: [ segment reverseTrapAt: soFar ]]].
  153. self isEmpty ifFalse: [
  154. model putBlock: [ :anObject :value | | penultimate |
  155. penultimate := self allButLast inject: anObject into: [ :soFar :segment |
  156. soFar ifNotNil: [ segment reverseTrapAt: soFar ]].
  157. self last reverseTrapAt: penultimate put: value ]].
  158. ^model
  159. ! !
  160. !String methodsFor: '*Trapped-Backend'!
  161. reverseTrapAt: anObject
  162. ^anObject at: self ifAbsent: [nil]
  163. !
  164. reverseTrapAt: anObject put: value
  165. ^anObject at: self put: value
  166. ! !
  167. !Symbol methodsFor: '*Trapped-Backend'!
  168. reverseTrapAt: anObject
  169. ^[anObject perform: self] on: MessageNotUnderstood do: [^nil]
  170. !
  171. reverseTrapAt: anObject put: value
  172. ^anObject perform: (self, ':') asSymbol withArguments: { value }
  173. ! !
  174. !Number methodsFor: '*Trapped-Backend'!
  175. reverseTrapAt: anObject
  176. ^anObject at: self ifAbsent: [nil]
  177. !
  178. reverseTrapAt: anObject put: value
  179. ^anObject at: self put: value
  180. ! !