Module: Glimmer::DataBinding::ObservableHash

Includes:
ObservableHashable
Defined in:
lib/glimmer/data_binding/observable_hash.rb

Defined Under Namespace

Classes: Notifier

Constant Summary

Constants included from ObservableHashable

Glimmer::DataBinding::ObservableHashable::OBSERVED_STORE_METHOD

Instance Method Summary collapse

Methods included from ObservableHashable

#add_key_writer_observer, #store_method

Methods included from Observable

#inspect

Instance Method Details

#add_observer(observer, key = nil, options = {}) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/glimmer/data_binding/observable_hash.rb', line 43

def add_observer(observer, key = nil, options = {})
  if key.is_a?(Hash)
    options = key
    key = nil
  end
  return observer if has_observer?(observer, key)
  key_observer_list(key) << observer
  add_key_writer_observer(key, options)
  observer
end

#all_key_observer_listObject



95
96
97
# File 'lib/glimmer/data_binding/observable_hash.rb', line 95

def all_key_observer_list
  key_observer_list(nil)
end

#array_object_observer_for(key) ⇒ Object



123
124
125
126
127
# File 'lib/glimmer/data_binding/observable_hash.rb', line 123

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



129
130
131
132
133
134
135
136
137
138
# File 'lib/glimmer/data_binding/observable_hash.rb', line 129

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



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/glimmer/data_binding/observable_hash.rb', line 140

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



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/glimmer/data_binding/observable_hash.rb', line 111

def ensure_array_object_observer(key, object, old_object = nil, options = {})
  options ||= {}
  return unless object&.is_a?(Array)
  array_object_observer = array_object_observer_for(key)
  array_observer_registration = array_object_observer.observe(object, options)
  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

#filter!(&block) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/glimmer/data_binding/observable_hash.rb', line 178

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

Returns:

  • (Boolean)


78
79
80
# File 'lib/glimmer/data_binding/observable_hash.rb', line 78

def has_observer?(observer, key = nil)
  key_observer_list(key).include?(observer)
end

#has_observer_for_any_key?(observer) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/glimmer/data_binding/observable_hash.rb', line 82

def has_observer_for_any_key?(observer)
  key_observer_hash.values.map(&:to_a).reduce(:+).include?(observer)
end

#keep_if(&block) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/glimmer/data_binding/observable_hash.rb', line 197

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_hashObject



86
87
88
# File 'lib/glimmer/data_binding/observable_hash.rb', line 86

def key_observer_hash
  @key_observers ||= Concurrent::Hash.new
end

#key_observer_list(key) ⇒ Object



90
91
92
93
# File 'lib/glimmer/data_binding/observable_hash.rb', line 90

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



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/glimmer/data_binding/observable_hash.rb', line 251

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



99
100
101
102
# File 'lib/glimmer/data_binding/observable_hash.rb', line 99

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



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/glimmer/data_binding/observable_hash.rb', line 216

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_observersObject



69
70
71
72
73
74
75
76
# File 'lib/glimmer/data_binding/observable_hash.rb', line 69

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



54
55
56
57
58
59
60
# File 'lib/glimmer/data_binding/observable_hash.rb', line 54

def remove_observer(observer, key = nil, options = {})
  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



62
63
64
65
66
67
# File 'lib/glimmer/data_binding/observable_hash.rb', line 62

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



270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/glimmer/data_binding/observable_hash.rb', line 270

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



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/glimmer/data_binding/observable_hash.rb', line 159

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

#shiftObject



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/glimmer/data_binding/observable_hash.rb', line 235

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

#transform_keys!(hash2 = nil, &block) ⇒ Object



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/glimmer/data_binding/observable_hash.rb', line 285

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



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/glimmer/data_binding/observable_hash.rb', line 305

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



104
105
106
107
108
# File 'lib/glimmer/data_binding/observable_hash.rb', line 104

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