module RuGUI module PropertyChangedSupport module ClassMethods # Invoked when a property was changed. # # Example: # # when_property_changed :name do |observable, new_value, old_value| # puts "Hey! The property 'name' of the #{observable.class.name} was changed from #{old_value} to #{new_value}." # end # # # Or you can inform the observable: # # when_property_changed :name, :observable => :rabbit do |observable, new_value, old_value| # puts "Hey! The property 'name' of the 'rabbit' was changed from #{old_value} to #{new_value}." # end # # # If you can inform a method to be called: # # when_property_changed :name, :puts_anything # # def puts_anything(observable, new_value, old_value) # puts "Hey! The property 'name' of the #{observable.class.name} was changed from #{old_value} to #{new_value}." # end # # # Or you can inform the observable and a method to be called. # # when_property_changed :name, :observable => :rabbit, :call => :puts_anything # # def puts_anything(observable, new_value, old_value) # puts "Hey! The property 'name' of the 'rabbit' was changed from #{old_value} to #{new_value}." # end # # # def when_property_changed(property, method_or_options = {}, &block) property_changed_block = RuGUI::PropertyChangedSupport::PropertyChangedBlock.new property_changed_block.property = property property_changed_block.set_options(method_or_options) property_changed_block.block = block if block_given? self.property_changed_blocks << property_changed_block end end def self.included(base) base.class_inheritable_accessor :property_changed_blocks base.property_changed_blocks = [] base.extend(ClassMethods) end class PropertyChangedBlock attr_accessor :property attr_accessor :options attr_accessor :block attr_accessor :observer # Call the block configurated for the property changed if a block exists for the one. def call_property_changed_block_if_exists(observer, observable, property, new_value, old_value) self.observer = observer call_property_changed_block(observable, new_value, old_value) if block_exists?(observable, property, new_value, old_value) end # Set the options given the args. def set_options(method_or_options) case method_or_options when String, Symbol self.options = { :call => prepared(method_or_options) } when Hash self.options = method_or_options end end protected # Check if a block exists for the property changed def block_exists?(observable, property, new_value, old_value) if self.options.has_key?(:observable) return same_observable_and_property?(observable, property) else return same_property?(property) end end # Call the block configurated for the property changed. def call_property_changed_block(observable, new_value, old_value) return if not self.options.has_key?(:call) and self.block.blank? if self.options.has_key?(:call) method = self.options[:call] self.observer.send(method, observable, new_value, old_value) if self.observer.respond_to?(method) else self.block.call(observable, new_value, old_value) unless self.block.blank? end end private def same_property?(property) prepared(self.property) == prepared(property) end def same_observable?(observable) prepared(self.options[:observable]) == prepared(observable.class.name) end def same_observable_and_property?(observable, property) same_observable?(observable) and same_property?(property) end def prepared(param) param.to_s.downcase.underscore end def logger @logger ||= RuGUILogger.logger end end end end