preferences 0.1.5 → 0.2.0
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/lib/preferences/preference_definition.rb +37 -39
- data/lib/preferences.rb +304 -306
- data/test/unit/preference_definition_test.rb +7 -7
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,44 +1,42 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
options.assert_valid_keys(:default)
|
8
|
-
|
9
|
-
@type = args.first ? args.first.to_s : 'boolean'
|
10
|
-
|
11
|
-
# Create a column that will be responsible for typecasting
|
12
|
-
@column = ActiveRecord::ConnectionAdapters::Column.new(attribute.to_s, options[:default], @type == 'any' ? nil : @type)
|
13
|
-
end
|
14
|
-
|
15
|
-
# The attribute which is being preferenced
|
16
|
-
def attribute
|
17
|
-
@column.name
|
18
|
-
end
|
19
|
-
|
20
|
-
# The default value to use for the preference in case none have been
|
21
|
-
# previously defined
|
22
|
-
def default_value
|
23
|
-
@column.default
|
24
|
-
end
|
1
|
+
module Preferences
|
2
|
+
# Represents the definition of a preference for a particular model
|
3
|
+
class PreferenceDefinition
|
4
|
+
def initialize(attribute, *args) #:nodoc:
|
5
|
+
options = args.extract_options!
|
6
|
+
options.assert_valid_keys(:default)
|
25
7
|
|
26
|
-
|
27
|
-
# This uses ActiveRecord's typecast functionality so the same rules for
|
28
|
-
# typecasting a model's columns apply here.
|
29
|
-
def type_cast(value)
|
30
|
-
@type == 'any' ? value : @column.type_cast(value)
|
31
|
-
end
|
8
|
+
@type = args.first ? args.first.to_s : 'boolean'
|
32
9
|
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
10
|
+
# Create a column that will be responsible for typecasting
|
11
|
+
@column = ActiveRecord::ConnectionAdapters::Column.new(attribute.to_s, options[:default], @type == 'any' ? nil : @type)
|
12
|
+
end
|
13
|
+
|
14
|
+
# The attribute which is being preferenced
|
15
|
+
def attribute
|
16
|
+
@column.name
|
17
|
+
end
|
18
|
+
|
19
|
+
# The default value to use for the preference in case none have been
|
20
|
+
# previously defined
|
21
|
+
def default_value
|
22
|
+
@column.default
|
23
|
+
end
|
24
|
+
|
25
|
+
# Typecasts the value based on the type of preference that was defined.
|
26
|
+
# This uses ActiveRecord's typecast functionality so the same rules for
|
27
|
+
# typecasting a model's columns apply here.
|
28
|
+
def type_cast(value)
|
29
|
+
@type == 'any' ? value : @column.type_cast(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Typecasts the value to true/false depending on the type of preference
|
33
|
+
def query(value)
|
34
|
+
if !(value = type_cast(value))
|
35
|
+
false
|
36
|
+
elsif @column.number?
|
37
|
+
!value.zero?
|
38
|
+
else
|
39
|
+
!value.blank?
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
data/lib/preferences.rb
CHANGED
@@ -1,336 +1,334 @@
|
|
1
1
|
require 'preferences/preference_definition'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
module
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
self.preference_definitions = {}
|
120
|
-
|
121
|
-
class_inheritable_hash :default_preferences
|
122
|
-
self.default_preferences = {}
|
123
|
-
|
124
|
-
has_many :stored_preferences,
|
125
|
-
:as => :owner,
|
126
|
-
:class_name => 'Preference'
|
127
|
-
|
128
|
-
after_save :update_preferences
|
129
|
-
|
130
|
-
include PluginAWeek::Preferences::InstanceMethods
|
131
|
-
end
|
3
|
+
# Adds support for defining preferences on ActiveRecord models.
|
4
|
+
#
|
5
|
+
# == Saving preferences
|
6
|
+
#
|
7
|
+
# Preferences are not automatically saved when they are set. You must save
|
8
|
+
# the record that the preferences were set on.
|
9
|
+
#
|
10
|
+
# For example,
|
11
|
+
#
|
12
|
+
# class User < ActiveRecord::Base
|
13
|
+
# preference :notifications
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# u = User.new(:login => 'admin', :prefers_notifications => false)
|
17
|
+
# u.save!
|
18
|
+
#
|
19
|
+
# u = User.find_by_login('admin')
|
20
|
+
# u.attributes = {:prefers_notifications => true}
|
21
|
+
# u.save!
|
22
|
+
#
|
23
|
+
# == Validations
|
24
|
+
#
|
25
|
+
# Since the generated accessors for a preference allow the preference to be
|
26
|
+
# treated just like regular ActiveRecord column attributes, they can also be
|
27
|
+
# validated against in the same way. For example,
|
28
|
+
#
|
29
|
+
# class User < ActiveRecord::Base
|
30
|
+
# preference :color, :string
|
31
|
+
#
|
32
|
+
# validates_presence_of :preferred_color
|
33
|
+
# validates_inclusion_of :preferred_color, :in => %w(red green blue)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# u = User.new
|
37
|
+
# u.valid? # => false
|
38
|
+
# u.errors.on(:preferred_color) # => "can't be blank"
|
39
|
+
#
|
40
|
+
# u.preferred_color = 'white'
|
41
|
+
# u.valid? # => false
|
42
|
+
# u.errors.on(:preferred_color) # => "is not included in the list"
|
43
|
+
#
|
44
|
+
# u.preferred_color = 'red'
|
45
|
+
# u.valid? # => true
|
46
|
+
module Preferences
|
47
|
+
module MacroMethods
|
48
|
+
# Defines a new preference for all records in the model. By default,
|
49
|
+
# preferences are assumed to have a boolean data type, so all values will
|
50
|
+
# be typecasted to true/false based on ActiveRecord rules.
|
51
|
+
#
|
52
|
+
# Configuration options:
|
53
|
+
# * +default+ - The default value for the preference. Default is nil.
|
54
|
+
#
|
55
|
+
# == Examples
|
56
|
+
#
|
57
|
+
# The example below shows the various ways to define a preference for a
|
58
|
+
# particular model.
|
59
|
+
#
|
60
|
+
# class User < ActiveRecord::Base
|
61
|
+
# preference :notifications, :default => false
|
62
|
+
# preference :color, :string, :default => 'red'
|
63
|
+
# preference :favorite_number, :integer
|
64
|
+
# preference :data, :any # Allows any data type to be stored
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# All preferences are also inherited by subclasses.
|
68
|
+
#
|
69
|
+
# == Associations
|
70
|
+
#
|
71
|
+
# After the first preference is defined, the following associations are
|
72
|
+
# created for the model:
|
73
|
+
# * +stored_preferences+ - A collection of all the custom preferences specified for a record. This will not include default preferences unless they have been explicitly set.
|
74
|
+
#
|
75
|
+
# == Generated accessors
|
76
|
+
#
|
77
|
+
# In addition to calling <tt>prefers?</tt> and +preferred+ on a record, you
|
78
|
+
# can also use the shortcut accessor methods that are generated when a
|
79
|
+
# preference is defined. For example,
|
80
|
+
#
|
81
|
+
# class User < ActiveRecord::Base
|
82
|
+
# preference :notifications
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# ...generates the following methods:
|
86
|
+
# * <tt>prefers_notifications?</tt> - Whether a value has been specified, i.e. <tt>record.prefers?(:notifications)</tt>
|
87
|
+
# * <tt>prefers_notifications</tt> - The actual value stored, i.e. <tt>record.prefers(:notifications)</tt>
|
88
|
+
# * <tt>prefers_notifications=(value)</tt> - Sets a new value, i.e. <tt>record.set_preference(:notifications, value)</tt>
|
89
|
+
# * <tt>preferred_notifications?</tt> - Whether a value has been specified, i.e. <tt>record.preferred?(:notifications)</tt>
|
90
|
+
# * <tt>preferred_notifications</tt> - The actual value stored, i.e. <tt>record.preferred(:notifications)</tt>
|
91
|
+
# * <tt>preferred_notifications=(value)</tt> - Sets a new value, i.e. <tt>record.set_preference(:notifications, value)</tt>
|
92
|
+
#
|
93
|
+
# Notice that there are two tenses used depending on the context of the
|
94
|
+
# preference. Conventionally, <tt>prefers_notifications?</tt> is better
|
95
|
+
# for accessing boolean preferences, while +preferred_color+ is better for
|
96
|
+
# accessing non-boolean preferences.
|
97
|
+
#
|
98
|
+
# Example:
|
99
|
+
#
|
100
|
+
# user = User.find(:first)
|
101
|
+
# user.prefers_notifications? # => false
|
102
|
+
# user.prefers_notifications # => false
|
103
|
+
# user.preferred_color? # => true
|
104
|
+
# user.preferred_color # => 'red'
|
105
|
+
# user.preferred_color = 'blue' # => 'blue'
|
106
|
+
#
|
107
|
+
# user.prefers_notifications = true
|
108
|
+
#
|
109
|
+
# car = Car.find(:first)
|
110
|
+
# user.preferred_color = 'red', car # => 'red'
|
111
|
+
# user.preferred_color(car) # => 'red'
|
112
|
+
# user.preferred_color?(car) # => true
|
113
|
+
#
|
114
|
+
# user.save! # => true
|
115
|
+
def preference(attribute, *args)
|
116
|
+
unless included_modules.include?(InstanceMethods)
|
117
|
+
class_inheritable_hash :preference_definitions
|
118
|
+
self.preference_definitions = {}
|
132
119
|
|
133
|
-
|
134
|
-
|
135
|
-
definition = PreferenceDefinition.new(attribute, *args)
|
136
|
-
self.preference_definitions[attribute] = definition
|
137
|
-
self.default_preferences[attribute] = definition.default_value
|
120
|
+
class_inheritable_hash :default_preferences
|
121
|
+
self.default_preferences = {}
|
138
122
|
|
139
|
-
|
140
|
-
|
141
|
-
|
123
|
+
has_many :stored_preferences,
|
124
|
+
:as => :owner,
|
125
|
+
:class_name => 'Preference'
|
142
126
|
|
143
|
-
|
144
|
-
define_method("preferred_#{attribute}?") do |*group|
|
145
|
-
preferred?(attribute, group.first)
|
146
|
-
end
|
147
|
-
alias_method "prefers_#{attribute}?", "preferred_#{attribute}?"
|
127
|
+
after_save :update_preferences
|
148
128
|
|
149
|
-
|
150
|
-
define_method("preferred_#{attribute}") do |*group|
|
151
|
-
preferred(attribute, group.first)
|
152
|
-
end
|
153
|
-
alias_method "prefers_#{attribute}", "preferred_#{attribute}"
|
154
|
-
|
155
|
-
# Writer
|
156
|
-
define_method("preferred_#{attribute}=") do |*args|
|
157
|
-
set_preference(*([attribute] + [args].flatten))
|
158
|
-
end
|
159
|
-
alias_method "prefers_#{attribute}=", "preferred_#{attribute}="
|
160
|
-
|
161
|
-
definition
|
129
|
+
include Preferences::InstanceMethods
|
162
130
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
131
|
+
|
132
|
+
# Create the definition
|
133
|
+
attribute = attribute.to_s
|
134
|
+
definition = PreferenceDefinition.new(attribute, *args)
|
135
|
+
self.preference_definitions[attribute] = definition
|
136
|
+
self.default_preferences[attribute] = definition.default_value
|
137
|
+
|
138
|
+
# Create short-hand accessor methods, making sure that the attribute
|
139
|
+
# is method-safe in terms of what characters are allowed
|
140
|
+
attribute = attribute.gsub(/[^A-Za-z0-9_-]/, '').underscore
|
141
|
+
|
142
|
+
# Query lookup
|
143
|
+
define_method("preferred_#{attribute}?") do |*group|
|
144
|
+
preferred?(attribute, group.first)
|
170
145
|
end
|
146
|
+
alias_method "prefers_#{attribute}?", "preferred_#{attribute}?"
|
171
147
|
|
172
|
-
#
|
173
|
-
#
|
174
|
-
|
175
|
-
#
|
176
|
-
# == Examples
|
177
|
-
#
|
178
|
-
# A user with no stored values:
|
179
|
-
# user = User.find(:first)
|
180
|
-
# user.preferences
|
181
|
-
# => {"language"=>"English", "color"=>nil}
|
182
|
-
#
|
183
|
-
# A user with stored values for a particular group:
|
184
|
-
# user.preferred_color = 'red', 'cars'
|
185
|
-
# user.preferences
|
186
|
-
# => {"language"=>"English", "color"=>nil, "cars"=>{"language=>"English", "color"=>"red"}}
|
187
|
-
#
|
188
|
-
# Getting preference values *just* for the owning record (i.e. excluding groups):
|
189
|
-
# user.preferences(nil)
|
190
|
-
# => {"language"=>"English", "color"=>nil}
|
191
|
-
#
|
192
|
-
# Getting preference values for a particular group:
|
193
|
-
# user.preferences('cars')
|
194
|
-
# => {"language"=>"English", "color"=>"red"}
|
195
|
-
def preferences(*args)
|
196
|
-
if args.empty?
|
197
|
-
group = nil
|
198
|
-
conditions = {}
|
199
|
-
else
|
200
|
-
group = args.first
|
201
|
-
|
202
|
-
# Split the actual group into its different parts (id/type) in case
|
203
|
-
# a record is passed in
|
204
|
-
group_id, group_type = Preference.split_group(group)
|
205
|
-
conditions = {:group_id => group_id, :group_type => group_type}
|
206
|
-
end
|
207
|
-
|
208
|
-
# Find all of the stored preferences
|
209
|
-
stored_preferences = self.stored_preferences.find(:all, :conditions => conditions)
|
210
|
-
|
211
|
-
# Hashify attribute -> value or group -> attribute -> value
|
212
|
-
stored_preferences.inject(self.class.default_preferences.dup) do |all_preferences, preference|
|
213
|
-
if !group && (preference_group = preference.group)
|
214
|
-
preferences = all_preferences[preference_group] ||= self.class.default_preferences.dup
|
215
|
-
else
|
216
|
-
preferences = all_preferences
|
217
|
-
end
|
218
|
-
|
219
|
-
preferences[preference.attribute] = preference.value
|
220
|
-
all_preferences
|
221
|
-
end
|
148
|
+
# Reader
|
149
|
+
define_method("preferred_#{attribute}") do |*group|
|
150
|
+
preferred(attribute, group.first)
|
222
151
|
end
|
152
|
+
alias_method "prefers_#{attribute}", "preferred_#{attribute}"
|
223
153
|
|
224
|
-
#
|
225
|
-
#
|
226
|
-
|
227
|
-
# == Examples
|
228
|
-
#
|
229
|
-
# class User < ActiveRecord::Base
|
230
|
-
# preference :color, :string, :default => 'red'
|
231
|
-
# end
|
232
|
-
#
|
233
|
-
# user = User.create
|
234
|
-
# user.preferred(:color) # => "red"
|
235
|
-
# user.preferred?(:color) # => true
|
236
|
-
# user.preferred?(:color, 'cars') # => true
|
237
|
-
# user.preferred?(:color, Car.first) # => true
|
238
|
-
#
|
239
|
-
# user.set_preference(:color, nil)
|
240
|
-
# user.preferred(:color) # => nil
|
241
|
-
# user.preferred?(:color) # => false
|
242
|
-
def preferred?(attribute, group = nil)
|
243
|
-
attribute = attribute.to_s
|
244
|
-
|
245
|
-
value = preferred(attribute, group)
|
246
|
-
preference_definitions[attribute].query(value)
|
154
|
+
# Writer
|
155
|
+
define_method("preferred_#{attribute}=") do |*args|
|
156
|
+
set_preference(*([attribute] + [args].flatten))
|
247
157
|
end
|
248
|
-
alias_method
|
158
|
+
alias_method "prefers_#{attribute}=", "preferred_#{attribute}="
|
249
159
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
160
|
+
definition
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
module InstanceMethods
|
165
|
+
def self.included(base) #:nodoc:
|
166
|
+
base.class_eval do
|
167
|
+
alias_method :prefs, :preferences
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Finds all preferences, including defaults, for the current record. If
|
172
|
+
# any custom group preferences have been stored, then this will include
|
173
|
+
# all default preferences within that particular group.
|
174
|
+
#
|
175
|
+
# == Examples
|
176
|
+
#
|
177
|
+
# A user with no stored values:
|
178
|
+
# user = User.find(:first)
|
179
|
+
# user.preferences
|
180
|
+
# => {"language"=>"English", "color"=>nil}
|
181
|
+
#
|
182
|
+
# A user with stored values for a particular group:
|
183
|
+
# user.preferred_color = 'red', 'cars'
|
184
|
+
# user.preferences
|
185
|
+
# => {"language"=>"English", "color"=>nil, "cars"=>{"language=>"English", "color"=>"red"}}
|
186
|
+
#
|
187
|
+
# Getting preference values *just* for the owning record (i.e. excluding groups):
|
188
|
+
# user.preferences(nil)
|
189
|
+
# => {"language"=>"English", "color"=>nil}
|
190
|
+
#
|
191
|
+
# Getting preference values for a particular group:
|
192
|
+
# user.preferences('cars')
|
193
|
+
# => {"language"=>"English", "color"=>"red"}
|
194
|
+
def preferences(*args)
|
195
|
+
if args.empty?
|
196
|
+
group = nil
|
197
|
+
conditions = {}
|
198
|
+
else
|
199
|
+
group = args.first
|
268
200
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
201
|
+
# Split the actual group into its different parts (id/type) in case
|
202
|
+
# a record is passed in
|
203
|
+
group_id, group_type = Preference.split_group(group)
|
204
|
+
conditions = {:group_id => group_id, :group_type => group_type}
|
205
|
+
end
|
206
|
+
|
207
|
+
# Find all of the stored preferences
|
208
|
+
stored_preferences = self.stored_preferences.find(:all, :conditions => conditions)
|
209
|
+
|
210
|
+
# Hashify attribute -> value or group -> attribute -> value
|
211
|
+
stored_preferences.inject(self.class.default_preferences.dup) do |all_preferences, preference|
|
212
|
+
if !group && (preference_group = preference.group)
|
213
|
+
preferences = all_preferences[preference_group] ||= self.class.default_preferences.dup
|
273
214
|
else
|
274
|
-
|
275
|
-
group_id, group_type = Preference.split_group(group)
|
276
|
-
|
277
|
-
# Grab the first preference; if it doesn't exist, use the default value
|
278
|
-
preference = stored_preferences.find(:first, :conditions => {:attribute => attribute, :group_id => group_id, :group_type => group_type})
|
279
|
-
value = preference ? preference.value : preference_definitions[attribute].default_value
|
215
|
+
preferences = all_preferences
|
280
216
|
end
|
281
217
|
|
282
|
-
value
|
218
|
+
preferences[preference.attribute] = preference.value
|
219
|
+
all_preferences
|
283
220
|
end
|
284
|
-
|
221
|
+
end
|
222
|
+
|
223
|
+
# Queries whether or not a value is present for the given attribute. This
|
224
|
+
# is dependent on how the value is type-casted.
|
225
|
+
#
|
226
|
+
# == Examples
|
227
|
+
#
|
228
|
+
# class User < ActiveRecord::Base
|
229
|
+
# preference :color, :string, :default => 'red'
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# user = User.create
|
233
|
+
# user.preferred(:color) # => "red"
|
234
|
+
# user.preferred?(:color) # => true
|
235
|
+
# user.preferred?(:color, 'cars') # => true
|
236
|
+
# user.preferred?(:color, Car.first) # => true
|
237
|
+
#
|
238
|
+
# user.set_preference(:color, nil)
|
239
|
+
# user.preferred(:color) # => nil
|
240
|
+
# user.preferred?(:color) # => false
|
241
|
+
def preferred?(attribute, group = nil)
|
242
|
+
attribute = attribute.to_s
|
285
243
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
244
|
+
value = preferred(attribute, group)
|
245
|
+
preference_definitions[attribute].query(value)
|
246
|
+
end
|
247
|
+
alias_method :prefers?, :preferred?
|
248
|
+
|
249
|
+
# Gets the actual value stored for the given attribute, or the default
|
250
|
+
# value if nothing is present.
|
251
|
+
#
|
252
|
+
# == Examples
|
253
|
+
#
|
254
|
+
# class User < ActiveRecord::Base
|
255
|
+
# preference :color, :string, :default => 'red'
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# user = User.create
|
259
|
+
# user.preferred(:color) # => "red"
|
260
|
+
# user.preferred(:color, 'cars') # => "red"
|
261
|
+
# user.preferred(:color, Car.first) # => "red"
|
262
|
+
#
|
263
|
+
# user.set_preference(:color, 'blue')
|
264
|
+
# user.preferred(:color) # => "blue"
|
265
|
+
def preferred(attribute, group = nil)
|
266
|
+
attribute = attribute.to_s
|
267
|
+
|
268
|
+
if @preference_values && @preference_values[attribute] && @preference_values[attribute].include?(group)
|
269
|
+
# Value for this attribute/group has been written, but not saved yet:
|
270
|
+
# grab from the pending values
|
271
|
+
value = @preference_values[attribute][group]
|
272
|
+
else
|
273
|
+
# Split the group being filtered
|
274
|
+
group_id, group_type = Preference.split_group(group)
|
306
275
|
|
307
|
-
value
|
276
|
+
# Grab the first preference; if it doesn't exist, use the default value
|
277
|
+
preference = stored_preferences.find(:first, :conditions => {:attribute => attribute, :group_id => group_id, :group_type => group_type})
|
278
|
+
value = preference ? preference.value : preference_definitions[attribute].default_value
|
308
279
|
end
|
309
280
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
281
|
+
value
|
282
|
+
end
|
283
|
+
alias_method :prefers, :preferred
|
284
|
+
|
285
|
+
# Sets a new value for the given attribute. The actual Preference record
|
286
|
+
# is *not* created until this record is saved. In this way, preferences
|
287
|
+
# act *exactly* the same as attributes. They can be written to and
|
288
|
+
# validated against, but won't actually be written to the database until
|
289
|
+
# the record is saved.
|
290
|
+
#
|
291
|
+
# == Examples
|
292
|
+
#
|
293
|
+
# user = User.find(:first)
|
294
|
+
# user.set_preference(:color, 'red') # => "red"
|
295
|
+
# user.save!
|
296
|
+
#
|
297
|
+
# user.set_preference(:color, 'blue', Car.first) # => "blue"
|
298
|
+
# user.save!
|
299
|
+
def set_preference(attribute, value, group = nil)
|
300
|
+
attribute = attribute.to_s
|
301
|
+
|
302
|
+
@preference_values ||= {}
|
303
|
+
@preference_values[attribute] ||= {}
|
304
|
+
@preference_values[attribute][group] = value
|
305
|
+
|
306
|
+
value
|
307
|
+
end
|
308
|
+
|
309
|
+
private
|
310
|
+
# Updates any preferences that have been changed/added since the record
|
311
|
+
# was last saved
|
312
|
+
def update_preferences
|
313
|
+
if @preference_values
|
314
|
+
@preference_values.each do |attribute, grouped_records|
|
315
|
+
grouped_records.each do |group, value|
|
316
|
+
group_id, group_type = Preference.split_group(group)
|
317
|
+
attributes = {:attribute => attribute, :group_id => group_id, :group_type => group_type}
|
318
|
+
|
319
|
+
# Find an existing preference or build a new one
|
320
|
+
preference = stored_preferences.find(:first, :conditions => attributes) || stored_preferences.build(attributes)
|
321
|
+
preference.value = value
|
322
|
+
preference.save!
|
325
323
|
end
|
326
|
-
|
327
|
-
@preference_values = nil
|
328
324
|
end
|
325
|
+
|
326
|
+
@preference_values = nil
|
329
327
|
end
|
330
|
-
|
328
|
+
end
|
331
329
|
end
|
332
330
|
end
|
333
331
|
|
334
332
|
ActiveRecord::Base.class_eval do
|
335
|
-
extend
|
333
|
+
extend Preferences::MacroMethods
|
336
334
|
end
|
@@ -2,7 +2,7 @@ require "#{File.dirname(__FILE__)}/../test_helper"
|
|
2
2
|
|
3
3
|
class PreferenceDefinitionByDefaultTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
@definition =
|
5
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications)
|
6
6
|
end
|
7
7
|
|
8
8
|
def test_should_have_an_attribute
|
@@ -24,13 +24,13 @@ end
|
|
24
24
|
|
25
25
|
class PreferenceDefinitionTest < Test::Unit::TestCase
|
26
26
|
def test_should_raise_exception_if_invalid_option_specified
|
27
|
-
assert_raise(ArgumentError) {
|
27
|
+
assert_raise(ArgumentError) {Preferences::PreferenceDefinition.new(:notifications, :invalid => true)}
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
class PreferenceDefinitionWithDefaultValueTest < Test::Unit::TestCase
|
32
32
|
def setup
|
33
|
-
@definition =
|
33
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications, :boolean, :default => 1)
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_should_type_cast_default_values
|
@@ -40,7 +40,7 @@ end
|
|
40
40
|
|
41
41
|
class PreferenceDefinitionWithAnyTypeTest < Test::Unit::TestCase
|
42
42
|
def setup
|
43
|
-
@definition =
|
43
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications, :any)
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_should_not_type_cast
|
@@ -76,7 +76,7 @@ end
|
|
76
76
|
|
77
77
|
class PreferenceDefinitionWithBooleanTypeTest < Test::Unit::TestCase
|
78
78
|
def setup
|
79
|
-
@definition =
|
79
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications)
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_should_not_type_cast_if_value_is_nil
|
@@ -122,7 +122,7 @@ end
|
|
122
122
|
|
123
123
|
class PreferenceDefinitionWithNumericTypeTest < Test::Unit::TestCase
|
124
124
|
def setup
|
125
|
-
@definition =
|
125
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications, :integer)
|
126
126
|
end
|
127
127
|
|
128
128
|
def test_should_type_cast_true_to_integer
|
@@ -152,7 +152,7 @@ end
|
|
152
152
|
|
153
153
|
class PreferenceDefinitionWithStringTypeTest < Test::Unit::TestCase
|
154
154
|
def setup
|
155
|
-
@definition =
|
155
|
+
@definition = Preferences::PreferenceDefinition.new(:notifications, :string)
|
156
156
|
end
|
157
157
|
|
158
158
|
def test_should_type_cast_integers_to_strings
|
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.
|
4
|
+
version: 0.2.0
|
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: 2008-12-
|
12
|
+
date: 2008-12-14 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|