ledermann-rails-settings 1.2.0 → 2.0.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.
- checksums.yaml +7 -0
- data/.travis.yml +2 -3
- data/Changelog.md +22 -1
- data/Gemfile +1 -1
- data/MIT-LICENSE +6 -5
- data/README.md +133 -158
- data/Rakefile +4 -9
- data/ci/Gemfile.rails-3.1.x +4 -3
- data/ci/Gemfile.rails-3.2.x +4 -3
- data/lib/generators/rails_settings/migration/migration_generator.rb +23 -0
- data/lib/generators/rails_settings/migration/templates/migration.rb +15 -0
- data/lib/rails-settings.rb +14 -5
- data/lib/rails-settings/base.rb +36 -0
- data/lib/rails-settings/configuration.rb +32 -0
- data/lib/rails-settings/scopes.rb +33 -0
- data/lib/rails-settings/setting_object.rb +64 -0
- data/lib/rails-settings/version.rb +2 -2
- data/rails-settings.gemspec +18 -21
- data/spec/configuration_spec.rb +108 -0
- data/spec/queries_spec.rb +108 -0
- data/spec/scopes_spec.rb +31 -0
- data/spec/serialize_spec.rb +40 -0
- data/spec/setting_object_spec.rb +119 -0
- data/spec/settings_spec.rb +206 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/support/matchers/perform_queries.rb +18 -0
- data/spec/support/query_counter.rb +17 -0
- metadata +100 -121
- data/ci/Gemfile.rails-2.3.x +0 -5
- data/ci/Gemfile.rails-3.0.x +0 -5
- data/init.rb +0 -1
- data/lib/rails-settings/active_record.rb +0 -38
- data/lib/rails-settings/null_store.rb +0 -48
- data/lib/rails-settings/scoped_settings.rb +0 -14
- data/lib/rails-settings/settings.rb +0 -142
- data/test/settings_test.rb +0 -252
- data/test/test_helper.rb +0 -34
data/spec/scopes_spec.rb
ADDED
@@ -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
|
+
User.with_settings.should eq([user1])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should find objects with settings for key" do
|
12
|
+
User.with_settings_for(:dashboard).should eq([user1])
|
13
|
+
User.with_settings_for(:foo).should eq([])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should records without settings" do
|
17
|
+
User.without_settings.should eq([user2])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should records without settings for key" do
|
21
|
+
User.without_settings_for(:foo).should eq([user1, user2])
|
22
|
+
User.without_settings_for(:dashboard).should 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
|
+
dashboard_settings.var.should == 'dashboard'
|
19
|
+
dashboard_settings.value.should eq({'theme' => 'white'})
|
20
|
+
|
21
|
+
calendar_settings.var.should == 'calendar'
|
22
|
+
calendar_settings.value.should eq({'scope' => 'all'})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'updated settings' do
|
27
|
+
it 'should be serialized' do
|
28
|
+
user.settings(:dashboard).update_attributes! :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
|
+
dashboard_settings.var.should == 'dashboard'
|
34
|
+
dashboard_settings.value.should eq({'theme' => 'white', 'smart' => true})
|
35
|
+
|
36
|
+
calendar_settings.var.should == 'calendar'
|
37
|
+
calendar_settings.value.should eq({'scope' => 'all'})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsSettings::SettingObject do
|
4
|
+
let(:user) { User.create! :name => 'Mr. Pink' }
|
5
|
+
let(:new_setting_object) { user.setting_objects.build :var => 'dashboard' }
|
6
|
+
let(:saved_setting_object) { user.setting_objects.create! :var => 'dashboard', :value => { 'theme' => 'pink', 'filter' => true } }
|
7
|
+
|
8
|
+
describe "Getter and Setter" do
|
9
|
+
context "on unsaved settings" do
|
10
|
+
it "should respond to setters" do
|
11
|
+
new_setting_object.should respond_to(:foo=)
|
12
|
+
new_setting_object.should respond_to(:bar=)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not respond to some getters" do
|
16
|
+
expect { new_setting_object.foo! }.to raise_error(NoMethodError)
|
17
|
+
expect { new_setting_object.foo? }.to raise_error(NoMethodError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not respond if a block is given" do
|
21
|
+
expect {
|
22
|
+
new_setting_object.foo do
|
23
|
+
end
|
24
|
+
}.to raise_error(NoMethodError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not respond if params are given" do
|
28
|
+
expect { new_setting_object.foo(42) }.to raise_error(NoMethodError)
|
29
|
+
expect { new_setting_object.foo(42,43) }.to raise_error(NoMethodError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return nil for unknown attribute" do
|
33
|
+
new_setting_object.foo.should eq(nil)
|
34
|
+
new_setting_object.bar.should eq(nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return defaults" do
|
38
|
+
new_setting_object.theme.should eq('blue')
|
39
|
+
new_setting_object.view.should eq('monthly')
|
40
|
+
new_setting_object.filter.should eq(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should store to value hash" do
|
44
|
+
new_setting_object.foo = 42
|
45
|
+
new_setting_object.bar = 'hello'
|
46
|
+
|
47
|
+
new_setting_object.value.should eq({'foo' => 42, 'bar' => 'hello'})
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set and return attributes" do
|
51
|
+
new_setting_object.theme = 'pink'
|
52
|
+
new_setting_object.foo = 42
|
53
|
+
new_setting_object.bar = 'hello'
|
54
|
+
|
55
|
+
new_setting_object.theme.should eq('pink')
|
56
|
+
new_setting_object.foo.should eq(42)
|
57
|
+
new_setting_object.bar.should eq('hello')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set dirty trackers on change" do
|
61
|
+
new_setting_object.theme = 'pink'
|
62
|
+
new_setting_object.should be_value_changed
|
63
|
+
new_setting_object.should be_changed
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "on saved settings" do
|
68
|
+
it "should not set dirty trackers on setting same value" do
|
69
|
+
saved_setting_object.theme = 'pink'
|
70
|
+
saved_setting_object.should_not be_value_changed
|
71
|
+
saved_setting_object.should_not be_changed
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should delete key on assigning nil" do
|
75
|
+
saved_setting_object.theme = nil
|
76
|
+
saved_setting_object.value.should == { 'filter' => true }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "update_attributes" do
|
82
|
+
it 'should save' do
|
83
|
+
new_setting_object.update_attributes(:foo => 42, :bar => 'string').should be_true
|
84
|
+
new_setting_object.reload
|
85
|
+
|
86
|
+
new_setting_object.foo.should eq(42)
|
87
|
+
new_setting_object.bar.should eq('string')
|
88
|
+
new_setting_object.should_not be_new_record
|
89
|
+
new_setting_object.id.should_not be_zero
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should not save blank hash' do
|
93
|
+
new_setting_object.update_attributes({}).should be_false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "save" do
|
98
|
+
it "should save" do
|
99
|
+
new_setting_object.foo = 42
|
100
|
+
new_setting_object.bar = 'string'
|
101
|
+
new_setting_object.save.should be_true
|
102
|
+
new_setting_object.reload
|
103
|
+
|
104
|
+
new_setting_object.foo.should eq(42)
|
105
|
+
new_setting_object.bar.should eq('string')
|
106
|
+
new_setting_object.should_not be_new_record
|
107
|
+
new_setting_object.id.should_not be_zero
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "validation" do
|
112
|
+
it "should not validate for unknown var" do
|
113
|
+
new_setting_object.var = "unknown-var"
|
114
|
+
|
115
|
+
new_setting_object.should_not be_valid
|
116
|
+
new_setting_object.errors[:var].should be_present
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Defaults" do
|
4
|
+
it "should be stored for simple class" do
|
5
|
+
Account.default_settings.should eq(:portal => {})
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be stored for parent class" do
|
9
|
+
User.default_settings.should eq(:dashboard => { 'theme' => 'blue', 'view' => 'monthly', 'filter' => false },
|
10
|
+
:calendar => { 'scope' => 'company'})
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be stored for child class" do
|
14
|
+
GuestUser.default_settings.should eq(:dashboard => { 'theme' => 'red', 'view' => 'monthly', 'filter' => false })
|
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
|
+
account.settings(:portal).enabled.should eq(true)
|
26
|
+
account.settings(:portal).template.should eq('black')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return nil for not existing key" do
|
30
|
+
account.settings(:portal).foo.should 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
|
+
account.settings(:portal).value.should eq({})
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not add settings on saving' do
|
43
|
+
account.save!
|
44
|
+
RailsSettings::SettingObject.count.should eq(0)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should save object with settings" do
|
48
|
+
account.settings(:portal).premium = true
|
49
|
+
account.settings(:portal).fee = 42.5
|
50
|
+
account.save!
|
51
|
+
|
52
|
+
account.reload
|
53
|
+
account.settings(:portal).premium.should eq(true)
|
54
|
+
account.settings(:portal).fee.should eq(42.5)
|
55
|
+
|
56
|
+
RailsSettings::SettingObject.count.should eq(1)
|
57
|
+
RailsSettings::SettingObject.first.value.should == { 'premium' => true, 'fee' => 42.5 }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should save settings separated" do
|
61
|
+
account.save!
|
62
|
+
|
63
|
+
settings = account.settings(:portal)
|
64
|
+
settings.enabled = true
|
65
|
+
settings.template = 'black'
|
66
|
+
settings.save!
|
67
|
+
|
68
|
+
account.reload
|
69
|
+
account.settings(:portal).enabled.should eq(true)
|
70
|
+
account.settings(:portal).template.should eq('black')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with defaults' do
|
75
|
+
let(:user) { User.new :name => 'Mr. Brown' }
|
76
|
+
|
77
|
+
it 'should have default settings' do
|
78
|
+
user.settings(:dashboard).theme.should eq('blue')
|
79
|
+
user.settings(:dashboard).view.should eq('monthly')
|
80
|
+
user.settings(:dashboard).filter.should eq(false)
|
81
|
+
user.settings(:calendar).scope.should eq('company')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should have default settings after changing one' do
|
85
|
+
user.settings(:dashboard).theme = 'gray'
|
86
|
+
|
87
|
+
user.settings(:dashboard).theme.should eq('gray')
|
88
|
+
user.settings(:dashboard).view.should eq('monthly')
|
89
|
+
user.settings(:dashboard).filter.should eq(false)
|
90
|
+
user.settings(:calendar).scope.should eq('company')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should overwrite settings" do
|
94
|
+
user.settings(:dashboard).theme = 'brown'
|
95
|
+
user.settings(:dashboard).filter = true
|
96
|
+
user.save!
|
97
|
+
|
98
|
+
user.reload
|
99
|
+
user.settings(:dashboard).theme.should eq('brown')
|
100
|
+
user.settings(:dashboard).filter.should eq(true)
|
101
|
+
RailsSettings::SettingObject.count.should eq(1)
|
102
|
+
RailsSettings::SettingObject.first.value.should == { 'theme' => 'brown', 'filter' => true }
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should merge settings with defaults" do
|
106
|
+
user.settings(:dashboard).theme = 'brown'
|
107
|
+
user.save!
|
108
|
+
|
109
|
+
user.reload
|
110
|
+
user.settings(:dashboard).theme.should eq('brown')
|
111
|
+
user.settings(:dashboard).filter.should eq(false)
|
112
|
+
RailsSettings::SettingObject.count.should eq(1)
|
113
|
+
RailsSettings::SettingObject.first.value.should == { 'theme' => 'brown' }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "Object without settings" do
|
119
|
+
let!(:user) { User.create! :name => 'Mr. White' }
|
120
|
+
|
121
|
+
it "should respond to #settings?" do
|
122
|
+
user.settings?.should eq(false)
|
123
|
+
user.settings?(:dashboard).should eq(false)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should have no setting objects" do
|
127
|
+
RailsSettings::SettingObject.count.should eq(0)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should add settings" do
|
131
|
+
user.settings(:dashboard).update_attributes! :smart => true
|
132
|
+
|
133
|
+
user.reload
|
134
|
+
user.settings(:dashboard).smart.should eq(true)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not save settings if assigned nil" do
|
138
|
+
expect {
|
139
|
+
user.settings = nil
|
140
|
+
user.save!
|
141
|
+
}.to_not change(RailsSettings::SettingObject, :count)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "Object with settings" do
|
146
|
+
let!(:user) do
|
147
|
+
User.create! :name => 'Mr. White' do |user|
|
148
|
+
user.settings(:dashboard).theme = 'white'
|
149
|
+
user.settings(:calendar).scope = 'all'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should respond to #settings?" do
|
154
|
+
user.settings?.should eq(true)
|
155
|
+
|
156
|
+
user.settings?(:dashboard).should eq(true)
|
157
|
+
user.settings?(:calendar).should eq(true)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should have two setting objects" do
|
161
|
+
RailsSettings::SettingObject.count.should eq(2)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should update settings" do
|
165
|
+
user.settings(:dashboard).update_attributes! :smart => true
|
166
|
+
user.reload
|
167
|
+
|
168
|
+
user.settings(:dashboard).smart.should eq(true)
|
169
|
+
user.settings(:dashboard).theme.should eq('white')
|
170
|
+
user.settings(:calendar).scope.should eq('all')
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should update settings by saving object" do
|
174
|
+
user.settings(:dashboard).smart = true
|
175
|
+
user.save!
|
176
|
+
|
177
|
+
user.reload
|
178
|
+
user.settings(:dashboard).smart.should eq(true)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should destroy settings with nil" do
|
182
|
+
expect {
|
183
|
+
user.settings = nil
|
184
|
+
user.save!
|
185
|
+
}.to change(RailsSettings::SettingObject, :count).by(-2)
|
186
|
+
|
187
|
+
user.settings?.should == false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "Customized SettingObject" do
|
192
|
+
let(:project) { Project.create! :name => 'Heist' }
|
193
|
+
|
194
|
+
it "should not accept invalid attributes" do
|
195
|
+
project.settings(:info).owner_name = 42
|
196
|
+
project.settings(:info).should_not be_valid
|
197
|
+
|
198
|
+
project.settings(:info).owner_name = ''
|
199
|
+
project.settings(:info).should_not be_valid
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should accept valid attributes" do
|
203
|
+
project.settings(:info).owner_name = 'Mr. Brown'
|
204
|
+
project.settings(:info).should be_valid
|
205
|
+
end
|
206
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
2
|
+
# in spec/support/ and its subdirectories.
|
3
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
4
|
+
|
5
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
6
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
7
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
8
|
+
# loaded once.
|
9
|
+
#
|
10
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
11
|
+
RSpec.configure do |config|
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
# config.order = 'random'
|
17
|
+
|
18
|
+
config.before(:each) do
|
19
|
+
clear_db
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'active_record'
|
24
|
+
require 'rails-settings'
|
25
|
+
|
26
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
27
|
+
ActiveRecord::Migration.verbose = false
|
28
|
+
|
29
|
+
class User < ActiveRecord::Base
|
30
|
+
has_settings do |s|
|
31
|
+
s.key :dashboard, :defaults => { :theme => 'blue', :view => 'monthly', :filter => false }
|
32
|
+
s.key :calendar, :defaults => { :scope => 'company'}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class GuestUser < User
|
37
|
+
has_settings do |s|
|
38
|
+
s.key :dashboard, :defaults => { :theme => 'red', :view => 'monthly', :filter => false }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Account < ActiveRecord::Base
|
43
|
+
has_settings :portal
|
44
|
+
end
|
45
|
+
|
46
|
+
class Project < ActiveRecord::Base
|
47
|
+
has_settings :info, :class_name => 'ProjectSettingObject'
|
48
|
+
end
|
49
|
+
|
50
|
+
class ProjectSettingObject < RailsSettings::SettingObject
|
51
|
+
validate do
|
52
|
+
unless self.owner_name.present? && self.owner_name.is_a?(String)
|
53
|
+
errors.add(:base, "Owner name is missing")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup_db
|
59
|
+
ActiveRecord::Schema.define(:version => 1) do
|
60
|
+
create_table :settings do |t|
|
61
|
+
t.string :var, :null => false
|
62
|
+
t.text :value, :null => false
|
63
|
+
t.references :target, :null => false, :polymorphic => true
|
64
|
+
t.timestamps
|
65
|
+
end
|
66
|
+
add_index :settings, [ :target_type, :target_id, :var ], :unique => true
|
67
|
+
|
68
|
+
create_table :users do |t|
|
69
|
+
t.string :type
|
70
|
+
t.string :name
|
71
|
+
end
|
72
|
+
|
73
|
+
create_table :accounts do |t|
|
74
|
+
t.string :subdomain
|
75
|
+
end
|
76
|
+
|
77
|
+
create_table :projects do |t|
|
78
|
+
t.string :name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def clear_db
|
84
|
+
User.delete_all
|
85
|
+
Account.delete_all
|
86
|
+
RailsSettings::SettingObject.delete_all
|
87
|
+
end
|
88
|
+
|
89
|
+
puts "Testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
|
90
|
+
setup_db
|