Trapped-Backend.st 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. | lesser |
  120. lesser := path size min: aPath size.
  121. ^(aPath copyFrom: 1 to: lesser) = (path copyFrom: 1 to: lesser)
  122. !
  123. isEnabled
  124. ^actionBlock notNil
  125. !
  126. isFlagged
  127. ^flagged
  128. ! !
  129. !TrappedSubscription class methodsFor: 'instance creation'!
  130. new
  131. self shouldNotImplement
  132. !
  133. path: anArray action: aBlock
  134. ^super new path: anArray actionBlock: aBlock
  135. ! !
  136. Error subclass: #TrappedUnwatch
  137. instanceVariableNames: ''
  138. package: 'Trapped-Backend'!
  139. !TrappedUnwatch commentStamp!
  140. SIgnal me from the watch: block to unwatch it.!
  141. !Object methodsFor: '*Trapped-Backend'!
  142. reverseTrapAt: anObject
  143. ^nil
  144. !
  145. reverseTrapAt: anObject put: value
  146. self error: 'Trapped cannot put at ', self class name, ' type key.'
  147. ! !
  148. !SequenceableCollection methodsFor: '*Trapped-Backend'!
  149. asEavModel
  150. | model |
  151. model := EavModel new.
  152. model getBlock: [ :anObject |
  153. self inject: anObject into: [ :soFar :segment |
  154. soFar ifNotNil: [ segment reverseTrapAt: soFar ]]].
  155. self isEmpty ifFalse: [
  156. model putBlock: [ :anObject :value | | penultimate |
  157. penultimate := self allButLast inject: anObject into: [ :soFar :segment |
  158. soFar ifNotNil: [ segment reverseTrapAt: soFar ]].
  159. self last reverseTrapAt: penultimate put: value ]].
  160. ^model
  161. ! !
  162. !String 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. ! !
  169. !Symbol methodsFor: '*Trapped-Backend'!
  170. reverseTrapAt: anObject
  171. ^[anObject perform: self] on: MessageNotUnderstood do: [^nil]
  172. !
  173. reverseTrapAt: anObject put: value
  174. ^anObject perform: (self, ':') asSymbol withArguments: { value }
  175. ! !
  176. !Number methodsFor: '*Trapped-Backend'!
  177. reverseTrapAt: anObject
  178. ^anObject at: self ifAbsent: [nil]
  179. !
  180. reverseTrapAt: anObject put: value
  181. ^anObject at: self put: value
  182. ! !