Trapped-Backend.st 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. | aPath lesser |
  70. aPath := each second.
  71. lesser := aPath size min: path size.
  72. (path copyFrom: 1 to: lesser) = (aPath copyFrom: 1 to: lesser) ifTrue: [
  73. each at: 1 put: true.
  74. needsToRun := true.
  75. ]
  76. ].
  77. self dirty: needsToRun
  78. !
  79. dirty: aBoolean
  80. aBoolean ifTrue: [[ self run ] fork]
  81. !
  82. on: path hook: aBlock
  83. self add: { true. path. aBlock }.
  84. self dirty: true
  85. !
  86. run
  87. | needsClean |
  88. needsClean := false.
  89. self do: [ :each |
  90. each first ifTrue: [
  91. [[ each third value ] ensure: [ each at: 1 put: false ]]
  92. on: TrappedUnwatch do: [ each at: 3 put: nil. needsClean := true ]
  93. ]
  94. ].
  95. needsClean ifTrue: [ self clean ]
  96. ! !
  97. Error subclass: #TrappedUnwatch
  98. instanceVariableNames: ''
  99. package: 'Trapped-Backend'!
  100. !TrappedUnwatch commentStamp!
  101. SIgnal me from the watch: block to unwatch it.!
  102. !Object methodsFor: '*Trapped-Backend'!
  103. reverseTrapAt: anObject
  104. ^nil
  105. !
  106. reverseTrapAt: anObject put: value
  107. self error: 'Trapped cannot put at ', self class name, ' type key.'
  108. ! !
  109. !SequenceableCollection methodsFor: '*Trapped-Backend'!
  110. asEavModel
  111. | model |
  112. model := EavModel new.
  113. model getBlock: [ :anObject |
  114. self inject: anObject into: [ :soFar :segment |
  115. soFar ifNotNil: [ segment reverseTrapAt: soFar ]]].
  116. self isEmpty ifFalse: [
  117. model putBlock: [ :anObject :value | | penultimate |
  118. penultimate := self allButLast inject: anObject into: [ :soFar :segment |
  119. soFar ifNotNil: [ segment reverseTrapAt: soFar ]].
  120. self last reverseTrapAt: penultimate put: value ]].
  121. ^model
  122. ! !
  123. !String methodsFor: '*Trapped-Backend'!
  124. reverseTrapAt: anObject
  125. ^anObject at: self ifAbsent: [nil]
  126. !
  127. reverseTrapAt: anObject put: value
  128. ^anObject at: self put: value
  129. ! !
  130. !Symbol methodsFor: '*Trapped-Backend'!
  131. reverseTrapAt: anObject
  132. ^[anObject perform: self] on: MessageNotUnderstood do: [^nil]
  133. !
  134. reverseTrapAt: anObject put: value
  135. ^anObject perform: (self, ':') asSymbol withArguments: { value }
  136. ! !
  137. !Number methodsFor: '*Trapped-Backend'!
  138. reverseTrapAt: anObject
  139. ^anObject at: self ifAbsent: [nil]
  140. !
  141. reverseTrapAt: anObject put: value
  142. ^anObject at: self put: value
  143. ! !