ee_preferences 0.4.3

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDc1NTg2MzkyYmYxMGRmMDgxNzY0M2EyYTRmMTczYThlZTgxN2IxNg==
5
+ data.tar.gz: !binary |-
6
+ Njk2N2U0OTBmYWY2NjVkM2Y5N2NhNzIxNjZmMWRjOWUyN2I4ZjZjMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ Mjc5MmQ5MmYwYzhhNWVmOGMyMmY5NTEwNDI1OThhNDMxNWFkYzRmNjdlNGI4
10
+ YjkxNjJhZDU0M2NiMTIyMzU5Mzg5ZjFlNzQwMGUyMWJiY2M2ZTBkNDIxZTZm
11
+ Y2NiODY3N2M1NmY2ZWM5NjA3NDAwNmRjYjk1MGJlODJlOGIyNDA=
12
+ data.tar.gz: !binary |-
13
+ MWUxY2M4MTM4MTU4ZTc0NmQ0ZGUxMTZhMWIyMWM4NTkxYmJhN2M0OTczNGIz
14
+ ZjcyOGQxMGE5YTdlZGU3MDUwMDYzZmI5ZGQ4Y2MwNGE5ODQ3NjZlMzAxODE1
15
+ ZjhkZWEyZjY1MDQzYWFjOGI2YmJiMjVjMzc1YjZlNTMxMjAwMGI=
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ coverage
3
+ pkg
4
+ rdoc
5
+ test/app_root/log
6
+ test/app_root/script
7
+ Gemfile.lock
8
+ .idea/*
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.8.7
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ == master
2
+ == 0.4.3 / 2014-09-08
3
+
4
+ * Fix #named_scope to #scope
5
+
6
+ == 0.4.2 / 2010-04-17
7
+
8
+ * Fix #preferences lookup not typecasting values
9
+
10
+ == 0.4.1 / 2010-03-07
11
+
12
+ * Add support for per-group default preferences
13
+ * Fix unsaved boolean preferences getting overridden by defaults if value is false
14
+
15
+ == 0.4.0 / 2010-03-07
16
+
17
+ * Add {preference}_changed?, {preference}_was, {preference}_changed, {preference}_will_change!, and reset_{preference}!
18
+ * Add #preferences_changed?, #preferences_changed, and #preference_changes
19
+ * Fix preferences that are reverted externally still getting stored
20
+ * Fix preference definition types not being used to typecast values
21
+ * No longer allow both group and non-group preferences to be looked up at once (except for named scopes)
22
+ * Add support for using Symbols to reference groups
23
+ * Fix #reload not causing unsaved preferences to get reset
24
+ * Raise exception if unknown preference is accessed
25
+ * Rename #set_preference to #write_preference
26
+ * Add caching of preference lookups
27
+ * Fix preferences being stored even if they didn't change
28
+ * Release gems via rake-gemcutter instead of rubyforge
29
+ * Add a generator for db migration to make installation a bit easier [Tim Lowrimore]
30
+ * Add named scopes: #with_preferences and #without_preferences
31
+
32
+ == 0.3.1 / 2009-04-25
33
+
34
+ * Rename Preference#attribute to #name to avoid conflicts with reserved methods in ActiveRecord
35
+
36
+ == 0.3.0 / 2009-04-13
37
+
38
+ * Add dependency on Rails 2.3
39
+ * Remove dependency on plugins_plus
40
+
41
+ == 0.2.0 / 2008-12-14
42
+
43
+ * Remove the PluginAWeek namespace
44
+
45
+ == 0.1.5 / 2008-11-16
46
+
47
+ * Add all prefers/preferred accessors for preferences to be analogous to ActiveRecord column accessors
48
+ * Fix preferences defined in STI subclasses not working [Quinn Shanahan]
49
+
50
+ == 0.1.4 / 2008-10-26
51
+
52
+ * Change how the base module is included to prevent namespacing conflicts
53
+
54
+ == 0.1.3 / 2008-06-29
55
+
56
+ * Add +prefs+ as an alias for +preferences+
57
+ * Fix +preferences+ not properly selecting preferences when a group is specified
58
+ * Improve test coverage
59
+
60
+ == 0.1.2 / 2008-06-22
61
+
62
+ * Remove log files from gems
63
+
64
+ == 0.1.1 / 2008-06-20
65
+
66
+ * Rename preference_values hash to preferences
67
+ * Rename preferences association to stored_preferences
68
+
69
+ == 0.1.0 / 2008-06-19
70
+
71
+ * Avoid string evaluation for dynamic methods
72
+ * Return hashes for the preference_values, e.g.
73
+
74
+ user.preference_values # => {'color' => 'red', 'number' => 11, 'website' => {'background' => 'white', 'foreground' => 'black'}}
75
+ user.preference_values('website') # => {'background' => 'white', 'foreground' => 'black'}
76
+
77
+ * Add more generic grouping of preferences than with just other records, e.g.
78
+
79
+ user.preferred_color('cars')
80
+
81
+ * Remove support for an options hash when specifying :for associations for preference
82
+
83
+ == 0.0.1 / 2008-05-10
84
+
85
+ * Initial public release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://www.rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2009 Aaron Pfeifer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,224 @@
1
+ == preferences http://travis-ci.org/pluginaweek/preferences.png
2
+
3
+ +preferences+ adds support for easily creating custom preferences for models.
4
+
5
+ == Resources
6
+
7
+ API
8
+
9
+ * http://rdoc.info/github/pluginaweek/preferences/master/frames
10
+
11
+ Bugs
12
+
13
+ * http://github.com/pluginaweek/preferences/issues
14
+
15
+ Development
16
+
17
+ * http://github.com/pluginaweek/preferences
18
+
19
+ Testing
20
+
21
+ * http://travis-ci.org/pluginaweek/preferences
22
+
23
+ Source
24
+
25
+ * git://github.com/pluginaweek/preferences.git
26
+
27
+ Mailing List
28
+
29
+ * http://groups.google.com/group/pluginaweek-talk
30
+
31
+ == Description
32
+
33
+ Preferences for models within an application, such as for users, is a pretty
34
+ common idiom. Although the rule of thumb is to keep the number of preferences
35
+ available to a minimum, sometimes it's necessary if you want users to be able to
36
+ disable things like e-mail notifications.
37
+
38
+ Generally, basic preferences can be accomplished through simple designs, such as
39
+ additional columns or a bit vector described and implemented by preference_fu[http://agilewebdevelopment.com/plugins/preferencefu].
40
+ However, as you find the need for non-binary preferences and the number of
41
+ preferences becomes unmanageable as individual columns in the database, the next
42
+ step is often to create a separate "preferences" table. This is where the
43
+ +preferences+ plugin comes in.
44
+
45
+ +preferences+ encapsulates this design by exposing preferences using simple
46
+ attribute accessors on the model, hiding the fact that preferences are stored in
47
+ a separate table and making it dead-simple to define and manage preferences.
48
+
49
+ == Usage
50
+
51
+ === Installation
52
+
53
+ +preferences+ requires an additional database table to work. You can generate
54
+ a migration for this table like so:
55
+
56
+ script/generate preferences
57
+
58
+ Then simply migrate your database:
59
+
60
+ rake db:migrate
61
+
62
+ === Defining preferences
63
+
64
+ To define the preferences for a model, you can do so right within the model:
65
+
66
+ class User < ActiveRecord::Base
67
+ preference :hot_salsa
68
+ preference :dark_chocolate, :default => true
69
+ preference :color, :string
70
+ preference :favorite_number
71
+ preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Spanish'}
72
+ end
73
+
74
+ In the above model, 5 preferences have been defined:
75
+ * hot_salsa
76
+ * dark_chocolate
77
+ * color
78
+ * favorite_number
79
+ * language
80
+
81
+ For each preference, a data type and default value can be specified. If no
82
+ data type is given, it's assumed to be a boolean value. If no default value is
83
+ given, the default is assumed to be nil.
84
+
85
+ === Accessing preferences
86
+
87
+ Once preferences have been defined for a model, they can be accessed either
88
+ using the accessor methods that are generated for each preference or the generic
89
+ methods that are not specific to a particular preference.
90
+
91
+ ==== Accessors
92
+
93
+ There are several shortcut methods that are generated for each preference
94
+ defined on a model. These reflect the same set of methods (attribute accessors)
95
+ that are generated for a model's columns. Examples of these are shown below:
96
+
97
+ Query methods:
98
+ user.prefers_hot_salsa? # => false
99
+ user.preferred_language? # => true
100
+
101
+ Reader methods:
102
+ user.prefers_hot_salsa # => false
103
+ user.preferred_language # => "English"
104
+
105
+ Writer methods:
106
+ user.prefers_hot_salsa = false # => false
107
+ user.preferred_language = 'English' # => "English"
108
+
109
+ ==== Generic methods
110
+
111
+ Each preference accessor is essentially a wrapper for the various generic methods
112
+ shown below:
113
+
114
+ Query method:
115
+ user.prefers?(:hot_salsa) # => false
116
+ user.preferred?(:language) # => true
117
+
118
+ Reader method:
119
+ user.prefers(:hot_salsa) # => false
120
+ user.preferred(:language) # => "English"
121
+
122
+ Write method:
123
+ user.write_preference(:hot_salsa, false) # => false
124
+ user.write_preference(:language, "English") # => "English"
125
+
126
+ === Accessing all preferences
127
+
128
+ To get the collection of all custom, stored preferences for a particular record,
129
+ you can access the +stored_preferences+ has_many association which is automatically
130
+ generated:
131
+
132
+ user.stored_preferences
133
+
134
+ In addition to this, you can get a hash of all stored preferences *and* default
135
+ preferences, by accessing the +preferences+ helper:
136
+
137
+ user.preferences # => {"language"=>"English", "color"=>nil}
138
+
139
+ This hash will contain the value for every preference that has been defined for
140
+ the model, whether that's the default value or one that has been previously
141
+ stored.
142
+
143
+ A short-hand alternative for preferences is also available:
144
+
145
+ user.prefs # => {"language"=>"English", "color"=>nil}
146
+
147
+ === Grouping preferences
148
+
149
+ In addition to defining generic preferences for the owning record, you can also
150
+ group preferences by ActiveRecord objects or arbitrary names. This is best shown
151
+ through an example:
152
+
153
+ user = User.find(:first)
154
+ car = Car.find(:first)
155
+
156
+ user.preferred_color = 'red', car
157
+ # user.write_preference(:color, 'red', car) # The generic way
158
+
159
+ This will create a color preference of "red" for the given car. In this way,
160
+ you can have "color" preferences for different records.
161
+
162
+ To access the preference for a particular record, you can use the same accessor
163
+ methods as before:
164
+
165
+ user.preferred_color(car)
166
+ # user.preferred(:color, car) # The generic way
167
+
168
+ In addition to grouping preferences for a particular record, you can also group
169
+ preferences by name. For example,
170
+
171
+ user = User.find(:first)
172
+
173
+ user.preferred_color = 'red', :automobiles
174
+ user.preferred_color = 'tan', :clothing
175
+
176
+ user.preferred_color(:automobiles) # => "red"
177
+ user.preferred_color(:clothing) # => "tan"
178
+
179
+ user.preferences(:automobiles) # => {"color"=>"red"}
180
+
181
+ === Saving preferences
182
+
183
+ Note that preferences are not saved until the owning record is saved.
184
+ Preferences are treated in a similar fashion to attributes. For example,
185
+
186
+ user = user.find(:first)
187
+ user.attributes = {:prefers_hot_salsa => false, :preferred_color => 'red'}
188
+ user.save!
189
+
190
+ Preferences are stored in a separate table called "preferences".
191
+
192
+ === Tracking changes
193
+
194
+ Similar to ActiveRecord attributes, unsaved changes to preferences can be
195
+ tracked. For example,
196
+
197
+ user.preferred_language # => "English"
198
+ user.preferred_language_changed? # => false
199
+ user.preferred_language = 'Spanish'
200
+ user.preferred_language_changed? # => true
201
+ user.preferred_language_was # => "English"
202
+ user.preferred_language_change # => ["English", "Spanish"]
203
+ user.reset_preferred_language!
204
+ user.preferred_language # => "English"
205
+
206
+ Assigning the same value leaves the preference unchanged:
207
+
208
+ user.preferred_language # => "English"
209
+ user.preferred_language = 'English'
210
+ user.preferred_language_changed? # => false
211
+ user.preferred_language_change # => nil
212
+
213
+ == Testing
214
+
215
+ Before you can run any tests, the following gem must be installed:
216
+ * plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
217
+
218
+ To run against a specific version of Rails:
219
+
220
+ rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
221
+
222
+ == Dependencies
223
+
224
+ * Rails 2.3 or later
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ desc 'Default: run all tests.'
7
+ task :default => :test
8
+
9
+ desc "Test preferences."
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.test_files = Dir['test/**/*_test.rb']
13
+ t.verbose = true
14
+ end
15
+
16
+ begin
17
+ require 'rcov/rcovtask'
18
+ namespace :test do
19
+ desc "Test preferences with Rcov."
20
+ Rcov::RcovTask.new(:rcov) do |t|
21
+ t.libs << 'lib'
22
+ t.test_files = Dir['test/**/*_test.rb']
23
+ t.rcov_opts << '--exclude="^(?!lib/|app/)"'
24
+ t.verbose = true
25
+ end
26
+ end
27
+ rescue LoadError
28
+ end
29
+
30
+ desc "Generate documentation for preferences."
31
+ Rake::RDocTask.new(:rdoc) do |rdoc|
32
+ rdoc.rdoc_dir = 'rdoc'
33
+ rdoc.title = 'preferences'
34
+ rdoc.options << '--line-numbers' << '--inline-source' << '--main=README.rdoc'
35
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb', 'app/**/*.rb')
36
+ end
@@ -0,0 +1,65 @@
1
+ # Represents a preferred value for a particular preference on a model.
2
+ #
3
+ # == Grouped preferences
4
+ #
5
+ # In addition to simple named preferences, preferences can also be grouped by
6
+ # a particular value, be it a string or ActiveRecord object. For example, a
7
+ # User may have a preferred color for a particular Car. In this case, the
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
+ class Preference < ActiveRecord::Base
11
+ belongs_to :owner, :polymorphic => true
12
+ belongs_to :group, :polymorphic => true
13
+
14
+ validates_presence_of :name, :owner_id, :owner_type
15
+ validates_presence_of :group_type, :if => :group_id?
16
+
17
+ class << self
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
+ # ActiveRecord objects, the id is the unique identifier stored in the
21
+ # database for the record.
22
+ #
23
+ # For example,
24
+ #
25
+ # Preference.split_group('google') # => [nil, "google"]
26
+ # Preference.split_group(1) # => [nil, 1]
27
+ # Preference.split_group(User.find(1)) # => [1, "User"]
28
+ def split_group(group = nil)
29
+ if group.is_a?(ActiveRecord::Base)
30
+ group_id, group_type = group.id, group.class.base_class.name.to_s
31
+ else
32
+ group_id, group_type = nil, group.is_a?(Symbol) ? group.to_s : group
33
+ end
34
+
35
+ [group_id, group_type]
36
+ end
37
+ end
38
+
39
+ # The definition of the preference as defined in the owner's model
40
+ def definition
41
+ # Optimize number of queries to the database by only looking up the actual
42
+ # owner record for STI cases when the definition can't be found in the
43
+ # stored owner type class
44
+ owner_type && (find_definition(owner_type.constantize) || find_definition(owner.class))
45
+ end
46
+
47
+ # Typecasts the value depending on the preference definition's declared type
48
+ def value
49
+ value = read_attribute(:value)
50
+ value = definition.type_cast(value) if definition
51
+ value
52
+ end
53
+
54
+ # Only searches for the group record if the group id is specified
55
+ def group_with_optional_lookup
56
+ group_id ? group_without_optional_lookup : group_type
57
+ end
58
+ alias_method_chain :group, :optional_lookup
59
+
60
+ private
61
+ # Finds the definition for this preference in the given owner class.
62
+ def find_definition(owner_class)
63
+ owner_class.respond_to?(:preference_definitions) && owner_class.preference_definitions[name]
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ Usage:
2
+
3
+ script/generate preferences
4
+
5
+ This will create a migration that will add the proper table to store preferences.
@@ -0,0 +1,7 @@
1
+ class PreferencesGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template '001_create_preferences.rb', 'db/migrate', :migration_file_name => 'create_preferences'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ class CreatePreferences < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :preferences do |t|
4
+ t.string :name, :null => false
5
+ t.references :owner, :polymorphic => true, :null => false
6
+ t.references :group, :polymorphic => true
7
+ t.string :value
8
+ t.timestamps
9
+ end
10
+ add_index :preferences, [:owner_id, :owner_type, :name, :group_id, :group_type], :unique => true, :name => 'index_preferences_on_owner_and_name_and_preference'
11
+ end
12
+
13
+ def self.down
14
+ drop_table :preferences
15
+ end
16
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'preferences'
@@ -0,0 +1,56 @@
1
+ module Preferences
2
+ # Represents the definition of a preference for a particular model
3
+ class PreferenceDefinition
4
+ # The data type for the content stored in this preference type
5
+ attr_reader :type
6
+
7
+ def initialize(name, *args) #:nodoc:
8
+ options = args.extract_options!
9
+ options.assert_valid_keys(:default, :group_defaults)
10
+
11
+ @type = args.first ? args.first.to_sym : :boolean
12
+
13
+ # Create a column that will be responsible for typecasting
14
+ @column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], @type == :any ? nil : @type.to_s)
15
+
16
+ @group_defaults = (options[:group_defaults] || {}).inject({}) do |defaults, (group, default)|
17
+ defaults[group.is_a?(Symbol) ? group.to_s : group] = type_cast(default)
18
+ defaults
19
+ end
20
+ end
21
+
22
+ # The name of the preference
23
+ def name
24
+ @column.name
25
+ end
26
+
27
+ # The default value to use for the preference in case none have been
28
+ # previously defined
29
+ def default_value(group = nil)
30
+ @group_defaults.include?(group) ? @group_defaults[group] : @column.default
31
+ end
32
+
33
+ # Determines whether column backing this preference stores numberic values
34
+ def number?
35
+ @column.number?
36
+ end
37
+
38
+ # Typecasts the value based on the type of preference that was defined.
39
+ # This uses ActiveRecord's typecast functionality so the same rules for
40
+ # typecasting a model's columns apply here.
41
+ def type_cast(value)
42
+ @type == :any ? value : @column.type_cast(value)
43
+ end
44
+
45
+ # Typecasts the value to true/false depending on the type of preference
46
+ def query(value)
47
+ if !(value = type_cast(value))
48
+ false
49
+ elsif number?
50
+ !value.zero?
51
+ else
52
+ !value.blank?
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Preferences
2
+ VERSION = '0.4.3'
3
+ end