lib/preferences.rb in preferences-0.0.1 vs lib/preferences.rb in preferences-0.1.0

- old
+ new

@@ -77,27 +77,31 @@ # preferences. # # Example: # # user = User.find(:first) - # user.prefers_notifications? # => false - # user.prefers_color? # => true - # user.preferred_color # => 'red' - # user.preferred_color = 'blue' # => 'blue' + # user.prefers_notifications? # => false + # user.prefers_color? # => true + # user.preferred_color # => 'red' + # user.preferred_color = 'blue' # => 'blue' # # user.prefers_notifications = true # # car = Car.find(:first) - # user.preferred_color = 'red', {:for => car} # => 'red' - # user.preferred_color(:for => car) # => 'red' - # user.prefers_color?(:for => car) # => true + # user.preferred_color = 'red', car # => 'red' + # user.preferred_color(car) # => 'red' + # user.prefers_color?(car) # => true # # user.save! # => true def preference(attribute, *args) unless included_modules.include?(InstanceMethods) class_inheritable_hash :preference_definitions + self.preference_definitions = {} + class_inheritable_hash :default_preference_values + self.default_preference_values = {} + has_many :preferences, :as => :owner after_save :update_preferences @@ -105,117 +109,160 @@ end # Create the definition attribute = attribute.to_s definition = PreferenceDefinition.new(attribute, *args) - self.preference_definitions = {attribute => definition} + self.preference_definitions[attribute] = definition + self.default_preference_values[attribute] = definition.default_value # Create short-hand helper methods, making sure that the attribute # is method-safe in terms of what characters are allowed attribute = attribute.gsub(/[^A-Za-z0-9_-]/, '').underscore - class_eval <<-end_eval - def prefers_#{attribute}?(options = {}) - prefers?(#{attribute.dump}, options) - end - - def prefers_#{attribute}=(args) - set_preference(*([#{attribute.dump}] + [args].flatten)) - end - - def preferred_#{attribute}(options = {}) - preferred(#{attribute.dump}, options) - end - - alias_method :preferred_#{attribute}=, :prefers_#{attribute}= - end_eval + # Query lookup + define_method("prefers_#{attribute}?") do |*group| + prefers?(attribute, group.first) + end + + # Writer + define_method("prefers_#{attribute}=") do |*args| + set_preference(*([attribute] + [args].flatten)) + end + alias_method "preferred_#{attribute}=", "prefers_#{attribute}=" + + # Reader + define_method("preferred_#{attribute}") do |*group| + preferred(attribute, group.first) + end + definition end end module InstanceMethods + # Finds all preferences, including defaults, for the current record. If + # any custom group preferences have been stored, then this will include + # all default preferences within that particular group. + # + # == Examples + # + # A user with no stored values: + # user = User.find(:first) + # user.preference_values + # => {"language"=>"English", "color"=>nil} + # + # A user with stored values for a particular group: + # user.preferred_color = 'red', 'cars' + # user.preference_values + # => {"language"=>"English", "color"=>nil, "cars"=>{"language=>"English", "color"=>"red"}} + # + # Getting preference values for the owning record: + # user.preference_values(nil) + # => {"language"=>"English", "color"=>nil} + # + # Getting preference values for a particular group: + # user.preference_values('cars') + # => {"language"=>"English", "color"=>"red"} + def preference_values(*args) + if args.any? + group = args.first + group_id, group_type = Preference.split_group(group) + conditions = {:group_id => group_id, :group_type => group_type} + else + conditions = {} + end + + # Find all of the stored preferences + stored_preferences = preferences.find(:all, :conditions => conditions) + + # Hashify attribute -> value or group -> attribute -> value + stored_preferences.inject(self.class.default_preference_values.dup) do |preferences, preference| + if group = preference.group + preference_group = preferences[group] ||= self.class.default_preference_values.dup + else + preference_group = preferences + end + + preference_group[preference.attribute] = preference.value + preferences + end + end + # Queries whether or not a value has been specified for the given attribute. # This is dependent on how the value is type-casted. # - # Configuration options: - # * +for+ - The record being preferenced - # # == Examples # # user = User.find(:first) - # user.prefers?(:notifications) # => true + # user.prefers?(:notifications) # => true # + # user.prefers(:notifications, 'error') # => true + # # newsgroup = Newsgroup.find(:first) - # user.prefers?(:notifications, :for => newsgroup) # => false - def prefers?(attribute, options = {}) + # user.prefers?(:notifications, newsgroup) # => false + def prefers?(attribute, group = nil) attribute = attribute.to_s - value = preferred(attribute, options) + value = preferred(attribute, group) preference_definitions[attribute].query(value) end # Gets the preferred value for the given attribute. # - # Configuration options: - # * +for+ - The record being preferenced - # # == Examples # # user = User.find(:first) - # user.preferred(:color) # => 'red' + # user.preferred(:color) # => 'red' # + # user.preferred(:color, 'cars') # => 'blue' + # # car = Car.find(:first) - # user.preferred(:color, :for => car) # => 'black' - def preferred(attribute, options = {}) - options.assert_valid_keys(:for) + # user.preferred(:color, car) # => 'black' + def preferred(attribute, group = nil) attribute = attribute.to_s - if @preference_values && @preference_values[attribute] && @preference_values[attribute].include?(options[:for]) - value = @preference_values[attribute][options[:for]] + if @preference_values && @preference_values[attribute] && @preference_values[attribute].include?(group) + value = @preference_values[attribute][group] else - preferenced_id, preferenced_type = options[:for].id, options[:for].class.base_class.name.to_s if options[:for] - preference = preferences.find(:first, :conditions => {:attribute => attribute, :preferenced_id => preferenced_id, :preferenced_type => preferenced_type}) + group_id, group_type = Preference.split_group(group) + preference = preferences.find(:first, :conditions => {:attribute => attribute, :group_id => group_id, :group_type => group_type}) value = preference ? preference.value : preference_definitions[attribute].default_value end value end # Sets a new value for the given attribute. The actual Preference record # is *not* created until the actual record is saved. # - # Configuration options: - # * +for+ - The record being preferenced - # # == Examples # # user = User.find(:first) # user.set_preference(:notifications, false) # => false # user.save! # # newsgroup = Newsgroup.find(:first) - # user.set_preference(:notifications, true, :for => newsgroup) # => true + # user.set_preference(:notifications, true, newsgroup) # => true # user.save! - def set_preference(attribute, value, options = {}) - options.assert_valid_keys(:for) + def set_preference(attribute, value, group = nil) attribute = attribute.to_s @preference_values ||= {} @preference_values[attribute] ||= {} - @preference_values[attribute][options[:for]] = value + @preference_values[attribute][group] = value value end private # Updates any preferences that have been changed/added since the record # was last saved def update_preferences if @preference_values - @preference_values.each do |attribute, preferenced_records| - preferenced_records.each do |preferenced, value| - preferenced_id, preferenced_type = preferenced.id, preferenced.class.base_class.name.to_s if preferenced - attributes = {:attribute => attribute, :preferenced_id => preferenced_id, :preferenced_type => preferenced_type} + @preference_values.each do |attribute, grouped_records| + grouped_records.each do |group, value| + group_id, group_type = Preference.split_group(group) + attributes = {:attribute => attribute, :group_id => group_id, :group_type => group_type} # Find an existing preference or build a new one preference = preferences.find(:first, :conditions => attributes) || preferences.build(attributes) preference.value = value preference.save!