preferences 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +4 -0
- data/Rakefile +1 -1
- data/app/models/preference.rb +11 -12
- data/lib/preferences/preference_definition.rb +5 -5
- data/lib/preferences.rb +45 -44
- data/test/factory.rb +1 -1
- data/test/unit/preference_definition_test.rb +2 -2
- data/test/unit/preference_test.rb +13 -13
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
data/Rakefile
CHANGED
data/app/models/preference.rb
CHANGED
@@ -5,20 +5,20 @@
|
|
5
5
|
# In addition to simple named preferences, preferences can also be grouped by
|
6
6
|
# a particular value, be it a string or ActiveRecord object. For example, a
|
7
7
|
# User may have a preferred color for a particular Car. In this case, the
|
8
|
-
# +owner+ is the User, the +
|
9
|
-
# This allows preferences to have a sort of context around them.
|
8
|
+
# +owner+ is the User record, the +name+ is "color", and the +group+ is the
|
9
|
+
# Car record. This allows preferences to have a sort of context around them.
|
10
10
|
class Preference < ActiveRecord::Base
|
11
|
-
belongs_to
|
12
|
-
belongs_to
|
11
|
+
belongs_to :owner, :polymorphic => true
|
12
|
+
belongs_to :group, :polymorphic => true
|
13
13
|
|
14
|
-
validates_presence_of :
|
14
|
+
validates_presence_of :name, :owner_id, :owner_type
|
15
15
|
validates_presence_of :group_type, :if => :group_id?
|
16
16
|
|
17
17
|
class << self
|
18
18
|
# Splits the given group into its corresponding id and type. For simple
|
19
|
-
# primitives, the id will be nil. For complex types, specifically
|
20
|
-
# objects, the id is the unique identifier stored in the
|
21
|
-
# record.
|
19
|
+
# primitives, the id will be nil. For complex types, specifically
|
20
|
+
# ActiveRecord objects, the id is the unique identifier stored in the
|
21
|
+
# database for the record.
|
22
22
|
#
|
23
23
|
# For example,
|
24
24
|
#
|
@@ -36,7 +36,7 @@ class Preference < ActiveRecord::Base
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
# The definition
|
39
|
+
# The definition of the preference as defined in the owner's model
|
40
40
|
def definition
|
41
41
|
# Optimize number of queries to the database by only looking up the actual
|
42
42
|
# owner record for STI cases when the definition can't be found in the
|
@@ -58,9 +58,8 @@ class Preference < ActiveRecord::Base
|
|
58
58
|
alias_method_chain :group, :optional_lookup
|
59
59
|
|
60
60
|
private
|
61
|
-
# Finds the definition for this preference
|
62
|
-
# class.
|
61
|
+
# Finds the definition for this preference in the given owner class.
|
63
62
|
def find_definition(owner_class)
|
64
|
-
owner_class.respond_to?(:preference_definitions) && owner_class.preference_definitions[
|
63
|
+
owner_class.respond_to?(:preference_definitions) && owner_class.preference_definitions[name]
|
65
64
|
end
|
66
65
|
end
|
@@ -1,23 +1,23 @@
|
|
1
1
|
module Preferences
|
2
2
|
# Represents the definition of a preference for a particular model
|
3
3
|
class PreferenceDefinition
|
4
|
-
def initialize(
|
4
|
+
def initialize(name, *args) #:nodoc:
|
5
5
|
options = args.extract_options!
|
6
6
|
options.assert_valid_keys(:default)
|
7
7
|
|
8
8
|
@type = args.first ? args.first.to_s : 'boolean'
|
9
9
|
|
10
10
|
# Create a column that will be responsible for typecasting
|
11
|
-
@column = ActiveRecord::ConnectionAdapters::Column.new(
|
11
|
+
@column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], @type == 'any' ? nil : @type)
|
12
12
|
end
|
13
13
|
|
14
|
-
# The
|
15
|
-
def
|
14
|
+
# The name of the preference
|
15
|
+
def name
|
16
16
|
@column.name
|
17
17
|
end
|
18
18
|
|
19
19
|
# The default value to use for the preference in case none have been
|
20
|
-
# previously defined
|
20
|
+
# previously defined
|
21
21
|
def default_value
|
22
22
|
@column.default
|
23
23
|
end
|
data/lib/preferences.rb
CHANGED
@@ -23,7 +23,7 @@ require 'preferences/preference_definition'
|
|
23
23
|
# == Validations
|
24
24
|
#
|
25
25
|
# Since the generated accessors for a preference allow the preference to be
|
26
|
-
# treated just like regular ActiveRecord
|
26
|
+
# treated just like regular ActiveRecord attributes, they can also be
|
27
27
|
# validated against in the same way. For example,
|
28
28
|
#
|
29
29
|
# class User < ActiveRecord::Base
|
@@ -76,8 +76,8 @@ module Preferences
|
|
76
76
|
#
|
77
77
|
# == Generated accessors
|
78
78
|
#
|
79
|
-
# In addition to calling <tt>prefers?</tt> and +preferred+ on a record,
|
80
|
-
# can also use the shortcut accessor methods that are generated when a
|
79
|
+
# In addition to calling <tt>prefers?</tt> and +preferred+ on a record,
|
80
|
+
# you can also use the shortcut accessor methods that are generated when a
|
81
81
|
# preference is defined. For example,
|
82
82
|
#
|
83
83
|
# class User < ActiveRecord::Base
|
@@ -114,7 +114,7 @@ module Preferences
|
|
114
114
|
# user.preferred_color?(car) # => true
|
115
115
|
#
|
116
116
|
# user.save! # => true
|
117
|
-
def preference(
|
117
|
+
def preference(name, *args)
|
118
118
|
unless included_modules.include?(InstanceMethods)
|
119
119
|
class_inheritable_hash :preference_definitions
|
120
120
|
self.preference_definitions = {}
|
@@ -130,32 +130,32 @@ module Preferences
|
|
130
130
|
end
|
131
131
|
|
132
132
|
# Create the definition
|
133
|
-
|
134
|
-
definition = PreferenceDefinition.new(
|
135
|
-
self.preference_definitions[
|
136
|
-
self.default_preferences[
|
133
|
+
name = name.to_s
|
134
|
+
definition = PreferenceDefinition.new(name, *args)
|
135
|
+
self.preference_definitions[name] = definition
|
136
|
+
self.default_preferences[name] = definition.default_value
|
137
137
|
|
138
|
-
# Create short-hand accessor methods, making sure that the
|
138
|
+
# Create short-hand accessor methods, making sure that the name
|
139
139
|
# is method-safe in terms of what characters are allowed
|
140
|
-
|
140
|
+
name = name.gsub(/[^A-Za-z0-9_-]/, '').underscore
|
141
141
|
|
142
142
|
# Query lookup
|
143
|
-
define_method("preferred_#{
|
144
|
-
preferred?(
|
143
|
+
define_method("preferred_#{name}?") do |*group|
|
144
|
+
preferred?(name, group.first)
|
145
145
|
end
|
146
|
-
alias_method "prefers_#{
|
146
|
+
alias_method "prefers_#{name}?", "preferred_#{name}?"
|
147
147
|
|
148
148
|
# Reader
|
149
|
-
define_method("preferred_#{
|
150
|
-
preferred(
|
149
|
+
define_method("preferred_#{name}") do |*group|
|
150
|
+
preferred(name, group.first)
|
151
151
|
end
|
152
|
-
alias_method "prefers_#{
|
152
|
+
alias_method "prefers_#{name}", "preferred_#{name}"
|
153
153
|
|
154
154
|
# Writer
|
155
|
-
define_method("preferred_#{
|
156
|
-
set_preference(*([
|
155
|
+
define_method("preferred_#{name}=") do |*args|
|
156
|
+
set_preference(*([name] + [args].flatten))
|
157
157
|
end
|
158
|
-
alias_method "prefers_#{
|
158
|
+
alias_method "prefers_#{name}=", "preferred_#{name}="
|
159
159
|
|
160
160
|
definition
|
161
161
|
end
|
@@ -211,7 +211,7 @@ module Preferences
|
|
211
211
|
# Find all of the stored preferences
|
212
212
|
stored_preferences = self.stored_preferences.find(:all, :conditions => conditions)
|
213
213
|
|
214
|
-
# Hashify
|
214
|
+
# Hashify name -> value or group -> name -> value
|
215
215
|
stored_preferences.inject(self.class.default_preferences.dup) do |all_preferences, preference|
|
216
216
|
if !group && (preference_group = preference.group)
|
217
217
|
preferences = all_preferences[preference_group] ||= self.class.default_preferences.dup
|
@@ -219,13 +219,13 @@ module Preferences
|
|
219
219
|
preferences = all_preferences
|
220
220
|
end
|
221
221
|
|
222
|
-
preferences[preference.
|
222
|
+
preferences[preference.name] = preference.value
|
223
223
|
all_preferences
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
227
|
-
# Queries whether or not a value is present for the given
|
228
|
-
# is dependent on how the value is type-casted.
|
227
|
+
# Queries whether or not a value is present for the given preference.
|
228
|
+
# This is dependent on how the value is type-casted.
|
229
229
|
#
|
230
230
|
# == Examples
|
231
231
|
#
|
@@ -242,15 +242,15 @@ module Preferences
|
|
242
242
|
# user.set_preference(:color, nil)
|
243
243
|
# user.preferred(:color) # => nil
|
244
244
|
# user.preferred?(:color) # => false
|
245
|
-
def preferred?(
|
246
|
-
|
245
|
+
def preferred?(name, group = nil)
|
246
|
+
name = name.to_s
|
247
247
|
|
248
|
-
value = preferred(
|
249
|
-
preference_definitions[
|
248
|
+
value = preferred(name, group)
|
249
|
+
preference_definitions[name].query(value)
|
250
250
|
end
|
251
251
|
alias_method :prefers?, :preferred?
|
252
252
|
|
253
|
-
# Gets the actual value stored for the given
|
253
|
+
# Gets the actual value stored for the given preference, or the default
|
254
254
|
# value if nothing is present.
|
255
255
|
#
|
256
256
|
# == Examples
|
@@ -266,27 +266,27 @@ module Preferences
|
|
266
266
|
#
|
267
267
|
# user.set_preference(:color, 'blue')
|
268
268
|
# user.preferred(:color) # => "blue"
|
269
|
-
def preferred(
|
270
|
-
|
269
|
+
def preferred(name, group = nil)
|
270
|
+
name = name.to_s
|
271
271
|
|
272
|
-
if @preference_values && @preference_values[
|
273
|
-
# Value for this
|
272
|
+
if @preference_values && @preference_values[group] && @preference_values[group].include?(name)
|
273
|
+
# Value for this group/name has been written, but not saved yet:
|
274
274
|
# grab from the pending values
|
275
|
-
value = @preference_values[
|
275
|
+
value = @preference_values[group][name]
|
276
276
|
else
|
277
277
|
# Split the group being filtered
|
278
278
|
group_id, group_type = Preference.split_group(group)
|
279
279
|
|
280
280
|
# Grab the first preference; if it doesn't exist, use the default value
|
281
|
-
preference = stored_preferences.find(:first, :conditions => {:
|
282
|
-
value = preference ? preference.value : preference_definitions[
|
281
|
+
preference = stored_preferences.find(:first, :conditions => {:name => name, :group_id => group_id, :group_type => group_type})
|
282
|
+
value = preference ? preference.value : preference_definitions[name].default_value
|
283
283
|
end
|
284
284
|
|
285
285
|
value
|
286
286
|
end
|
287
287
|
alias_method :prefers, :preferred
|
288
288
|
|
289
|
-
# Sets a new value for the given
|
289
|
+
# Sets a new value for the given preference. The actual Preference record
|
290
290
|
# is *not* created until this record is saved. In this way, preferences
|
291
291
|
# act *exactly* the same as attributes. They can be written to and
|
292
292
|
# validated against, but won't actually be written to the database until
|
@@ -300,12 +300,12 @@ module Preferences
|
|
300
300
|
#
|
301
301
|
# user.set_preference(:color, 'blue', Car.first) # => "blue"
|
302
302
|
# user.save!
|
303
|
-
def set_preference(
|
304
|
-
|
303
|
+
def set_preference(name, value, group = nil)
|
304
|
+
name = name.to_s
|
305
305
|
|
306
306
|
@preference_values ||= {}
|
307
|
-
@preference_values[
|
308
|
-
@preference_values[
|
307
|
+
@preference_values[group] ||= {}
|
308
|
+
@preference_values[group][name] = value
|
309
309
|
|
310
310
|
value
|
311
311
|
end
|
@@ -315,10 +315,11 @@ module Preferences
|
|
315
315
|
# was last saved
|
316
316
|
def update_preferences
|
317
317
|
if @preference_values
|
318
|
-
@preference_values.each do |
|
319
|
-
|
320
|
-
|
321
|
-
|
318
|
+
@preference_values.each do |group, new_preferences|
|
319
|
+
group_id, group_type = Preference.split_group(group)
|
320
|
+
|
321
|
+
new_preferences.each do |name, value|
|
322
|
+
attributes = {:name => name, :group_id => group_id, :group_type => group_type}
|
322
323
|
|
323
324
|
# Find an existing preference or build a new one
|
324
325
|
preference = stored_preferences.find(:first, :conditions => attributes) || stored_preferences.build(attributes)
|
data/test/factory.rb
CHANGED
@@ -5,8 +5,8 @@ class PreferenceDefinitionByDefaultTest < ActiveSupport::TestCase
|
|
5
5
|
@definition = Preferences::PreferenceDefinition.new(:notifications)
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
assert_equal 'notifications', @definition.
|
8
|
+
def test_should_have_a_name
|
9
|
+
assert_equal 'notifications', @definition.name
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_should_not_have_a_default_value
|
@@ -5,8 +5,8 @@ class PreferenceByDefaultTest < ActiveSupport::TestCase
|
|
5
5
|
@preference = Preference.new
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
assert @preference.
|
8
|
+
def test_should_not_have_a_name
|
9
|
+
assert @preference.name.blank?
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_should_not_have_an_owner
|
@@ -40,10 +40,10 @@ class PreferenceTest < ActiveSupport::TestCase
|
|
40
40
|
assert preference.valid?
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
preference = new_preference(:
|
43
|
+
def test_should_require_a_name
|
44
|
+
preference = new_preference(:name => nil)
|
45
45
|
assert !preference.valid?
|
46
|
-
assert preference.errors.invalid?(:
|
46
|
+
assert preference.errors.invalid?(:name)
|
47
47
|
end
|
48
48
|
|
49
49
|
def test_should_require_an_owner_id
|
@@ -84,7 +84,7 @@ class PreferenceTest < ActiveSupport::TestCase
|
|
84
84
|
def test_should_protect_attributes_from_mass_assignment
|
85
85
|
preference = Preference.new(
|
86
86
|
:id => 1,
|
87
|
-
:
|
87
|
+
:name => 'notifications',
|
88
88
|
:value => '123',
|
89
89
|
:owner_id => 1,
|
90
90
|
:owner_type => 'User',
|
@@ -93,7 +93,7 @@ class PreferenceTest < ActiveSupport::TestCase
|
|
93
93
|
)
|
94
94
|
|
95
95
|
assert_nil preference.id
|
96
|
-
assert_equal 'notifications', preference.
|
96
|
+
assert_equal 'notifications', preference.name
|
97
97
|
assert_equal '123', preference.value
|
98
98
|
assert_equal 1, preference.owner_id
|
99
99
|
assert_equal 'User', preference.owner_type
|
@@ -132,7 +132,7 @@ class PreferenceAfterBeingCreatedTest < ActiveSupport::TestCase
|
|
132
132
|
def setup
|
133
133
|
User.preference :notifications, :boolean
|
134
134
|
|
135
|
-
@preference = create_preference(:
|
135
|
+
@preference = create_preference(:name => 'notifications')
|
136
136
|
end
|
137
137
|
|
138
138
|
def test_should_have_an_owner
|
@@ -178,18 +178,18 @@ class PreferenceWithActiveRecordGroupTest < ActiveSupport::TestCase
|
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
181
|
-
class
|
181
|
+
class PreferenceWithBooleanTypeTest < ActiveSupport::TestCase
|
182
182
|
def setup
|
183
183
|
User.preference :notifications, :boolean
|
184
184
|
end
|
185
185
|
|
186
186
|
def test_should_type_cast_nil_values
|
187
|
-
preference = new_preference(:
|
187
|
+
preference = new_preference(:name => 'notifications', :value => nil)
|
188
188
|
assert_nil preference.value
|
189
189
|
end
|
190
190
|
|
191
191
|
def test_should_type_cast_numeric_values
|
192
|
-
preference = new_preference(:
|
192
|
+
preference = new_preference(:name => 'notifications', :value => 0)
|
193
193
|
assert_equal false, preference.value
|
194
194
|
|
195
195
|
preference.value = 1
|
@@ -197,7 +197,7 @@ class PreferenceWithBooleanAttributeTest < ActiveSupport::TestCase
|
|
197
197
|
end
|
198
198
|
|
199
199
|
def test_should_type_cast_boolean_values
|
200
|
-
preference = new_preference(:
|
200
|
+
preference = new_preference(:name => 'notifications', :value => false)
|
201
201
|
assert_equal false, preference.value
|
202
202
|
|
203
203
|
preference.value = true
|
@@ -213,7 +213,7 @@ end
|
|
213
213
|
class PreferenceWithSTIOwnerTest < ActiveSupport::TestCase
|
214
214
|
def setup
|
215
215
|
@manager = create_manager
|
216
|
-
@preference = create_preference(:owner => @manager, :
|
216
|
+
@preference = create_preference(:owner => @manager, :name => 'health_insurance', :value => true)
|
217
217
|
end
|
218
218
|
|
219
219
|
def test_should_have_an_owner
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: preferences
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-25 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|