ledermann-rails-settings 1.2.0 → 2.5.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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +14 -6
  4. data/Gemfile +1 -1
  5. data/MIT-LICENSE +6 -5
  6. data/README.md +171 -158
  7. data/Rakefile +4 -9
  8. data/ci/Gemfile-rails-4-2 +7 -0
  9. data/ci/Gemfile-rails-5-0 +6 -0
  10. data/ci/Gemfile-rails-5-1 +6 -0
  11. data/ci/Gemfile-rails-5-2 +6 -0
  12. data/ci/Gemfile-rails-6-0 +6 -0
  13. data/lib/generators/rails_settings/migration/migration_generator.rb +23 -0
  14. data/lib/generators/rails_settings/migration/templates/migration.rb +21 -0
  15. data/lib/ledermann-rails-settings.rb +1 -0
  16. data/lib/rails-settings.rb +21 -5
  17. data/lib/rails-settings/base.rb +48 -0
  18. data/lib/rails-settings/configuration.rb +39 -0
  19. data/lib/rails-settings/scopes.rb +34 -0
  20. data/lib/rails-settings/setting_object.rb +84 -0
  21. data/lib/rails-settings/version.rb +2 -2
  22. data/rails-settings.gemspec +22 -21
  23. data/spec/configuration_spec.rb +120 -0
  24. data/spec/database.yml +3 -0
  25. data/spec/queries_spec.rb +101 -0
  26. data/spec/scopes_spec.rb +31 -0
  27. data/spec/serialize_spec.rb +40 -0
  28. data/spec/setting_object_spec.rb +153 -0
  29. data/spec/settings_spec.rb +248 -0
  30. data/spec/spec_helper.rb +111 -0
  31. data/spec/support/matchers/perform_queries.rb +22 -0
  32. data/spec/support/query_counter.rb +17 -0
  33. metadata +130 -118
  34. data/Changelog.md +0 -17
  35. data/ci/Gemfile.rails-2.3.x +0 -5
  36. data/ci/Gemfile.rails-3.0.x +0 -5
  37. data/ci/Gemfile.rails-3.1.x +0 -5
  38. data/ci/Gemfile.rails-3.2.x +0 -5
  39. data/init.rb +0 -1
  40. data/lib/rails-settings/active_record.rb +0 -38
  41. data/lib/rails-settings/null_store.rb +0 -48
  42. data/lib/rails-settings/scoped_settings.rb +0 -14
  43. data/lib/rails-settings/settings.rb +0 -142
  44. data/test/settings_test.rb +0 -252
  45. data/test/test_helper.rb +0 -34
