Permalink
Browse files

Add #preferences_changed?, #preferences_changed, and #preference_changes

Fix preferences that are reverted externally still getting stored
  • Loading branch information...
1 parent 450f979 commit 1ed8cd2f7e89b64c939f98f60eb7a38fd31c6d8f @obrie obrie committed Mar 7, 2010
Showing with 305 additions and 26 deletions.
  1. +2 −0 CHANGELOG.rdoc
  2. +84 −11 lib/preferences.rb
  3. +219 −15 test/functional/preferences_test.rb
View
2 CHANGELOG.rdoc
@@ -1,5 +1,7 @@
== master
+* Add #preferences_changed?, #preferences_changed, and #preference_changes
+* Fix preferences that are reverted externally still getting stored
* Fix preference definition types not being used to typecast values
* No longer allow both group and non-group preferences to be looked up at once (except for named scopes)
* Add support for using Symbols to reference groups
View
95 lib/preferences.rb
@@ -265,8 +265,6 @@ def self.included(base) #:nodoc:
# user.preferences(:cars)
# => {"language=>"English", "color"=>"red"}
def preferences(group = nil)
- group = group.is_a?(Symbol) ? group.to_s : group
-
unless preferences_group_loaded?(group)
preferences = preferences_group(group)
@@ -302,7 +300,6 @@ def preferences(group = nil)
# user.preferred?(:color) # => false
def preferred?(name, group = nil)
name = name.to_s
- group = group.is_a?(Symbol) ? group.to_s : group
assert_valid_preference(name)
value = preferred(name, group)
@@ -328,7 +325,6 @@ def preferred?(name, group = nil)
# user.preferred(:color) # => "blue"
def preferred(name, group = nil)
name = name.to_s
- group = group.is_a?(Symbol) ? group.to_s : group
assert_valid_preference(name)
if preferences_group(group).include?(name)
@@ -366,12 +362,15 @@ def preferred(name, group = nil)
# user.save!
def write_preference(name, value, group = nil)
name = name.to_s
- group = group.is_a?(Symbol) ? group.to_s : group
assert_valid_preference(name)
- unless preferences_changed(group).include?(name)
+ preferences_changed = preferences_changed_group(group)
+ if preferences_changed.include?(name)
+ old = preferences_changed[name]
+ preferences_changed.delete(name) unless preference_value_changed?(name, old, value)
+ else
old = clone_preference_value(name, group)
- preferences_changed(group)[name] = old if preference_value_changed?(name, old, value)
+ preferences_changed[name] = old if preference_value_changed?(name, old, value)
end
value = convert_number_column_value(value) if preference_definitions[name].number?
@@ -380,8 +379,71 @@ def write_preference(name, value, group = nil)
value
end
+ # Whether any attributes have unsaved changes.
+ #
+ # == Examples
+ #
+ # user = User.find(:first)
+ # user.preferences_changed? # => false
+ # user.write_preference(:color, 'red')
+ # user.preferences_changed? # => true
+ # user.save
+ # user.preferences_changed? # => false
+ #
+ # # Groups
+ # user.preferences_changed?(:car) # => false
+ # user.write_preference(:color, 'red', :car)
+ # user.preferences_changed(:car) # => true
+ def preferences_changed?(group = nil)
+ !preferences_changed_group(group).empty?
+ end
+
+ # A list of the preferences that have unsaved changes.
+ #
+ # == Examples
+ #
+ # user = User.find(:first)
+ # user.preferences_changed # => []
+ # user.write_preference(:color, 'red')
+ # user.preferences_changed # => ["color"]
+ # user.save
+ # user.preferences_changed # => []
+ #
+ # # Groups
+ # user.preferences_changed(:car) # => []
+ # user.write_preference(:color, 'red', :car)
+ # user.preferences_changed(:car) # => ["color"]
+ def preferences_changed(group = nil)
+ preferences_changed_group(group).keys
+ end
+
+ # A map of the preferences that have changed in the current object.
+ #
+ # == Examples
+ #
+ # user = User.find(:first)
+ # user.preferred(:color) # => nil
+ # user.preference_changes # => {}
+ #
+ # user.write_preference(:color, 'red')
+ # user.preference_changes # => {"color" => [nil, "red"]}
+ # user.save
+ # user.preference_changes # => {}
+ #
+ # # Groups
+ # user.preferred(:color, :car) # => nil
+ # user.preference_changes(:car) # => {}
+ # user.write_preference(:color, 'red', :car)
+ # user.preference_changes(:car) # => {"color" => [nil, "red"]}
+ def preference_changes(group = nil)
+ preferences_changed(group).inject({}) do |changes, preference|
+ changes[preference] = preference_change(preference, group)
+ changes
+ end
+ end
+
# Reloads the pereferences of this object as well as its attributes
- def reload(*args)
+ def reload(*args) #:nodoc:
result = super
@preferences.clear if @preferences
@@ -400,7 +462,7 @@ def assert_valid_preference(name)
# Gets the set of preferences identified by the given group
def preferences_group(group)
@preferences ||= {}
- @preferences[group] ||= {}
+ @preferences[group.is_a?(Symbol) ? group.to_s : group] ||= {}
end
# Determines whether the given group of preferences has already been
@@ -420,9 +482,20 @@ def clone_preference_value(name, group)
# Keeps track of all preferences that have been changed so that they can
# be properly updated in the database. Maps group -> preference -> value.
- def preferences_changed(group = nil)
+ def preferences_changed_group(group)
@preferences_changed ||= {}
- @preferences_changed[group] ||= {}
+ @preferences_changed[group.is_a?(Symbol) ? group.to_s : group] ||= {}
+ end
+
+ # Determines whether a preference changed in the given group
+ def preference_changed?(name, group)
+ preferences_changed_group(group).include?(name)
+ end
+
+ # Builds an array of [original_value, new_value] for the given preference.
+ # If the perference did not change, this will return nil.
+ def preference_change(name, group)
+ [preferences_changed_group(group)[name], preferred(name, group)] if preference_changed?(name, group)
end
# Determines whether the old value is different from the new value for the
View
234 test/functional/preferences_test.rb
@@ -123,6 +123,30 @@ def test_should_include_in_default_preferences
def test_should_only_have_default_preferences
assert_equal e = {'notifications' => nil}, @user.preferences
end
+
+ def test_should_not_query_preferences_changed
+ assert_equal false, @user.preferences_changed?
+ end
+
+ def test_should_not_query_group_preferences_changed
+ assert_equal false, @user.preferences_changed?(:chat)
+ end
+
+ def test_should_not_have_preferences_changed
+ assert_equal [], @user.preferences_changed
+ end
+
+ def test_should_not_have_group_preferences_changed
+ assert_equal [], @user.preferences_changed(:chat)
+ end
+
+ def test_should_not_have_preference_changes
+ assert_equal e = {}, @user.preference_changes
+ end
+
+ def test_should_not_have_group_preference_changes
+ assert_equal e = {}, @user.preference_changes(:chat)
+ end
end
class PreferencesWithCustomTypeTest < ModelPreferenceTest
@@ -498,21 +522,6 @@ def test_should_create_stored_preference_if_value_changed
assert_equal 1, @user.stored_preferences.count
end
- def test_should_reset_unsaved_preferences_after_reload
- @user.write_preference(:notifications, false)
- @user.reload
-
- assert_equal true, @user.preferred(:notifications)
- end
-
- def test_should_not_save_reset_preferences_after_reload
- @user.write_preference(:notifications, false)
- @user.reload
- @user.save!
-
- assert @user.stored_preferences.empty?
- end
-
def test_should_overwrite_existing_stored_preference_if_value_changed
preference = create_preference(:owner => @user, :name => 'notifications', :value => true)
@@ -648,6 +657,128 @@ def test_should_set_group_attributes_on_stored_preferences
end
end
+class PreferencesAfterChangingPreferenceTest < ModelPreferenceTest
+ def setup
+ User.preference :notifications, :boolean, :default => true
+ User.preference :language, :string, :default => 'English'
+ @user = create_user
+
+ @user.write_preference(:notifications, false)
+ end
+
+ def test_should_query_preferences_changed
+ assert_equal true, @user.preferences_changed?
+ end
+
+ def test_should_not_query_preferences_changed_for_group
+ assert_equal false, @user.preferences_changed?(:chat)
+ end
+
+ def test_should_have_preferences_changed
+ assert_equal ['notifications'], @user.preferences_changed
+ end
+
+ def test_should_not_build_same_preferences_changed_result
+ assert_not_same @user.preferences_changed, @user.preferences_changed
+ end
+
+ def test_should_not_have_preferences_changed_for_group
+ assert_equal [], @user.preferences_changed(:chat)
+ end
+
+ def test_should_track_multiple_preferences_changed
+ @user.write_preference(:language, 'Latin')
+ assert_equal ['language', 'notifications'], @user.preferences_changed.sort
+ end
+
+ def test_should_have_preference_changes
+ assert_equal e = {'notifications' => [true, false]}, @user.preference_changes
+ end
+
+ def test_should_not_build_same_preference_changes_result
+ assert_not_same @user.preference_changes, @user.preference_changes
+ end
+
+ def test_should_not_have_preference_changes_for_group
+ assert_equal e = {}, @user.preference_changes(:chat)
+ end
+
+ def test_should_use_latest_value_for_preference_changes
+ @user.write_preference(:notifications, nil)
+ assert_equal e = {'notifications' => [true, nil]}, @user.preference_changes
+ end
+
+ def test_should_use_cloned_old_value_for_preference_changes
+ old_value = @user.preferred(:language)
+ @user.write_preference(:language, 'Latin')
+
+ tracked_old_value = @user.preference_changes['language'][0]
+ assert_equal old_value, tracked_old_value
+ assert_not_same old_value, tracked_old_value
+ end
+
+ def test_should_track_multiple_preference_changes
+ @user.write_preference(:language, 'Latin')
+ assert_equal e = {'notifications' => [true, false], 'language' => ['English', 'Latin']}, @user.preference_changes
+ end
+end
+
+class PreferencesAfterChangingGroupPreferenceTest < ModelPreferenceTest
+ def setup
+ User.preference :notifications, :boolean, :default => true
+ User.preference :language, :string, :default => 'English'
+ @user = create_user
+
+ @user.write_preference(:notifications, false, :chat)
+ end
+
+ def test_should_not_query_preferences_changed
+ assert_equal false, @user.preferences_changed?
+ end
+
+ def test_should_query_preferences_changed_for_group
+ assert_equal true, @user.preferences_changed?(:chat)
+ end
+
+ def test_should_have_preferences_changed
+ assert_equal [], @user.preferences_changed
+ end
+
+ def test_should_not_have_preferences_changed_for_group
+ assert_equal ['notifications'], @user.preferences_changed(:chat)
+ end
+
+ def test_should_have_preference_changes
+ assert_equal e = {}, @user.preference_changes
+ end
+
+ def test_should_not_have_preference_changes_for_group
+ assert_equal e = {'notifications' => [true, false]}, @user.preference_changes(:chat)
+ end
+end
+
+class PreferencesAfterRevertPreferenceChangeTest < ModelPreferenceTest
+ def setup
+ User.preference :notifications, :boolean, :default => true
+
+ @user = create_user
+ @user.write_preference(:notifications, false)
+ @user.write_preference(:notifications, true)
+ end
+
+ def test_should_not_query_preferences_changed
+ assert_equal false, @user.preferences_changed?
+ end
+
+ def test_should_not_have_preferences_changed
+ assert_equal [], @user.preferences_changed
+ end
+
+ def test_should_not_have_preference_changes
+ assert_equal e = {}, @user.preference_changes
+ end
+end
+
class PreferencesLookupTest < ModelPreferenceTest
def setup
User.preference :notifications, :boolean, :default => true
@@ -826,6 +957,79 @@ def test_not_include_group_preferences_by_default
end
end
+class PreferencesAfterBeingReloadedTest < ModelPreferenceTest
+ def setup
+ User.preference :notifications, :boolean, :default => true
+
+ @user = create_user
+ @user.write_preference(:notifications, false)
+ @user.reload
+ end
+
+ def test_should_reset_unsaved_preferences
+ assert_equal true, @user.preferred(:notifications)
+ end
+
+ def test_should_not_save_reset_preferences
+ @user.save!
+ assert @user.stored_preferences.empty?
+ end
+
+ def test_should_reset_preferences
+ assert_equal e = {'notifications' => true}, @user.preferences
+ end
+
+ def test_should_clear_query_cache_for_preferences
+ assert_queries(1) { @user.preferences }
+ end
+
+ def test_should_reset_preferences_changed_query
+ assert_equal false, @user.preferences_changed?
+ end
+
+ def test_should_reset_preferences_changed
+ assert_equal [], @user.preferences_changed
+ end
+
+ def test_should_reset_preference_changes
+ assert_equal e = {}, @user.preference_changes
+ end
+end
+
+class PreferencesForGroupAfterBeingReloadedTest < ModelPreferenceTest
+ def setup
+ User.preference :notifications, :boolean, :default => true
+
+ @user = create_user
+ @user.write_preference(:notifications, false, :chat)
+ @user.reload
+ end
+
+ def test_should_reset_unsaved_preferences
+ assert_equal true, @user.preferred(:notifications, :chat)
+ end
+
+ def test_should_reset_preferences
+ assert_equal e = {'notifications' => true}, @user.preferences(:chat)
+ end
+
+ def test_should_clear_query_cache_for_preferences
+ assert_queries(1) { @user.preferences(:chat) }
+ end
+
+ def test_should_reset_preferences_changed_query
+ assert_equal false, @user.preferences_changed?(:chat)
+ end
+
+ def test_should_reset_preferences_changed
+ assert_equal [], @user.preferences_changed(:chat)
+ end
+
+ def test_should_reset_preference_changes
+ assert_equal e = {}, @user.preference_changes(:chat)
+ end
+end
+
class PreferencesWithScopeTest < ModelPreferenceTest
def setup
User.preference :notifications

0 comments on commit 1ed8cd2

Please sign in to comment.