enumerize 1.0.0 → 1.1.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 +4 -4
- data/.rspec +2 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -20
- data/Gemfile.global +20 -0
- data/Gemfile.mongo_mapper +3 -20
- data/Gemfile.rails40 +2 -19
- data/README.md +146 -6
- data/Rakefile +2 -4
- data/lib/enumerize.rb +7 -0
- data/lib/enumerize/base.rb +3 -1
- data/lib/enumerize/hooks/sequel_dataset.rb +19 -0
- data/lib/enumerize/integrations/rspec/matcher.rb +107 -26
- data/lib/enumerize/scope/sequel.rb +40 -0
- data/lib/enumerize/sequel.rb +57 -0
- data/lib/enumerize/set.rb +2 -1
- data/lib/enumerize/version.rb +1 -1
- data/spec/enumerize/integrations/rspec/matcher_spec.rb +254 -0
- data/spec/spec_helper.rb +24 -0
- data/test/sequel_test.rb +291 -0
- data/test/value_test.rb +35 -27
- metadata +14 -7
- data/test/rspec_matcher_test.rb +0 -76
- data/test/rspec_spec.rb +0 -14
@@ -0,0 +1,40 @@
|
|
1
|
+
module Enumerize
|
2
|
+
module Scope
|
3
|
+
module Sequel
|
4
|
+
def enumerize(name, options={})
|
5
|
+
super
|
6
|
+
|
7
|
+
_enumerize_module.dependent_eval do
|
8
|
+
if defined?(::Sequel::Model) && self < ::Sequel::Model
|
9
|
+
if options[:scope]
|
10
|
+
_define_sequel_scope_methods!(name, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'enumerize/hooks/sequel_dataset'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def _define_sequel_scope_methods!(name, options)
|
21
|
+
klass = self
|
22
|
+
scope_name = options[:scope] == true ? "with_#{name}" : options[:scope]
|
23
|
+
|
24
|
+
def_dataset_method scope_name do |*values|
|
25
|
+
values = values.map { |value| klass.enumerized_attributes[name].find_value(value).value }
|
26
|
+
values = values.first if values.size == 1
|
27
|
+
|
28
|
+
where(name => values)
|
29
|
+
end
|
30
|
+
|
31
|
+
if options[:scope] == true
|
32
|
+
def_dataset_method "without_#{name}" do |*values|
|
33
|
+
values = values.map { |value| klass.enumerized_attributes[name].find_value(value).value }
|
34
|
+
exclude(name => values)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Enumerize
|
2
|
+
module SequelSupport
|
3
|
+
def enumerize(name, options={})
|
4
|
+
super
|
5
|
+
|
6
|
+
_enumerize_module.dependent_eval do
|
7
|
+
if defined?(::Sequel::Model) && self < ::Sequel::Model
|
8
|
+
include InstanceMethods
|
9
|
+
|
10
|
+
require 'enumerize/hooks/sequel_dataset'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def validate
|
19
|
+
super
|
20
|
+
|
21
|
+
self.class.enumerized_attributes.each do |attr|
|
22
|
+
value = read_attribute_for_validation(attr.name)
|
23
|
+
next if value.blank?
|
24
|
+
|
25
|
+
if attr.kind_of? Multiple
|
26
|
+
errors.add attr.name, "is invalid" unless value.respond_to?(:all?) && value.all? { |v| v.blank? || attr.find_value(v) }
|
27
|
+
else
|
28
|
+
errors.add attr.name, "is not included in the list" unless attr.find_value(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def _set_default_value_for_enumerized_attributes
|
34
|
+
_enumerized_values_for_validation.delete_if do |k, v|
|
35
|
+
v.nil?
|
36
|
+
end
|
37
|
+
|
38
|
+
if defined?(Sequel::Plugins::Serialization::InstanceMethods)
|
39
|
+
modules = self.class.ancestors
|
40
|
+
plugin_idx = modules.index(Sequel::Plugins::Serialization::InstanceMethods)
|
41
|
+
|
42
|
+
if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods)
|
43
|
+
abort "ERROR: You need to enable the Sequel serialization plugin before calling any enumerize methods on a model."
|
44
|
+
end
|
45
|
+
|
46
|
+
plugin_idx = modules.index(Sequel::Plugins::ValidationHelpers::InstanceMethods)
|
47
|
+
|
48
|
+
if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods)
|
49
|
+
abort "ERROR: You need to enable the Sequel validation_helpers plugin before calling any enumerize methods on a model."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/enumerize/set.rb
CHANGED
@@ -37,12 +37,13 @@ module Enumerize
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def texts
|
40
|
-
@values.
|
40
|
+
@values.map(&:text)
|
41
41
|
end
|
42
42
|
|
43
43
|
delegate :join, to: :to_ary
|
44
44
|
|
45
45
|
def ==(other)
|
46
|
+
return false unless other.respond_to?(:each)
|
46
47
|
other.size == size && other.all? { |v| @values.include?(@attr.find_value(v)) }
|
47
48
|
end
|
48
49
|
|
data/lib/enumerize/version.rb
CHANGED
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
silence_warnings do
|
4
|
+
ActiveRecord::Migration.verbose = false
|
5
|
+
ActiveRecord::Base.logger = Logger.new(nil)
|
6
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
|
+
end
|
8
|
+
|
9
|
+
ActiveRecord::Base.connection.instance_eval do
|
10
|
+
create_table :users do |t|
|
11
|
+
t.string :sex
|
12
|
+
t.string :role
|
13
|
+
t.string :account_type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class User < ActiveRecord::Base
|
18
|
+
extend Enumerize
|
19
|
+
|
20
|
+
enumerize :sex, :in => [:male, :female], scope: true
|
21
|
+
enumerize :role, :in => [:user, :admin], scope: :having_role
|
22
|
+
enumerize :account_type, :in => [:basic, :premium]
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec.describe Enumerize::Integrations::RSpec::Matcher do
|
26
|
+
|
27
|
+
let(:model) do
|
28
|
+
Class.new do
|
29
|
+
extend Enumerize
|
30
|
+
|
31
|
+
def self.name
|
32
|
+
'Model'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
subject do
|
38
|
+
model.new
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'without qualifier' do
|
42
|
+
|
43
|
+
it 'accepts when has defined a enumerize' do
|
44
|
+
model.enumerize(:sex, :in => [:male, :female])
|
45
|
+
expect(subject).to enumerize(:sex)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'rejects when has not defined a enumerize' do
|
49
|
+
message = 'Expected Model to define enumerize :sex'
|
50
|
+
expect do
|
51
|
+
expect(subject).to enumerize(:sex)
|
52
|
+
end.to fail_with(message)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#in' do
|
57
|
+
|
58
|
+
context 'defined as array' do
|
59
|
+
|
60
|
+
before do
|
61
|
+
model.enumerize(:sex, :in => [:male, :female])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'accepts the right params as a array' do
|
65
|
+
expect(subject).to enumerize(:sex).in(:male, :female)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'accepts the the right params in a different order' do
|
69
|
+
expect(subject).to enumerize(:sex).in(:female, :male)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'rejects wrong params' do
|
73
|
+
message = 'Expected Model to define enumerize :sex in: "boy", "girl"'
|
74
|
+
expect do
|
75
|
+
expect(subject).to enumerize(:sex).in(:boy, :girl)
|
76
|
+
end.to fail_with(message)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'has the right message when negated' do
|
80
|
+
message = 'Did not expect Model to define enumerize :sex in: "female", "male"'
|
81
|
+
expect do
|
82
|
+
expect(subject).to_not enumerize(:sex).in(:male, :female)
|
83
|
+
end.to fail_with(message)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'defined as hash' do
|
88
|
+
|
89
|
+
before do
|
90
|
+
model.enumerize(:sex, :in => { male: 0, female: 1 })
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'accepts the right params as a array' do
|
94
|
+
expect(subject).to enumerize(:sex).in(:male, :female)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'accepts the right params as a hash' do
|
98
|
+
expect(subject).to enumerize(:sex).in(male: 0, female: 1)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'accepts the right params as a hash in a different order' do
|
102
|
+
expect(subject).to enumerize(:sex).in(female: 1, male: 0)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'rejects wrong keys' do
|
106
|
+
message = 'Expected Model to define enumerize :sex in: "{:boy=>0, :girl=>1}"'
|
107
|
+
expect do
|
108
|
+
expect(subject).to enumerize(:sex).in(boy: 0, girl: 1)
|
109
|
+
end.to fail_with(message)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'rejects wrong values' do
|
113
|
+
message = 'Expected Model to define enumerize :sex in: "{:male=>2, :female=>3}"'
|
114
|
+
expect do
|
115
|
+
expect(subject).to enumerize(:sex).in(male: 2, female: 3)
|
116
|
+
end.to fail_with(message)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'has the right description' do
|
121
|
+
matcher = enumerize(:sex).in(:male, :female)
|
122
|
+
expect(matcher.description).to eq('define enumerize :sex in: "female", "male"')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#with_default' do
|
127
|
+
|
128
|
+
before do
|
129
|
+
model.enumerize(:sex, :in => [:male, :female], default: :female)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'accepts the right default value' do
|
133
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_default(:female)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'rejects the wrong default value' do
|
137
|
+
message = 'Expected Model to define enumerize :sex in: "female", "male" with "male" as default value'
|
138
|
+
expect do
|
139
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_default(:male)
|
140
|
+
end.to fail_with(message)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'rejects if the `in` is wrong with a correct default value' do
|
144
|
+
message = 'Expected Model to define enumerize :sex in: "boy", "girl" with "female" as default value'
|
145
|
+
expect do
|
146
|
+
expect(subject).to enumerize(:sex).in(:boy, :girl).with_default(:female)
|
147
|
+
end.to fail_with(message)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'has the right description' do
|
151
|
+
matcher = enumerize(:sex).in(:male, :female).with_default(:female)
|
152
|
+
message = 'define enumerize :sex in: "female", "male" with "female" as default value'
|
153
|
+
expect(matcher.description).to eq(message)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#with_i18n_scope' do
|
158
|
+
|
159
|
+
context 'defined as string' do
|
160
|
+
|
161
|
+
before do
|
162
|
+
model.enumerize(:sex, :in => [:male, :female], i18n_scope: 'sex')
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'accepts the right i18n_scope' do
|
166
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('sex')
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'rejects the wrong i18n_scope' do
|
170
|
+
message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: "gender"'
|
171
|
+
expect do
|
172
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('gender')
|
173
|
+
end.to fail_with(message)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'defined as array' do
|
178
|
+
|
179
|
+
before do
|
180
|
+
model.enumerize(:sex, :in => [:male, :female], i18n_scope: ['sex', 'more.sex'])
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'accepts the wrong i18n_scope' do
|
184
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex', 'more.sex'])
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'rejects the wrong i18n_scope' do
|
188
|
+
message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: ["sex"]'
|
189
|
+
expect do
|
190
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex'])
|
191
|
+
end.to fail_with(message)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#with_predicates' do
|
197
|
+
|
198
|
+
it 'accepts when predicates is defined as a boolean' do
|
199
|
+
model.enumerize(:sex, :in => [:male, :female], predicates: true)
|
200
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'accepts when predicates is defined as a hash' do
|
204
|
+
model.enumerize(:sex, :in => [:male, :female], predicates: { prefix: true })
|
205
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(prefix: true)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'rejects when predicates is not defined' do
|
209
|
+
model.enumerize(:sex, :in => [:male, :female])
|
210
|
+
message = 'Expected Model to define enumerize :sex in: "female", "male" predicates: true'
|
211
|
+
expect do
|
212
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
|
213
|
+
end.to fail_with(message)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#with_multiple' do
|
218
|
+
|
219
|
+
it 'accepts when has defined the multiple' do
|
220
|
+
model.enumerize(:sex, :in => [:male, :female], multiple: true)
|
221
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'rejects when has not defined the multiple' do
|
225
|
+
model.enumerize(:sex, :in => [:male, :female])
|
226
|
+
message = 'Expected Model to define enumerize :sex in: "female", "male" multiple: true'
|
227
|
+
expect do
|
228
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true)
|
229
|
+
end.to fail_with(message)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#with_scope' do
|
234
|
+
|
235
|
+
subject do
|
236
|
+
User.new
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'accepts when scope is defined as a boolean' do
|
240
|
+
expect(subject).to enumerize(:sex).in(:male, :female).with_scope(true)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'accepts when scope is defined as a hash' do
|
244
|
+
expect(subject).to enumerize(:role).in(:user, :admin).with_scope(scope: :having_role)
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'rejects when scope is not defined' do
|
248
|
+
message = 'Expected User to define enumerize :account_type in: "basic", "premium" scope: true'
|
249
|
+
expect do
|
250
|
+
expect(subject).to enumerize(:account_type).in(:basic, :premium).with_scope(true)
|
251
|
+
end.to fail_with(message)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'enumerize'
|
3
|
+
require 'rspec/matchers/fail_matchers'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.disable_monkey_patching!
|
7
|
+
config.order = :random
|
8
|
+
Kernel.srand config.seed
|
9
|
+
config.filter_run focus: true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.expect_with :rspec do |expectations|
|
12
|
+
expectations.syntax = :expect
|
13
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
14
|
+
end
|
15
|
+
config.mock_with :rspec do |mocks|
|
16
|
+
mocks.syntax = :expect
|
17
|
+
mocks.verify_partial_doubles = true
|
18
|
+
end
|
19
|
+
if config.files_to_run.one?
|
20
|
+
config.default_formatter = 'doc'
|
21
|
+
end
|
22
|
+
config.warnings = true
|
23
|
+
config.include RSpec::Matchers::FailMatchers
|
24
|
+
end
|
data/test/sequel_test.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sequel'
|
3
|
+
require 'logger'
|
4
|
+
require 'jdbc/sqlite3' if RUBY_PLATFORM == 'java'
|
5
|
+
|
6
|
+
module SequelTest
|
7
|
+
silence_warnings do
|
8
|
+
DB = if RUBY_PLATFORM == 'java'
|
9
|
+
Sequel.connect('jdbc:sqlite::memory:')
|
10
|
+
else
|
11
|
+
Sequel.sqlite
|
12
|
+
end
|
13
|
+
DB.loggers << Logger.new(nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
DB.create_table :users do
|
17
|
+
primary_key :id
|
18
|
+
String :sex
|
19
|
+
String :role
|
20
|
+
String :lambda_role
|
21
|
+
String :name
|
22
|
+
String :interests
|
23
|
+
String :status
|
24
|
+
String :account_type, default: "basic"
|
25
|
+
end
|
26
|
+
|
27
|
+
DB.create_table :documents do
|
28
|
+
primary_key :id
|
29
|
+
String :visibility
|
30
|
+
Time :created_at
|
31
|
+
Time :updated_at
|
32
|
+
end
|
33
|
+
|
34
|
+
class Document < Sequel::Model
|
35
|
+
extend Enumerize
|
36
|
+
enumerize :visibility, :in => [:public, :private, :protected], :scope => true, :default => :public
|
37
|
+
end
|
38
|
+
|
39
|
+
module RoleEnum
|
40
|
+
extend Enumerize
|
41
|
+
enumerize :role, :in => [:user, :admin], :default => :user, scope: :having_role
|
42
|
+
enumerize :lambda_role, :in => [:user, :admin], :default => lambda { :admin }
|
43
|
+
end
|
44
|
+
|
45
|
+
class User < Sequel::Model
|
46
|
+
plugin :serialization, :json, :interests
|
47
|
+
plugin :dirty
|
48
|
+
plugin :defaults_setter
|
49
|
+
plugin :validation_helpers
|
50
|
+
extend Enumerize
|
51
|
+
include RoleEnum
|
52
|
+
|
53
|
+
enumerize :sex, :in => [:male, :female]
|
54
|
+
|
55
|
+
enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true
|
56
|
+
|
57
|
+
enumerize :status, :in => { active: 1, blocked: 2 }, scope: true
|
58
|
+
|
59
|
+
enumerize :account_type, :in => [:basic, :premium]
|
60
|
+
end
|
61
|
+
|
62
|
+
class UniqStatusUser < User
|
63
|
+
def validate
|
64
|
+
super
|
65
|
+
validates_unique :status
|
66
|
+
validates_presence :sex
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe Enumerize::SequelSupport do
|
71
|
+
it 'sets nil if invalid value is passed' do
|
72
|
+
user = User.new
|
73
|
+
user.sex = :invalid
|
74
|
+
user.sex.must_equal nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'saves value' do
|
78
|
+
User.filter.delete
|
79
|
+
user = User.new
|
80
|
+
user.sex = :female
|
81
|
+
user.save
|
82
|
+
user.sex.must_equal 'female'
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'loads value' do
|
86
|
+
User.filter.delete
|
87
|
+
User.create(:sex => :male)
|
88
|
+
store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do
|
89
|
+
user = User.first
|
90
|
+
user.sex.must_equal 'male'
|
91
|
+
user.sex_text.must_equal 'Male'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'has default value' do
|
96
|
+
User.new.role.must_equal 'user'
|
97
|
+
User.new.values[:role].must_equal 'user'
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'does not set default value for not selected attributes' do
|
101
|
+
User.filter.delete
|
102
|
+
User.create(:sex => :male)
|
103
|
+
|
104
|
+
assert_equal [:id], User.select(:id).first.values.keys
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'has default value with lambda' do
|
108
|
+
User.new.lambda_role.must_equal 'admin'
|
109
|
+
User.new.values[:lambda_role].must_equal 'admin'
|
110
|
+
end
|
111
|
+
it 'uses after_initialize callback to set default value' do
|
112
|
+
User.filter.delete
|
113
|
+
User.create(sex: 'male', lambda_role: nil)
|
114
|
+
|
115
|
+
user = User.where(:sex => 'male').first
|
116
|
+
user.lambda_role.must_equal 'admin'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'uses default value from db column' do
|
120
|
+
User.new.account_type.must_equal 'basic'
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'validates inclusion' do
|
124
|
+
user = User.new
|
125
|
+
user.role = 'wrong'
|
126
|
+
user.wont_be :valid?
|
127
|
+
user.errors[:role].must_include 'is not included in the list'
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'validates inclusion on mass assignment' do
|
131
|
+
assert_raises Sequel::ValidationFailed do
|
132
|
+
User.create(role: 'wrong')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it "uses persisted value for validation if it hasn't been set" do
|
137
|
+
user = User.create :sex => :male
|
138
|
+
User[user.id].read_attribute_for_validation(:sex).must_equal 'male'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'is valid with empty string assigned' do
|
142
|
+
user = User.new
|
143
|
+
user.role = ''
|
144
|
+
user.must_be :valid?
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'stores nil when empty string assigned' do
|
148
|
+
user = User.new
|
149
|
+
user.role = ''
|
150
|
+
user.values[:role].must_equal nil
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'supports multiple attributes' do
|
154
|
+
user = User.new
|
155
|
+
user.interests ||= []
|
156
|
+
user.interests.must_be_empty
|
157
|
+
user.interests << "music"
|
158
|
+
user.interests.must_equal %w(music)
|
159
|
+
user.save
|
160
|
+
|
161
|
+
user = User[user.id]
|
162
|
+
user.interests.must_be_instance_of Enumerize::Set
|
163
|
+
user.interests.must_equal %w(music)
|
164
|
+
user.interests << "sports"
|
165
|
+
user.interests.must_equal %w(music sports)
|
166
|
+
|
167
|
+
user.interests = []
|
168
|
+
interests = user.interests
|
169
|
+
interests << "music"
|
170
|
+
interests.must_equal %w(music)
|
171
|
+
interests << "dancing"
|
172
|
+
interests.must_equal %w(music dancing)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'returns invalid multiple value for validation' do
|
176
|
+
user = User.new
|
177
|
+
user.interests << :music
|
178
|
+
user.interests << :invalid
|
179
|
+
values = user.read_attribute_for_validation(:interests)
|
180
|
+
values.must_equal %w(music invalid)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'validates multiple attributes' do
|
184
|
+
user = User.new
|
185
|
+
user.interests << :invalid
|
186
|
+
user.wont_be :valid?
|
187
|
+
|
188
|
+
user.interests = Object.new
|
189
|
+
user.wont_be :valid?
|
190
|
+
|
191
|
+
user.interests = ['music', '']
|
192
|
+
user.must_be :valid?
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'stores custom values for multiple attributes' do
|
196
|
+
User.filter.delete
|
197
|
+
|
198
|
+
klass = Class.new(User)
|
199
|
+
klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true
|
200
|
+
|
201
|
+
user = klass.new
|
202
|
+
user.interests << :music
|
203
|
+
user.interests.must_equal %w(music)
|
204
|
+
user.save
|
205
|
+
|
206
|
+
user = klass[user.id]
|
207
|
+
user.interests.must_equal %w(music)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'adds scope' do
|
211
|
+
User.filter.delete
|
212
|
+
|
213
|
+
user_1 = User.create(status: :active, role: :admin)
|
214
|
+
user_2 = User.create(status: :blocked)
|
215
|
+
|
216
|
+
User.with_status(:active).to_a.must_equal [user_1]
|
217
|
+
User.with_status(:blocked).to_a.must_equal [user_2]
|
218
|
+
User.with_status(:active, :blocked).to_set.must_equal [user_1, user_2].to_set
|
219
|
+
|
220
|
+
User.without_status(:active).to_a.must_equal [user_2]
|
221
|
+
User.without_status(:active, :blocked).to_a.must_equal []
|
222
|
+
|
223
|
+
User.having_role(:admin).to_a.must_equal [user_1]
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'allows either key or value as valid' do
|
227
|
+
user_1 = User.new(status: :active)
|
228
|
+
user_2 = User.new(status: 1)
|
229
|
+
user_3 = User.new(status: '1')
|
230
|
+
|
231
|
+
user_1.status.must_equal 'active'
|
232
|
+
user_2.status.must_equal 'active'
|
233
|
+
user_3.status.must_equal 'active'
|
234
|
+
|
235
|
+
user_1.must_be :valid?
|
236
|
+
user_2.must_be :valid?
|
237
|
+
user_3.must_be :valid?
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'supports defining enumerized attributes on abstract class' do
|
241
|
+
Document.filter.delete
|
242
|
+
|
243
|
+
document = Document.new
|
244
|
+
document.visibility = :protected
|
245
|
+
document.visibility.must_equal 'protected'
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'supports defining enumerized scopes on abstract class' do
|
249
|
+
Document.filter.delete
|
250
|
+
|
251
|
+
document_1 = Document.create(visibility: :public)
|
252
|
+
document_2 = Document.create(visibility: :private)
|
253
|
+
|
254
|
+
Document.with_visibility(:public).to_a.must_equal [document_1]
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'validates uniqueness' do
|
258
|
+
user = User.create(status: :active, sex: "male")
|
259
|
+
|
260
|
+
user = UniqStatusUser.new
|
261
|
+
user.sex = "male"
|
262
|
+
user.status = :active
|
263
|
+
user.valid?.must_equal false
|
264
|
+
|
265
|
+
user.errors[:status].wont_be :empty?
|
266
|
+
end
|
267
|
+
|
268
|
+
it "doesn't update record" do
|
269
|
+
Document.filter.delete
|
270
|
+
|
271
|
+
expected = Time.new(2010, 10, 10)
|
272
|
+
|
273
|
+
document = Document.new
|
274
|
+
document.updated_at = expected
|
275
|
+
document.save
|
276
|
+
|
277
|
+
document = Document.last
|
278
|
+
document.save
|
279
|
+
|
280
|
+
assert_equal expected, document.updated_at
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'changes from dirty should be serialized as scalar values' do
|
284
|
+
user = User.create(:status => :active)
|
285
|
+
user.status = :blocked
|
286
|
+
|
287
|
+
expected = { status: [1, 2] }.to_yaml
|
288
|
+
assert_equal expected, user.column_changes.to_yaml
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|