data/spec/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ sqlite:
2
+ adapter: sqlite3
3
+ database: ":memory:"
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Queries performed' do
4
+ context 'New record' do
5
+ let!(:user) { User.new :name => 'Mr. Pink' }
6
+
7
+ it 'should be saved by one SQL query' do
8
+ expect {
9
+ user.save!
10
+ }.to perform_queries(1)
11
+ end
12
+
13
+ it 'should be saved with settings for one key by two SQL queries' do
14
+ expect {
15
+ user.settings(:dashboard).foo = 42
16
+ user.settings(:dashboard).bar = 'string'
17
+ user.save!
18
+ }.to perform_queries(2)
19
+ end
20
+
21
+ it 'should be saved with settings for two keys by three SQL queries' do
22
+ expect {
23
+ user.settings(:dashboard).foo = 42
24
+ user.settings(:dashboard).bar = 'string'
25
+ user.settings(:calendar).bar = 'string'
26
+ user.save!
27
+ }.to perform_queries(3)
28
+ end
29
+ end
30
+
31
+ context 'Existing record without settings' do
32
+ let!(:user) { User.create! :name => 'Mr. Pink' }
33
+
34
+ it 'should be saved without SQL queries' do
35
+ expect {
36
+ user.save!
37
+ }.to perform_queries(0)
38
+ end
39
+
40
+ it 'should be saved with settings for one key by two SQL queries' do
41
+ expect {
42
+ user.settings(:dashboard).foo = 42
43
+ user.settings(:dashboard).bar = 'string'
44
+ user.save!
45
+ }.to perform_queries(2)
46
+ end
47
+
48
+ it 'should be saved with settings for two keys by three SQL queries' do
49
+ expect {
50
+ user.settings(:dashboard).foo = 42
51
+ user.settings(:dashboard).bar = 'string'
52
+ user.settings(:calendar).bar = 'string'
53
+ user.save!
54
+ }.to perform_queries(3)
55
+ end
56
+ end
57
+
58
+ context 'Existing record with settings' do
59
+ let!(:user) do
60
+ User.create! :name => 'Mr. Pink' do |user|
61
+ user.settings(:dashboard).theme = 'pink'
62
+ user.settings(:calendar).scope = 'all'
63
+ end
64
+ end
65
+
66
+ it 'should be saved without SQL queries' do
67
+ expect {
68
+ user.save!
69
+ }.to perform_queries(0)
70
+ end
71
+
72
+ it 'should be saved with settings for one key by one SQL queries' do
73
+ expect {
74
+ user.settings(:dashboard).foo = 42
75
+ user.settings(:dashboard).bar = 'string'
76
+ user.save!
77
+ }.to perform_queries(1)
78
+ end
79
+
80
+ it 'should be saved with settings for two keys by two SQL queries' do
81
+ expect {
82
+ user.settings(:dashboard).foo = 42
83
+ user.settings(:dashboard).bar = 'string'
84
+ user.settings(:calendar).bar = 'string'
85
+ user.save!
86
+ }.to perform_queries(2)
87
+ end
88
+
89
+ it 'should be destroyed by two SQL queries' do
90
+ expect {
91
+ user.destroy
92
+ }.to perform_queries(2)
93
+ end
94
+
95
+ it "should update settings by one SQL query" do
96
+ expect {
97
+ user.settings(:dashboard).update! :foo => 'bar'
98
+ }.to perform_queries(1)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'scopes' do
4
+ let!(:user1) { User.create! :name => 'Mr. White' do |user| user.settings(:dashboard).theme = 'white' end }
5
+ let!(:user2) { User.create! :name => 'Mr. Blue' }
6
+
7
+ it "should find objects with existing settings" do
8
+ expect(User.with_settings).to eq([user1])
9
+ end
10
+
11
+ it "should find objects with settings for key" do
12
+ expect(User.with_settings_for(:dashboard)).to eq([user1])
13
+ expect(User.with_settings_for(:foo)).to eq([])
14
+ end
15
+
16
+ it "should records without settings" do
17
+ expect(User.without_settings).to eq([user2])
18
+ end
19
+
20
+ it "should records without settings for key" do
21
+ expect(User.without_settings_for(:foo)).to eq([user1, user2])
22
+ expect(User.without_settings_for(:dashboard)).to eq([user2])
23
+ end
24
+
25
+ it "should require symbol as key" do
26
+ [ nil, "string", 42 ].each do |invalid_key|
27
+ expect { User.without_settings_for(invalid_key) }.to raise_error(ArgumentError)
28
+ expect { User.with_settings_for(invalid_key) }.to raise_error(ArgumentError)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Serialization" do
4
+ let!(:user) do
5
+ User.create! :name => 'Mr. White' do |user|
6
+ user.settings(:dashboard).theme = 'white'
7
+ user.settings(:calendar).scope = 'all'
8
+ end
9
+ end
10
+
11
+ describe 'created settings' do
12
+ it 'should be serialized' do
13
+ user.reload
14
+
15
+ dashboard_settings = user.setting_objects.where(:var => 'dashboard').first
16
+ calendar_settings = user.setting_objects.where(:var => 'calendar').first
17
+
18
+ expect(dashboard_settings.var).to eq('dashboard')
19
+ expect(dashboard_settings.value).to eq({'theme' => 'white'})
20
+
21
+ expect(calendar_settings.var).to eq('calendar')
22
+ expect(calendar_settings.value).to eq({'scope' => 'all'})
23
+ end
24
+ end
25
+
26
+ describe 'updated settings' do
27
+ it 'should be serialized' do
28
+ user.settings(:dashboard).update! :smart => true
29
+
30
+ dashboard_settings = user.setting_objects.where(:var => 'dashboard').first
31
+ calendar_settings = user.setting_objects.where(:var => 'calendar').first
32
+
33
+ expect(dashboard_settings.var).to eq('dashboard')
34
+ expect(dashboard_settings.value).to eq({'theme' => 'white', 'smart' => true})
35
+
36
+ expect(calendar_settings.var).to eq('calendar')
37
+ expect(calendar_settings.value).to eq({'scope' => 'all'})
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,153 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsSettings::SettingObject do
4
+ let(:user) { User.create! :name => 'Mr. Pink' }
5
+
6
+ if RailsSettings.can_protect_attributes?
7
+ let(:new_setting_object) { user.setting_objects.build({ :var => 'dashboard'}, :without_protection => true) }
8
+ let(:saved_setting_object) { user.setting_objects.create!({ :var => 'dashboard', :value => { 'theme' => 'pink', 'filter' => false}}, :without_protection => true) }
9
+ else
10
+ let(:new_setting_object) { user.setting_objects.build({ :var => 'dashboard'}) }
11
+ let(:saved_setting_object) { user.setting_objects.create!({ :var => 'dashboard', :value => { 'theme' => 'pink', 'filter' => false}}) }
12
+ end
13
+
14
+ describe "serialization" do
15
+ it "should have a hash default" do
16
+ expect(RailsSettings::SettingObject.new.value).to eq({})
17
+ end
18
+ end
19
+
20
+ describe "Getter and Setter" do
21
+ context "on unsaved settings" do
22
+ it "should respond to setters" do
23
+ expect(new_setting_object).to respond_to(:foo=)
24
+ expect(new_setting_object).to respond_to(:bar=)
25
+ end
26
+
27
+ it "should not respond to some getters" do
28
+ expect { new_setting_object.foo! }.to raise_error(NoMethodError)
29
+ expect { new_setting_object.foo? }.to raise_error(NoMethodError)
30
+ end
31
+
32
+ it "should not respond if a block is given" do
33
+ expect {
34
+ new_setting_object.foo do
35
+ end
36
+ }.to raise_error(NoMethodError)
37
+ end
38
+
39
+ it "should not respond if params are given" do
40
+ expect { new_setting_object.foo(42) }.to raise_error(NoMethodError)
41
+ expect { new_setting_object.foo(42,43) }.to raise_error(NoMethodError)
42
+ end
43
+
44
+ it "should return nil for unknown attribute" do
45
+ expect(new_setting_object.foo).to eq(nil)
46
+ expect(new_setting_object.bar).to eq(nil)
47
+ end
48
+
49
+ it "should return defaults" do
50
+ expect(new_setting_object.theme).to eq('blue')
51
+ expect(new_setting_object.view).to eq('monthly')
52
+ expect(new_setting_object.filter).to eq(true)
53
+ end
54
+
55
+ it "should return defaults when using `try`" do
56
+ expect(new_setting_object.try(:theme)).to eq('blue')
57
+ expect(new_setting_object.try(:view)).to eq('monthly')
58
+ expect(new_setting_object.try(:filter)).to eq(true)
59
+ end
60
+
61
+ it "should store different objects to value hash" do
62
+ new_setting_object.integer = 42
63
+ new_setting_object.float = 1.234
64
+ new_setting_object.string = 'Hello, World!'
65
+ new_setting_object.array = [ 1,2,3 ]
66
+ new_setting_object.symbol = :foo
67
+
68
+ expect(new_setting_object.value).to eq('integer' => 42,
69
+ 'float' => 1.234,
70
+ 'string' => 'Hello, World!',
71
+ 'array' => [ 1,2,3 ],
72
+ 'symbol' => :foo)
73
+ end
74
+
75
+ it "should set and return attributes" do
76
+ new_setting_object.theme = 'pink'
77
+ new_setting_object.foo = 42
78
+ new_setting_object.bar = 'hello'
79
+
80
+ expect(new_setting_object.theme).to eq('pink')
81
+ expect(new_setting_object.foo).to eq(42)
82
+ expect(new_setting_object.bar).to eq('hello')
83
+ end
84
+
85
+ it "should set dirty trackers on change" do
86
+ new_setting_object.theme = 'pink'
87
+ expect(new_setting_object).to be_value_changed
88
+ expect(new_setting_object).to be_changed
89
+ end
90
+ end
91
+
92
+ context "on saved settings" do
93
+ it "should not set dirty trackers on setting same value" do
94
+ saved_setting_object.theme = 'pink'
95
+ expect(saved_setting_object).not_to be_value_changed
96
+ expect(saved_setting_object).not_to be_changed
97
+ end
98
+
99
+ it "should delete key on assigning nil" do
100
+ saved_setting_object.theme = nil
101
+ expect(saved_setting_object.value).to eq({ 'filter' => false })
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "update" do
107
+ it 'should save' do
108
+ expect(new_setting_object.update(:foo => 42, :bar => 'string')).to be_truthy
109
+ new_setting_object.reload
110
+
111
+ expect(new_setting_object.foo).to eq(42)
112
+ expect(new_setting_object.bar).to eq('string')
113
+ expect(new_setting_object).not_to be_new_record
114
+ expect(new_setting_object.id).not_to be_zero
115
+ end
116
+
117
+ it 'should not save blank hash' do
118
+ expect(new_setting_object.update({})).to be_truthy
119
+ end
120
+
121
+ if RailsSettings.can_protect_attributes?
122
+ it 'should not allow changing protected attributes' do
123
+ new_setting_object.update!(:var => 'calendar', :foo => 42)
124
+
125
+ expect(new_setting_object.var).to eq('dashboard')
126
+ expect(new_setting_object.foo).to eq(42)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe "save" do
132
+ it "should save" do
133
+ new_setting_object.foo = 42
134
+ new_setting_object.bar = 'string'
135
+ expect(new_setting_object.save).to be_truthy
136
+ new_setting_object.reload
137
+
138
+ expect(new_setting_object.foo).to eq(42)
139
+ expect(new_setting_object.bar).to eq('string')
140
+ expect(new_setting_object).not_to be_new_record
141
+ expect(new_setting_object.id).not_to be_zero
142
+ end
143
+ end
144
+
145
+ describe "validation" do
146
+ it "should not validate for unknown var" do
147
+ new_setting_object.var = "unknown-var"
148
+
149
+ expect(new_setting_object).not_to be_valid
150
+ expect(new_setting_object.errors[:var]).to be_present
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Defaults" do
4
+ it "should be stored for simple class" do
5
+ expect(Account.default_settings).to eq(:portal => {})
6
+ end
7
+
8
+ it "should be stored for parent class" do
9
+ expect(User.default_settings).to eq(:dashboard => { 'theme' => 'blue', 'view' => 'monthly', 'filter' => true },
10
+ :calendar => { 'scope' => 'company'})
11
+ end
12
+
13
+ it "should be stored for child class" do
14
+ expect(GuestUser.default_settings).to eq(:dashboard => { 'theme' => 'red', 'view' => 'monthly', 'filter' => true })
15
+ end
16
+ end
17
+
18
+ describe "Getter/Setter" do
19
+ let(:account) { Account.new :subdomain => 'foo' }
20
+
21
+ it "should handle method syntax" do
22
+ account.settings(:portal).enabled = true
23
+ account.settings(:portal).template = 'black'
24
+
25
+ expect(account.settings(:portal).enabled).to eq(true)
26
+ expect(account.settings(:portal).template).to eq('black')
27
+ end
28
+
29
+ it "should return nil for not existing key" do
30
+ expect(account.settings(:portal).foo).to eq(nil)
31
+ end
32
+ end
33
+
34
+ describe 'Objects' do
35
+ context 'without defaults' do
36
+ let(:account) { Account.new :subdomain => 'foo' }
37
+
38
+ it 'should have blank settings' do
39
+ expect(account.settings(:portal).value).to eq({})
40
+ end
41
+
42
+ it 'should allow saving a blank value' do
43
+ account.save!
44
+ expect(account.settings(:portal).save).to be_truthy
45
+ end
46
+
47
+ it 'should allow removing all values' do
48
+ account.settings(:portal).premium = true
49
+ account.settings(:portal).fee = 42.5
50
+ account.save!
51
+
52
+ account.settings(:portal).premium = nil
53
+ expect(account.save).to be_truthy
54
+
55
+ account.settings(:portal).fee = nil
56
+ expect(account.save).to be_truthy
57
+ end
58
+
59
+ it 'should not add settings on saving' do
60
+ account.save!
61
+ expect(RailsSettings::SettingObject.count).to eq(0)
62
+ end
63
+
64
+ it "should save object with settings" do
65
+ account.settings(:portal).premium = true
66
+ account.settings(:portal).fee = 42.5
67
+ account.save!
68
+
69
+ account.reload
70
+ expect(account.settings(:portal).premium).to eq(true)
71
+ expect(account.settings(:portal).fee).to eq(42.5)
72
+
73
+ expect(RailsSettings::SettingObject.count).to eq(1)
74
+ expect(RailsSettings::SettingObject.first.value).to eq({ 'premium' => true, 'fee' => 42.5 })
75
+ end
76
+
77
+ it "should save settings separated" do
78
+ account.save!
79
+
80
+ settings = account.settings(:portal)
81
+ settings.enabled = true
82
+ settings.template = 'black'
83
+ settings.save!
84
+
85
+ account.reload
86
+ expect(account.settings(:portal).enabled).to eq(true)
87
+ expect(account.settings(:portal).template).to eq('black')
88
+ end
89
+ end
90
+
91
+ context 'with defaults' do
92
+ let(:user) { User.new :name => 'Mr. Brown' }
93
+
94
+ it 'should have default settings' do
95
+ expect(user.settings(:dashboard).theme).to eq('blue')
96
+ expect(user.settings(:dashboard).view).to eq('monthly')
97
+ expect(user.settings(:dashboard).filter).to eq(true)
98
+ expect(user.settings(:calendar).scope).to eq('company')
99
+ end
100
+
101
+ it 'should have default settings after changing one' do
102
+ user.settings(:dashboard).theme = 'gray'
103
+
104
+ expect(user.settings(:dashboard).theme).to eq('gray')
105
+ expect(user.settings(:dashboard).view).to eq('monthly')
106
+ expect(user.settings(:dashboard).filter).to eq(true)
107
+ expect(user.settings(:calendar).scope).to eq('company')
108
+ end
109
+
110
+ it "should overwrite settings" do
111
+ user.settings(:dashboard).theme = 'brown'
112
+ user.settings(:dashboard).filter = false
113
+ user.save!
114
+
115
+ user.reload
116
+ expect(user.settings(:dashboard).theme).to eq('brown')
117
+ expect(user.settings(:dashboard).filter).to eq(false)
118
+ expect(RailsSettings::SettingObject.count).to eq(1)
119
+ expect(RailsSettings::SettingObject.first.value).to eq({ 'theme' => 'brown', 'filter' => false })
120
+ end
121
+
122
+ it "should merge settings with defaults" do
123
+ user.settings(:dashboard).theme = 'brown'
124
+ user.save!
125
+
126
+ user.reload
127
+ expect(user.settings(:dashboard).theme).to eq('brown')
128
+ expect(user.settings(:dashboard).filter).to eq(true)
129
+ expect(RailsSettings::SettingObject.count).to eq(1)
130
+ expect(RailsSettings::SettingObject.first.value).to eq({ 'theme' => 'brown' })
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "Object without settings" do
136
+ let!(:user) { User.create! :name => 'Mr. White' }
137
+
138
+ it "should respond to #settings?" do
139
+ expect(user.settings?).to eq(false)
140
+ expect(user.settings?(:dashboard)).to eq(false)
141
+ end
142
+
143
+ it "should have no setting objects" do
144
+ expect(RailsSettings::SettingObject.count).to eq(0)
145
+ end
146
+
147
+ it "should add settings" do
148
+ user.settings(:dashboard).update! :smart => true
149
+
150
+ user.reload
151
+ expect(user.settings(:dashboard).smart).to eq(true)
152
+ end
153
+
154
+ it "should not save settings if assigned nil" do
155
+ expect {
156
+ user.settings = nil
157
+ user.save!
158
+ }.to_not change(RailsSettings::SettingObject, :count)
159
+ end
160
+ end
161
+
162
+ describe "Object with settings" do
163
+ let!(:user) do
164
+ User.create! :name => 'Mr. White' do |user|
165
+ user.settings(:dashboard).theme = 'white'
166
+ user.settings(:calendar).scope = 'all'
167
+ end
168
+ end
169
+
170
+ it "should respond to #settings?" do
171
+ expect(user.settings?).to eq(true)
172
+
173
+ expect(user.settings?(:dashboard)).to eq(true)
174
+ expect(user.settings?(:calendar)).to eq(true)
175
+ end
176
+
177
+ it "should have two setting objects" do
178
+ expect(RailsSettings::SettingObject.count).to eq(2)
179
+ end
180
+
181
+ it "should update settings" do
182
+ user.settings(:dashboard).update! :smart => true
183
+ user.reload
184
+
185
+ expect(user.settings(:dashboard).smart).to eq(true)
186
+ expect(user.settings(:dashboard).theme).to eq('white')
187
+ expect(user.settings(:calendar).scope).to eq('all')
188
+ end
189
+
190
+ it "should update settings by saving object" do
191
+ user.settings(:dashboard).smart = true
192
+ user.save!
193
+
194
+ user.reload
195
+ expect(user.settings(:dashboard).smart).to eq(true)
196
+ end
197
+
198
+ it "should destroy settings with nil" do
199
+ expect {
200
+ user.settings = nil
201
+ user.save!
202
+ }.to change(RailsSettings::SettingObject, :count).by(-2)
203
+
204
+ expect(user.settings?).to eq(false)
205
+ end
206
+
207
+ it "should raise exception on assigning other than nil" do
208
+ expect {
209
+ user.settings = :foo
210
+ user.save!
211
+ }.to raise_error(ArgumentError)
212
+ end
213
+ end
214
+
215
+ describe "Customized SettingObject" do
216
+ let(:project) { Project.create! :name => 'Heist' }
217
+
218
+ it "should not accept invalid attributes" do
219
+ project.settings(:info).owner_name = 42
220
+ expect(project.settings(:info)).not_to be_valid
221
+
222
+ project.settings(:info).owner_name = ''
223
+ expect(project.settings(:info)).not_to be_valid
224
+ end
225
+
226
+ it "should accept valid attributes" do
227
+ project.settings(:info).owner_name = 'Mr. Brown'
228
+ expect(project.settings(:info)).to be_valid
229
+ end
230
+ end
231
+
232
+ describe "to_settings_hash" do
233
+ let(:user) do
234
+ User.new :name => 'Mrs. Fin' do |user|
235
+ user.settings(:dashboard).theme = 'green'
236
+ user.settings(:dashboard).sound = 11
237
+ user.settings(:calendar).scope = 'some'
238
+ end
239
+ end
240
+
241
+ it "should return defaults" do
242
+ expect(User.new.to_settings_hash).to eq({:dashboard=>{"theme"=>"blue", "view"=>"monthly", "filter"=>true}, :calendar=>{"scope"=>"company"}})
243
+ end
244
+
245
+ it "should return merged settings" do
246
+ expect(user.to_settings_hash).to eq({:dashboard=>{"theme"=>"green", "view"=>"monthly", "filter"=>true, "sound" => 11}, :calendar=>{"scope"=>"some"}})
247
+ end
248
+ end