acts_as_preferenced 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ..gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,75 @@
1
+ ActsAsPreferenced
2
+ ===========
3
+
4
+ ActsAsPreferenced helps with handling of some settings you might want to store
5
+ per-object (usually per-user) in Rails applications. It provides unified API to
6
+ access those, ways to handle default values and some useful view helpers.
7
+ Preferences may be divided into sections for easier categorization if many are
8
+ present.
9
+
10
+ Preferences can be stored in one of pluggable stores. Currently two stores are
11
+ implemented: Field (stores in serialized db column) and Association (stores in
12
+ associated table). One of the aims of this gem was to provide smooth transition
13
+ between different stores - API stays the same for all of them, so you may start
14
+ with preferences being stored in a serialized field and then transition to
15
+ associated table.
16
+
17
+ Example
18
+ =======
19
+
20
+ # Association store - use whatever association you like, there are just 2
21
+ # requirements:
22
+ # * associated table needs to have field for every preference (type matching)
23
+ # * the name of the association cannot be "preferences", as it is used
24
+ # internally by ActsAsPreferenced
25
+
26
+ class User
27
+ attr_accessor :user_preferences
28
+
29
+ acts_as_preferenced( :association => :user_preferences ) do |config|
30
+
31
+ # Just an integer preference with allowed range
32
+ config.preference :items_per_page, :section => :general, :choices => (1..100), :default => 20
33
+ # Define the whole section of preferences. :prefix => true means
34
+ # preference names will start with section name, so :flowers will become
35
+ # "likes_flowers?" method ("?" added because it's boolean)
36
+ config.section :likes, :prefix => true do |section|
37
+ section.preference :flowers, :default => true
38
+ # No default - if not set will be nil
39
+ section.preference :animals
40
+ end
41
+ # Enumerated preference with no section (it belongs to nil section)
42
+ config.preference :likes_people, :choices => [:no, :little, :yes]
43
+ end
44
+
45
+ end
46
+
47
+ OR
48
+
49
+ # Field store
50
+
51
+ class User
52
+ acts_as_preferenced( :field => :prefs, ...
53
+ end
54
+
55
+
56
+ # Usage
57
+
58
+ user = User.new
59
+ user.likes_flowers? # True - default; as preference is boolean question mark is appended to getter
60
+ user.likes_flowers = false
61
+ user.likes_flowers? # False
62
+ user.likes_animals? # Nil - no default present
63
+ user.items_per_page = 120 # ArgumentError - value out of range
64
+ user.likes_people = :yes
65
+ user.likes_people # :yes - name might be misleading, but it's not boolean, so no question mark here
66
+
67
+ TODO
68
+ ====
69
+
70
+ Helpers
71
+ API documentation
72
+ Migration generator for Association store.
73
+ I18n tests.
74
+
75
+ Copyright (c) 2009-2013 Marek Janukowicz, released under the MIT license
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,72 @@
1
+ require 'acts_as_preferenced/version'
2
+ require 'acts_as_preferenced/store/base'
3
+ require 'acts_as_preferenced/store/association'
4
+ require 'acts_as_preferenced/store/field'
5
+ require 'acts_as_preferenced/preference'
6
+ require 'acts_as_preferenced/section'
7
+
8
+ module ActsAsPreferenced
9
+
10
+ def self.included( klass )
11
+ klass.extend( ActMethods )
12
+ end
13
+
14
+ module ActMethods
15
+
16
+ def acts_as_preferenced( options = {} )
17
+ options.assert_valid_keys( :field, :association, :translation_scope )
18
+ class_attribute :preference_config
19
+ include InstanceMethods
20
+ extend ClassMethods
21
+ if options[:field]
22
+ field = options[:field]
23
+ self.module_eval { serialize field, Hash } # TODO: move this line into config initialization
24
+ config = ActsAsPreferenced::Store::Field.new( self, field, options[:translation_scope] )
25
+ self.preference_config = config
26
+ yield config
27
+ elsif options[:association]
28
+ config = ActsAsPreferenced::Store::Association.new( self, options[:association], options[:translation_scope] )
29
+ self.preference_config = config
30
+ yield config
31
+ else
32
+ raise ArgumentError, "Invalid options for acts_as_preferenced: #{options.inspect}"
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ # TODO: Those methods should only be available when preferences are actually defined
41
+ def preference_sections
42
+ preference_config.sections.keys
43
+ end
44
+
45
+ def preferences_for_section( section )
46
+ preference_config.sections[section]
47
+ end
48
+
49
+ def all_preferences
50
+ preference_config.all_preferences
51
+ end
52
+
53
+ end
54
+
55
+ module InstanceMethods
56
+
57
+ def preference_value( name )
58
+ # TODO: implement
59
+ end
60
+
61
+ #def preferences
62
+ # Preferences.configs[self.class].all
63
+ #end
64
+
65
+ #def preferences= (prefs)
66
+ # Preferences.configs[self.class].all = prefs
67
+ #end
68
+ end
69
+
70
+ end
71
+
72
+ ActiveRecord::Base.send( :include, ActsAsPreferenced )
@@ -0,0 +1,48 @@
1
+ module ActsAsPreferenced
2
+ class Preference
3
+
4
+ attr_reader :name, :default, :section
5
+
6
+ def initialize( store, name, options = {} )
7
+ options.assert_valid_keys( :section, :label, :choices, :default )
8
+ @store, @name = store, name
9
+ @section = options[:section]
10
+ @label = options[:label]
11
+ @choices = options[:choices]
12
+ @default = options[:default]
13
+ store.sections[@section] << self
14
+ store.all_preferences << self
15
+ end
16
+
17
+ def label
18
+ if @store.translation_scope && @label.nil?
19
+ I18n.t( @name, :scope => [@store.translation_scope, @section] )
20
+ else
21
+ @label
22
+ end
23
+ end
24
+
25
+ # Options translations are stored under hardcoded :choices key in Preferences
26
+ # translation_scope. TODO: make it not hardcoded and make it work for other
27
+ # options than Array (eg. Range?)
28
+ # TODO: it should be cached
29
+ def choices
30
+ if @choices.is_a?( Array )
31
+ # TODO: I don't quite understand checking for an array here
32
+ @choices.collect { |choice| choice.is_a?( Array ) ? choice : [I18n.t( choice, :scope => [@store.translation_scope, :choices] ), opt] }
33
+ else
34
+ @choices
35
+ end
36
+ end
37
+
38
+ def value_valid?( value )
39
+ value = value.to_sym if value.is_a?( String )
40
+ if @choices
41
+ return @choices.include?( value )
42
+ else
43
+ return [true, false].include?( value )
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ module ActsAsPreferenced
2
+
3
+ # This class only helps with defining of preference sections, not with storage
4
+ # (as I see no reason to make storage more complicated while bringing no real
5
+ # benefit)
6
+ class Section
7
+
8
+ # Options:
9
+ # * prefix - if true, section name will be prepended to all preferences
10
+ # defined within. False by default
11
+ def initialize( store, name, options = {} )
12
+ options.assert_valid_keys( :prefix )
13
+ @store, @name = store, name
14
+ @prefix = options[:prefix]
15
+ end
16
+
17
+ def preference( name, options = {} )
18
+ pref_name = (@prefix ? "#{@name}_#{name}".to_sym : name)
19
+ @store.preference( pref_name, options.merge( :section => @name ))
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,66 @@
1
+ module ActsAsPreferenced
2
+ module Store
3
+
4
+ class Association < Base
5
+
6
+ attr_reader :association
7
+
8
+ def initialize(klass, assoc, translation_scope = nil)
9
+ super( klass, translation_scope )
10
+ @association = assoc
11
+ @klass.send( :define_method, "preferences" ) do
12
+ prefs = send( preference_config.association ) || send( "build_#{preference_config.association}" )
13
+ return prefs
14
+ end
15
+ @klass.send( :define_method, "preferences=" ) do |new_prefs|
16
+ pref_object = send( preference_config.association ) || send( "build_#{preference_config.association}" )
17
+ self.class.all_preferences.each do |pref|
18
+ old_value = pref_object.send( pref.name )
19
+ new_value = new_prefs[pref.name]
20
+ if new_value
21
+ stringified_value = new_value.is_a?( Symbol ) ? new_value.to_s : new_value
22
+ new_prefs[pref.name] = stringified_value
23
+ else
24
+ # Hack to allow boolean preferences to be set to false. This looks
25
+ # wrong from model point of view (if you mass assign preferences,
26
+ # absent boolean ones will be set to false even though default is
27
+ # true), but it works well for forms.
28
+ # TODO: find a way to make it work properly both for defaults and
29
+ # forms (if at all possible)
30
+ if pref.default == true || old_value == true
31
+ new_prefs[pref.name] = false
32
+ end
33
+ end
34
+ end
35
+ pref_object.attributes = new_prefs
36
+ end
37
+
38
+ @klass.send( :define_method, "save_preferences" ) do
39
+ pref_object = send( preference_config.association )
40
+ pref_object.save! if pref_object
41
+ end
42
+ @klass.before_save :save_preferences
43
+ end
44
+
45
+ def preference( name, options = {} )
46
+ options.assert_valid_keys( :section, :label, :choices, :default )
47
+ pref = Preference.new( self, name, options )
48
+ method_name = options[:choices] ? name.to_s : "#{name}?"
49
+ @klass.send( :define_method, method_name ) do
50
+ value = preferences[name]
51
+ value = pref.default if value.nil?
52
+ value &&= value.to_sym if value.is_a?( String )
53
+ value
54
+ end
55
+ @klass.send( :define_method, "#{name}=" ) do |value|
56
+ if pref.value_valid?( value )
57
+ preferences[name] = (value.is_a?( Symbol ) ? value.to_s : value)
58
+ else
59
+ raise ArgumentError, "Value #{value} invalid for preference #{pref.name}"
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,23 @@
1
+ module ActsAsPreferenced
2
+ module Store
3
+
4
+ # Base class for all stores for preferences
5
+ class Base
6
+
7
+ attr_reader :sections, :all_preferences, :translation_scope
8
+
9
+ def initialize( klass, translation_scope = nil )
10
+ @klass = klass
11
+ @translation_scope = translation_scope
12
+ @sections = Hash.new { |h,k| h[k] = [] }
13
+ @all_preferences = []
14
+ end
15
+
16
+ def section( name, options = {} )
17
+ section = Section.new( self, name, options )
18
+ yield section
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,61 @@
1
+ module ActsAsPreferenced
2
+ module Store
3
+
4
+ # This store holds preferences in a serialized field
5
+ class Field < Base
6
+
7
+ def initialize( klass, field, translation_scope = nil )
8
+ super( klass, translation_scope )
9
+ @field = field
10
+ @klass.send( :define_method, "preferences" ) do
11
+ prefs = read_attribute(field)
12
+ unless prefs
13
+ prefs = HashWithIndifferentAccess.new
14
+ write_attribute(field, prefs)
15
+ end
16
+ return prefs
17
+ end
18
+
19
+ @klass.send( :define_method, "preferences=" ) do |new_prefs|
20
+ self.class.all_preferences.each do |pref|
21
+ # Hack to allow boolean preferences to be set to false. This looks
22
+ # wrong from model point of view (if you mass assign preferences,
23
+ # absent boolean ones will be set to false even though default is
24
+ # true), but it works well for forms.
25
+ # TODO: find a way to make it work properly both for defaults and
26
+ # forms (if at all possible)
27
+ new_prefs[pref.name] ||= false if pref.default == true
28
+ end
29
+ write_attribute(field, new_prefs)
30
+ end
31
+ end
32
+
33
+ def preference( name, options = {} )
34
+ options.assert_valid_keys( :section, :label, :choices, :default )
35
+ pref = Preference.new( self, name, options )
36
+ if options[:choices] # Choice
37
+ @klass.send( :define_method, "#{name}" ) do
38
+ # This symbolizes strings and leave other values (eg. numbers)
39
+ # intact
40
+ value = preferences[name].is_a?( String ) ? preferences[name].to_sym : preferences[name]
41
+ value || pref.default
42
+ end
43
+ else # Boolean
44
+ @klass.send( :define_method, "#{name}?" ) do
45
+ # We check for nil to allow "false" here
46
+ preferences[name].nil? ? pref.default : preferences[name]
47
+ end
48
+ end
49
+ @klass.send( :define_method, "#{name}=" ) do |value|
50
+ if pref.value_valid?( value )
51
+ preferences[name] = value
52
+ else
53
+ raise ArgumentError, "Value #{value} invalid for preference #{pref.name}"
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module ActsAsPreferenced
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,253 @@
1
+ require 'test_helper'
2
+
3
+ class ActsAsPreferencedFieldTest < ActiveSupport::TestCase
4
+
5
+ class User < FakeModel
6
+
7
+ attr_accessor :hold_preferences_here
8
+
9
+ acts_as_preferenced( :field => :hold_preferences_here ) do |config|
10
+ config.preference :items_per_page, :section => :general, :choices => (1..100), :default => 20
11
+ config.section :likes, :prefix => true do |section|
12
+ section.preference :flowers, :default => true
13
+ section.preference :animals
14
+ end
15
+ config.preference :likes_people, :choices => [:no, :little, :yes]
16
+ end
17
+ end
18
+
19
+ def setup
20
+ @user = User.new
21
+ end
22
+
23
+ test "all preferences" do
24
+ all = User.all_preferences
25
+ assert_equal [:items_per_page, :likes_flowers, :likes_animals, :likes_people], all.collect(&:name)
26
+ end
27
+
28
+ test "preference sections" do
29
+ assert_equal [:general, nil, :likes], User.preference_sections
30
+ prefs = User.preferences_for_section( :sdjkfajsdf )
31
+ assert prefs.empty?
32
+ prefs = User.preferences_for_section( :likes )
33
+ assert_equal [:likes_flowers, :likes_animals], prefs.collect(&:name)
34
+ prefs = User.preferences_for_section( nil )
35
+ assert_equal [:likes_people], prefs.collect(&:name)
36
+ end
37
+
38
+ test "defaults" do
39
+ assert_equal true, @user.likes_flowers?
40
+ assert_equal 20, @user.items_per_page
41
+ assert_nil @user.likes_animals?
42
+ assert_nil @user.likes_people
43
+ end
44
+
45
+ test "set boolean" do
46
+ @user.likes_flowers = false
47
+ assert_equal false, @user.likes_flowers?
48
+ end
49
+
50
+ test "set integer" do
51
+ @user.items_per_page = 11
52
+ assert_equal 11, @user.items_per_page
53
+ end
54
+
55
+ test "set enumerable" do
56
+ @user.likes_people = :little
57
+ assert_equal :little, @user.likes_people
58
+ end
59
+
60
+ test "set integer as boolean" do
61
+ assert_raises( ArgumentError ) do
62
+ @user.items_per_page = true
63
+ end
64
+ end
65
+
66
+ test "set integer out of range" do
67
+ assert_raises( ArgumentError ) do
68
+ @user.items_per_page = 0
69
+ end
70
+ assert_raises( ArgumentError ) do
71
+ @user.items_per_page = 101
72
+ end
73
+ end
74
+
75
+ test "set boolean as integer" do
76
+ assert_raises( ArgumentError ) do
77
+ @user.likes_flowers = 10
78
+ end
79
+ end
80
+
81
+ test "set enumerable out of range" do
82
+ assert_raises( ArgumentError ) do
83
+ @user.likes_people = :lot
84
+ end
85
+ end
86
+
87
+ test "set enumerable as string" do
88
+ @user.likes_people = "yes"
89
+ assert_equal :yes, @user.likes_people
90
+ end
91
+
92
+ test "set batch preferences" do
93
+ @user.likes_flowers = true
94
+ @user.likes_animals = true
95
+ @user.preferences = { :items_per_page => 23 }
96
+ assert_equal 23, @user.items_per_page
97
+ # No value for boolean defaulting to true - we assume it was unset
98
+ # TODO: in fact Rails handle this by sending hidden field with the same
99
+ # name, use the same approach
100
+ assert_equal false, @user.likes_flowers?
101
+ # No value for this boolean without default - reset it
102
+ # TODO: this also doesn't seem correct
103
+ assert_nil @user.likes_animals?
104
+ end
105
+ end
106
+
107
+ class ActsAsPreferencedAssociationTest < ActiveSupport::TestCase
108
+
109
+ class UserPreference < FakeModel
110
+
111
+ # Tons of fakes here
112
+ attr_accessor :attributes
113
+
114
+ def items_per_page
115
+ attributes[:items_per_page]
116
+ end
117
+
118
+ def items_per_page= (value)
119
+ attributes[:items_per_page] = value
120
+ end
121
+
122
+ def likes_flowers?
123
+ attributes[:likes_flowers]
124
+ end
125
+
126
+ def likes_flowers= (value)
127
+ attributes[:likes_flowers] = value
128
+ end
129
+
130
+ def likes_animals?
131
+ attributes[:likes_animals]
132
+ end
133
+
134
+ def likes_animals= (value)
135
+ attributes[:likes_animals] = value
136
+ end
137
+
138
+ def likes_people?
139
+ attributes[:likes_people]
140
+ end
141
+
142
+ def likes_people= (value)
143
+ attributes[:likes_people] = value
144
+ end
145
+
146
+ alias_method :likes_flowers, :likes_flowers?
147
+ alias_method :likes_animals, :likes_animals?
148
+ alias_method :likes_people, :likes_people?
149
+ delegate :[], :[]=, :to => :attributes
150
+ end
151
+
152
+ class User < FakeModel
153
+
154
+ attr_accessor :user_preferences
155
+
156
+ acts_as_preferenced( :association => :user_preferences ) do |config|
157
+ config.preference :items_per_page, :section => :general, :choices => (1..100), :default => 20
158
+ config.section :likes, :prefix => true do |section|
159
+ section.preference :flowers, :default => true
160
+ section.preference :animals
161
+ end
162
+ config.preference :likes_people, :choices => [:no, :little, :yes]
163
+ end
164
+ end
165
+
166
+ def setup
167
+ @user = User.new
168
+ @user.user_preferences = UserPreference.new
169
+ end
170
+
171
+ test "all preferences" do
172
+ all = User.all_preferences
173
+ assert_equal [:items_per_page, :likes_flowers, :likes_animals, :likes_people], all.collect(&:name)
174
+ end
175
+
176
+ test "preference sections" do
177
+ assert_equal [:general, nil, :likes], User.preference_sections
178
+ prefs = User.preferences_for_section( :sdjkfajsdf )
179
+ assert prefs.empty?
180
+ prefs = User.preferences_for_section( :likes )
181
+ assert_equal [:likes_flowers, :likes_animals], prefs.collect(&:name)
182
+ prefs = User.preferences_for_section( nil )
183
+ assert_equal [:likes_people], prefs.collect(&:name)
184
+ end
185
+
186
+ test "defaults" do
187
+ assert_equal true, @user.likes_flowers?
188
+ assert_equal 20, @user.items_per_page
189
+ assert_nil @user.likes_animals?
190
+ assert_nil @user.likes_people
191
+ end
192
+
193
+ test "set boolean" do
194
+ @user.likes_flowers = false
195
+ assert_equal false, @user.likes_flowers?
196
+ end
197
+
198
+ test "set integer" do
199
+ @user.items_per_page = 11
200
+ assert_equal 11, @user.items_per_page
201
+ end
202
+
203
+ test "set enumerable" do
204
+ @user.likes_people = :little
205
+ assert_equal :little, @user.likes_people
206
+ end
207
+
208
+ test "set integer as boolean" do
209
+ assert_raises( ArgumentError ) do
210
+ @user.items_per_page = true
211
+ end
212
+ end
213
+
214
+ test "set integer out of range" do
215
+ assert_raises( ArgumentError ) do
216
+ @user.items_per_page = 0
217
+ end
218
+ assert_raises( ArgumentError ) do
219
+ @user.items_per_page = 101
220
+ end
221
+ end
222
+
223
+ test "set boolean as integer" do
224
+ assert_raises( ArgumentError ) do
225
+ @user.likes_flowers = 10
226
+ end
227
+ end
228
+
229
+ test "set enumerable out of range" do
230
+ assert_raises( ArgumentError ) do
231
+ @user.likes_people = :lot
232
+ end
233
+ end
234
+
235
+ test "set enumerable as string" do
236
+ @user.likes_people = "yes"
237
+ assert_equal :yes, @user.likes_people
238
+ end
239
+
240
+ test "set batch preferences" do
241
+ @user.likes_flowers = true
242
+ @user.likes_animals = false
243
+ @user.preferences = { :items_per_page => 23 }
244
+ assert_equal 23, @user.items_per_page
245
+ # No value for boolean defaulting to true - we assume it was unset
246
+ # TODO: in fact Rails handle this by sending hidden field with the same
247
+ # name, use the same approach
248
+ assert_equal false, @user.likes_flowers?
249
+ # No value for this boolean without default - reset it
250
+ # TODO: this also doesn't seem correct
251
+ assert_nil @user.likes_animals?
252
+ end
253
+ end
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'set'
4
+ gem 'activesupport', "> 3.0.0"
5
+ require 'active_support/test_case'
6
+ require 'active_record'
7
+ require 'active_record/base'
8
+ require 'acts_as_preferenced'
9
+ require 'acts_as_preferenced/preference'
10
+ require 'acts_as_preferenced/section'
11
+ require 'acts_as_preferenced/store/base'
12
+ require 'acts_as_preferenced/store/association'
13
+ require 'acts_as_preferenced/store/field'
14
+
15
+ # Class faking AR model behavior - needed to test the validations without the database
16
+ class FakeModel < ActiveRecord::Base
17
+
18
+ self.abstract_class = true
19
+
20
+ def self.columns
21
+ @columns ||= [];
22
+ end
23
+
24
+ def self.column(name, sql_type = nil, default = nil, null = true)
25
+ columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
26
+ end
27
+
28
+ end
29
+
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_preferenced
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marek Janukowicz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Preferences for Rails
15
+ email:
16
+ - marek@janukowicz.net
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/acts_as_preferenced.rb
22
+ - lib/acts_as_preferenced/version.rb
23
+ - lib/acts_as_preferenced/section.rb
24
+ - lib/acts_as_preferenced/store/field.rb
25
+ - lib/acts_as_preferenced/store/association.rb
26
+ - lib/acts_as_preferenced/store/base.rb
27
+ - lib/acts_as_preferenced/preference.rb
28
+ - Gemfile
29
+ - LICENSE.txt
30
+ - Rakefile
31
+ - README
32
+ - test/acts_as_preferences_test.rb
33
+ - test/test_helper.rb
34
+ homepage: ''
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.24
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: ''
58
+ test_files:
59
+ - test/acts_as_preferences_test.rb
60
+ - test/test_helper.rb