lib/glimmer/data_binding/observable_array.rb in glimmer-0.10.1 vs lib/glimmer/data_binding/observable_array.rb in glimmer-0.10.2

- old
+ new

@@ -1,78 +1,281 @@ require 'set' +require 'array_include_methods' require 'glimmer/data_binding/observable' +using ArrayIncludeMethods + module Glimmer module DataBinding # TODO prefix utility methods with double-underscore module ObservableArray include Observable - def add_observer(observer, element_properties=nil) - return observer if has_observer?(observer) && element_properties.nil? + def add_observer(observer, *element_properties) + element_properties = element_properties.flatten.compact.uniq + return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties) property_observer_list << observer - [element_properties].flatten.compact.each do |property| - each do |element| - observer.observe(element, property) - end - end + observer_element_properties[observer] = element_properties_for(observer) + Set.new(element_properties) + each { |element| add_element_observer(element, observer) } observer end + + def add_element_observers(element) + property_observer_list.each do |observer| + add_element_observer(element, observer) + end + end - def remove_observer(observer, element_properties=nil) - property_observer_list.delete(observer) - [element_properties].flatten.compact.each do |property| + def add_element_observer(element, observer) + element_properties_for(observer).each do |property| + observer.observe(element, property) + end + end + + def remove_observer(observer, *element_properties) + element_properties = element_properties.flatten.compact.uniq + if !element_properties.empty? + old_element_properties = element_properties_for(observer) + observer_element_properties[observer] = element_properties_for(observer) - Set.new(element_properties) each do |element| - observer.unobserve(element, property) + element_properties.each do |property| + observer.unobserve(element, property) + end end end + if element_properties_for(observer).empty? + property_observer_list.delete(observer) + observer_element_properties.delete(observer) + each { |element| remove_element_observer(element, observer) } + end observer end + def remove_element_observers(element) + property_observer_list.each do |observer| + remove_element_observer(element, observer) + end + end + + def remove_element_observer(element, observer) + element_properties_for(observer).each do |property| + observer.unobserve(element, property) + end + end + def has_observer?(observer) property_observer_list.include?(observer) end + + def has_observer_element_properties?(observer, element_properties) + element_properties_for(observer).to_a.include_all?(element_properties) + end def property_observer_list @property_observer_list ||= Set.new end + def observer_element_properties + @observer_element_properties ||= {} + end + + def element_properties_for(observer) + observer_element_properties[observer] ||= Set.new + end + def notify_observers property_observer_list.to_a.each(&:call) end def <<(element) - super(element) - notify_observers + super(element).tap do + add_element_observers(element) + notify_observers + end end + alias push << def []=(index, value) old_value = self[index] unregister_dependent_observers(old_value) - super(index, value) - notify_observers + remove_element_observers(old_value) + add_element_observers(value) + super(index, value).tap do + notify_observers + end end + def pop + popped_element = last + unregister_dependent_observers(popped_element) + remove_element_observers(popped_element) + super.tap do + notify_observers + end + end + def delete(element) unregister_dependent_observers(element) - super(element) - notify_observers + remove_element_observers(element) + super(element).tap do + notify_observers + end end def delete_at(index) old_value = self[index] unregister_dependent_observers(old_value) - super(index) - notify_observers + remove_element_observers(old_value) + super(index).tap do + notify_observers + end end + def delete_if(&block) + if block_given? + old_array = Array.new(self) + super(&block).tap do |new_array| + (old_array - new_array).each do |element| + unregister_dependent_observers(element) + remove_element_observers(element) + end + notify_observers + end + else + super + end + end + def clear each do |old_value| unregister_dependent_observers(old_value) + remove_element_observers(old_value) end - super() - notify_observers + super.tap do + notify_observers + end + end + + def reverse! + super.tap do + notify_observers + end + end + + def collect!(&block) + if block_given? + each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + super(&block).tap do + each do |element| + add_element_observers(element) + end + notify_observers + end + else + super + end + end + alias map! collect! + + def compact! + super.tap do + notify_observers + end + end + + def flatten!(level=nil) + each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + (level.nil? ? super() : super(level)).tap do + each do |element| + add_element_observers(element) + end + notify_observers + end + end + + def rotate!(count=1) + super(count).tap do + notify_observers + end + end + + def select!(&block) + if block_given? + old_array = Array.new(self) + super(&block).tap do + (old_array - self).each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + notify_observers + end + else + super + end + end + + def shuffle!(hash = nil) + (hash.nil? ? super() : super(random: hash[:random])).tap do + notify_observers + end + end + + def slice!(arg1, arg2=nil) + old_array = Array.new(self) + (arg2.nil? ? super(arg1) : super(arg1, arg2)).tap do + (old_array - self).each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + notify_observers + end + end + + def sort!(&block) + (block.nil? ? super() : super(&block)).tap do + notify_observers + end + end + + def sort_by!(&block) + (block.nil? ? super() : super(&block)).tap do + notify_observers + end + end + + def uniq!(&block) + each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + (block.nil? ? super() : super(&block)).tap do + each do |element| + add_element_observers(element) + end + notify_observers + end + end + + def reject!(&block) + if block_given? + old_array = Array.new(self) + super(&block).tap do + (old_array - self).each do |old_value| + unregister_dependent_observers(old_value) + remove_element_observers(old_value) + end + notify_observers + end + else + super + end end def unregister_dependent_observers(old_value) # TODO look into optimizing this return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)