Module: Glimmer::DataBinding::ObservableHash
- Includes:
- Observable
- Defined in:
- lib/glimmer/data_binding/observable_hash.rb
Defined Under Namespace
Classes: Notifier
Constant Summary collapse
- OBSERVED_STORE_METHOD =
lambda do |key, value| if key_observer_list(key).empty? if all_key_observer_list.empty? self.send('__original__store', key, value) else old_value = self[key] unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer self.send('__original__store', key, value) notify_observers(key) ensure_array_object_observer(nil, value, old_value) ensure_hash_object_observer(nil, value, old_value) end else old_value = self[key] unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer self.send('__original__store', key, value) notify_observers(key) ensure_array_object_observer(key, value, old_value) ensure_hash_object_observer(key, value, old_value) end end
Instance Method Summary collapse
- #add_key_writer_observer(key = nil, options) ⇒ Object
- #add_observer(observer, key = nil, options = {}) ⇒ Object
- #all_key_observer_list ⇒ Object
- #array_object_observer_for(key) ⇒ Object
- #delete(key, &block) ⇒ Object
- #delete_if(&block) ⇒ Object
- #ensure_array_object_observer(key, object, old_object = nil, options = {}) ⇒ Object
- #ensure_hash_object_observer(key, object, old_object = nil, options = {}) ⇒ Object
- #filter!(&block) ⇒ Object
- #has_observer?(observer, key = nil) ⇒ Boolean
- #has_observer_for_any_key?(observer) ⇒ Boolean
- #hash_object_observer_for(key) ⇒ Object
- #keep_if(&block) ⇒ Object
- #key_observer_hash ⇒ Object
- #key_observer_list(key) ⇒ Object
- #merge!(*other_hashes, &block) ⇒ Object
- #notify_observers(key) ⇒ Object
- #reject!(&block) ⇒ Object
- #remove_all_observers ⇒ Object
- #remove_observer(observer, key = nil, options = {}) ⇒ Object
- #remove_observers(key) ⇒ Object
- #replace(other_hash) ⇒ Object
- #select!(&block) ⇒ Object
- #shift ⇒ Object
- #store_method ⇒ Object
- #transform_keys!(hash2 = nil, &block) ⇒ Object
- #transform_values!(&block) ⇒ Object
- #unregister_dependent_observers(key, old_value) ⇒ Object (also: #deregister_dependent_observers)
Methods included from Observable
Instance Method Details
#add_key_writer_observer(key = nil, options) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 126 def add_key_writer_observer(key = nil, ) ensure_array_object_observer(key, self[key], nil, ) ensure_hash_object_observer(key, self[key], nil, ) begin method('__original__store') rescue define_singleton_method('__original__store', store_method) define_singleton_method('[]=', &OBSERVED_STORE_METHOD) end rescue => e #ignore writing if no key writer exists Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.}\n#{e.backtrace.join("\n")}"} end |
#add_observer(observer, key = nil, options = {}) ⇒ Object
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 65 def add_observer(observer, key = nil, = {}) if key.is_a?(Hash) = key key = nil end return observer if has_observer?(observer, key) key_observer_list(key) << observer add_key_writer_observer(key, ) observer end |
#all_key_observer_list ⇒ Object
117 118 119 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 117 def all_key_observer_list key_observer_list(nil) end |
#array_object_observer_for(key) ⇒ Object
163 164 165 166 167 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 163 def array_object_observer_for(key) @array_object_observers ||= Concurrent::Hash.new @array_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @array_object_observers.has_key?(key) @array_object_observers[key] end |
#delete(key, &block) ⇒ Object
187 188 189 190 191 192 193 194 195 196 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 187 def delete(key, &block) old_value = self[key] unless old_value.nil? unregister_dependent_observers(key, old_value) unregister_dependent_observers(nil, old_value) end super(key, &block).tap do notify_observers(key) unless old_value.nil? end end |
#delete_if(&block) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 198 def delete_if(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end else super end end |
#ensure_array_object_observer(key, object, old_object = nil, options = {}) ⇒ Object
151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 151 def ensure_array_object_observer(key, object, old_object = nil, = {}) ||= {} return unless object&.is_a?(Array) array_object_observer = array_object_observer_for(key) array_observer_registration = array_object_observer.observe(object, ) key_observer_list(key).each do |observer| my_registration = observer.registration_for(self, key) # TODO eliminate repetition observer.add_dependent(my_registration => array_observer_registration) end array_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableArray) end |
#ensure_hash_object_observer(key, object, old_object = nil, options = {}) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 169 def ensure_hash_object_observer(key, object, old_object = nil, = {}) ||= {} return unless object&.is_a?(Hash) hash_object_observer = hash_object_observer_for(key) hash_observer_registration = hash_object_observer.observe(object, ) key_observer_list(key).each do |observer| my_registration = observer.registration_for(self, key) # TODO eliminate repetition observer.add_dependent(my_registration => hash_observer_registration) end hash_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableHash) end |
#filter!(&block) ⇒ Object
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 236 def filter!(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end else super end end |
#has_observer?(observer, key = nil) ⇒ Boolean
100 101 102 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 100 def has_observer?(observer, key = nil) key_observer_list(key).include?(observer) end |
#has_observer_for_any_key?(observer) ⇒ Boolean
104 105 106 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 104 def has_observer_for_any_key?(observer) key_observer_hash.values.map(&:to_a).reduce(:+).include?(observer) end |
#hash_object_observer_for(key) ⇒ Object
181 182 183 184 185 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 181 def hash_object_observer_for(key) @hash_object_observers ||= Concurrent::Hash.new @hash_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @hash_object_observers.has_key?(key) @hash_object_observers[key] end |
#keep_if(&block) ⇒ Object
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 255 def keep_if(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end else super end end |
#key_observer_hash ⇒ Object
108 109 110 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 108 def key_observer_hash @key_observers ||= Hash.new end |
#key_observer_list(key) ⇒ Object
112 113 114 115 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 112 def key_observer_list(key) key_observer_hash[key] = Concurrent::Set.new unless key_observer_hash[key] key_observer_hash[key] end |
#merge!(*other_hashes, &block) ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 309 def merge!(*other_hashes, &block) if other_hashes.empty? super else old_hash = self.dup super(*other_hashes, &block).tap do |new_hash| changed_keys = other_hashes.map(&:keys).reduce(:+) changed_keys.each do |changed_key| old_value = old_hash[changed_key] if new_hash[changed_key] != old_value unregister_dependent_observers(changed_key, old_value) unregister_dependent_observers(nil, old_value) notify_observers(changed_key) end end end end end |
#notify_observers(key) ⇒ Object
121 122 123 124 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 121 def notify_observers(key) all_key_observer_list.to_a.each { |observer| observer.call(self[key], key) } (key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) } end |
#reject!(&block) ⇒ Object
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 274 def reject!(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end else super end end |
#remove_all_observers ⇒ Object
91 92 93 94 95 96 97 98 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 91 def remove_all_observers all_observers = key_observer_hash.clone key_observer_hash.keys.each do |key| remove_observers(key) end key_observer_hash.clear all_observers end |
#remove_observer(observer, key = nil, options = {}) ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 76 def remove_observer(observer, key = nil, = {}) old_value = self[key] if has_observer?(observer, key) key_observer_list(key).delete(observer) observer.unobserve(self, key) end end |
#remove_observers(key) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 84 def remove_observers(key) key_observer_hash[key].each do |observer| remove_observer(observer, key) end key_observer_hash.delete(key) end |
#replace(other_hash) ⇒ Object
328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 328 def replace(other_hash) old_hash = self.dup super(other_hash).tap do |new_hash| changed_keys = old_hash.keys + new_hash.keys changed_keys.each do |changed_key| old_value = old_hash[changed_key] if new_hash[changed_key] != old_value unregister_dependent_observers(changed_key, old_value) unregister_dependent_observers(nil, old_value) notify_observers(changed_key) end end end end |
#select!(&block) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 217 def select!(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end else super end end |
#shift ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 293 def shift old_hash = self.dup super.tap do new_hash = self deleted_keys = old_hash.keys - new_hash.keys deleted_keys.each do |deleted_key| deleted_value = old_hash[deleted_key] unless deleted_value.nil? unregister_dependent_observers(deleted_key, deleted_value) unregister_dependent_observers(nil, deleted_value) notify_observers(deleted_key) end end end end |
#store_method ⇒ Object
140 141 142 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 140 def store_method self.class.instance_method('[]=') rescue self.method('[]=') end |
#transform_keys!(hash2 = nil, &block) ⇒ Object
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 343 def transform_keys!(hash2 = nil, &block) if hash2.nil? && block.nil? super else old_hash = self.dup result = hash2.nil? ? super(&block) : super(hash2, &block) result.tap do |new_hash| changed_keys = old_hash.keys + new_hash.keys changed_keys.each do |changed_key| old_value = old_hash[changed_key] if new_hash[changed_key] != old_value unregister_dependent_observers(changed_key, old_value) unregister_dependent_observers(nil, old_value) notify_observers(changed_key) end end end end end |
#transform_values!(&block) ⇒ Object
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 363 def transform_values!(&block) if block_given? old_hash = self.dup super(&block).tap do |new_hash| new_hash.keys.each do |changed_key| old_value = old_hash[changed_key] if new_hash[changed_key] != old_value unregister_dependent_observers(changed_key, old_value) unregister_dependent_observers(nil, old_value) notify_observers(changed_key) end end end else super end end |
#unregister_dependent_observers(key, old_value) ⇒ Object Also known as: deregister_dependent_observers
144 145 146 147 148 |
# File 'lib/glimmer/data_binding/observable_hash.rb', line 144 def unregister_dependent_observers(key, old_value) # TODO look into optimizing this return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray) || old_value.is_a?(ObservableHash) key_observer_list(key).each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self, key), old_value) } end |