assignable_values 0.14.0 → 0.16.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +44 -27
- data/CHANGELOG.md +36 -2
- data/Gemfile +1 -1
- data/{gemfiles/Gemfile.2.3 → Gemfile.2.3} +1 -1
- data/{gemfiles/Gemfile.2.3.lock → Gemfile.2.3.lock} +2 -2
- data/{gemfiles/Gemfile.3.2 → Gemfile.3.2} +1 -1
- data/{gemfiles/Gemfile.3.2.lock → Gemfile.3.2.lock} +2 -2
- data/{gemfiles/Gemfile.4.2 → Gemfile.4.2} +1 -1
- data/{gemfiles/Gemfile.4.2.lock → Gemfile.4.2.lock} +2 -2
- data/{gemfiles/Gemfile.5.0 → Gemfile.5.0} +1 -1
- data/{gemfiles/Gemfile.5.0.lock → Gemfile.5.0.lock} +2 -2
- data/{gemfiles/Gemfile.5.1 → Gemfile.5.1} +1 -1
- data/{gemfiles/Gemfile.5.1.lock → Gemfile.5.1.lock} +3 -3
- data/{gemfiles/Gemfile.5.1.pg → Gemfile.5.1.pg} +1 -1
- data/{gemfiles/Gemfile.5.1.pg.lock → Gemfile.5.1.pg.lock} +2 -2
- data/Gemfile.6.0.pg +16 -0
- data/Gemfile.6.0.pg.lock +68 -0
- data/Gemfile.lock +1 -1
- data/README.md +24 -14
- data/lib/assignable_values.rb +1 -0
- data/lib/assignable_values/active_record/restriction/base.rb +30 -10
- data/lib/assignable_values/active_record/restriction/scalar_attribute.rb +33 -8
- data/lib/assignable_values/humanizable_string.rb +2 -1
- data/lib/assignable_values/version.rb +1 -1
- data/spec/assignable_values/active_record_spec.rb +249 -56
- data/spec/support/database.rb +1 -1
- data/spec/support/i18n.yml +7 -1
- data/spec/support/models.rb +3 -3
- metadata +17 -16
data/lib/assignable_values.rb
CHANGED
@@ -48,25 +48,31 @@ module AssignableValues
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def assignable_values(record, options = {})
|
51
|
-
|
51
|
+
additional_assignable_values = []
|
52
52
|
current_values = assignable_values_from_record_or_delegate(record)
|
53
53
|
|
54
54
|
if options.fetch(:include_old_value, true) && has_previously_saved_value?(record)
|
55
55
|
old_value = previously_saved_value(record)
|
56
56
|
if @options[:multiple]
|
57
57
|
if old_value.is_a?(Array)
|
58
|
-
|
58
|
+
additional_assignable_values |= old_value
|
59
59
|
end
|
60
60
|
elsif !old_value.blank? && !current_values.include?(old_value)
|
61
|
-
|
61
|
+
additional_assignable_values << old_value
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
assignable_values += current_values
|
66
65
|
if options[:decorate]
|
67
|
-
|
66
|
+
current_values = decorate_values(current_values)
|
67
|
+
additional_assignable_values = decorate_values(additional_assignable_values)
|
68
|
+
end
|
69
|
+
|
70
|
+
if additional_assignable_values.present?
|
71
|
+
# will not keep current_values scoped
|
72
|
+
additional_assignable_values + current_values
|
73
|
+
else
|
74
|
+
current_values
|
68
75
|
end
|
69
|
-
assignable_values
|
70
76
|
end
|
71
77
|
|
72
78
|
private
|
@@ -94,7 +100,21 @@ module AssignableValues
|
|
94
100
|
def assignable_single_value?(record, value)
|
95
101
|
(has_previously_saved_value?(record) && value == previously_saved_value(record)) ||
|
96
102
|
(value.blank? && allow_blank?(record)) ||
|
97
|
-
|
103
|
+
included_in_assignable_values?(record, value)
|
104
|
+
end
|
105
|
+
|
106
|
+
def included_in_assignable_values?(record, value)
|
107
|
+
values_or_scope = assignable_values(record, :include_old_value => false)
|
108
|
+
|
109
|
+
if is_scope?(values_or_scope)
|
110
|
+
values_or_scope.exists?(value.id)
|
111
|
+
else
|
112
|
+
values_or_scope.include?(value)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def is_scope?(object)
|
117
|
+
object.respond_to?(:scoped) || object.respond_to?(:all)
|
98
118
|
end
|
99
119
|
|
100
120
|
def assignable_multi_value?(record, value)
|
@@ -217,9 +237,9 @@ module AssignableValues
|
|
217
237
|
|
218
238
|
def assignable_values_from_record_or_delegate(record)
|
219
239
|
if delegate?
|
220
|
-
assignable_values_from_delegate(record)
|
240
|
+
assignable_values_from_delegate(record)
|
221
241
|
else
|
222
|
-
record.instance_exec(&@values)
|
242
|
+
record.instance_exec(&@values)
|
223
243
|
end
|
224
244
|
end
|
225
245
|
|
@@ -240,7 +260,7 @@ module AssignableValues
|
|
240
260
|
delegate = delegate(record)
|
241
261
|
delegate.present? or raise DelegateUnavailable, "Cannot query a nil delegate for assignable values"
|
242
262
|
delegate_query_method = :"assignable_#{model.name.underscore.gsub('/', '_')}_#{property.to_s.pluralize}"
|
243
|
-
args = delegate.method(delegate_query_method).arity ==
|
263
|
+
args = delegate.method(delegate_query_method).arity == 0 ? [] : [record]
|
244
264
|
delegate.send(delegate_query_method, *args)
|
245
265
|
end
|
246
266
|
|
@@ -7,7 +7,7 @@ module AssignableValues
|
|
7
7
|
super
|
8
8
|
define_humanized_value_instance_method
|
9
9
|
define_humanized_value_class_method
|
10
|
-
|
10
|
+
define_humanized_assignable_values_instance_method
|
11
11
|
end
|
12
12
|
|
13
13
|
def humanized_value(value)
|
@@ -17,8 +17,8 @@ module AssignableValues
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
values = assignable_values(record)
|
20
|
+
def humanized_assignable_values(record, options = {})
|
21
|
+
values = assignable_values(record, options)
|
22
22
|
values.collect do |value|
|
23
23
|
HumanizedValue.new(value, humanized_value(value))
|
24
24
|
end
|
@@ -37,7 +37,7 @@ module AssignableValues
|
|
37
37
|
def define_humanized_value_class_method
|
38
38
|
restriction = self
|
39
39
|
enhance_model_singleton do
|
40
|
-
define_method :"humanized_#{restriction.property}" do |given_value|
|
40
|
+
define_method :"humanized_#{restriction.property.to_s.singularize}" do |given_value|
|
41
41
|
restriction.humanized_value(given_value)
|
42
42
|
end
|
43
43
|
end
|
@@ -45,20 +45,45 @@ module AssignableValues
|
|
45
45
|
|
46
46
|
def define_humanized_value_instance_method
|
47
47
|
restriction = self
|
48
|
+
multiple = @options[:multiple]
|
48
49
|
enhance_model do
|
49
|
-
define_method :"humanized_#{restriction.property}" do |*args|
|
50
|
+
define_method :"humanized_#{restriction.property.to_s.singularize}" do |*args|
|
51
|
+
if args.size > 1 || (multiple && args.size == 0)
|
52
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for #{multiple ? '1' : '0..1'})")
|
53
|
+
end
|
50
54
|
given_value = args[0]
|
51
55
|
value = given_value || send(restriction.property)
|
52
56
|
restriction.humanized_value(value)
|
53
57
|
end
|
58
|
+
|
59
|
+
if multiple
|
60
|
+
define_method :"humanized_#{restriction.property}" do
|
61
|
+
values = send(restriction.property)
|
62
|
+
if values.respond_to?(:map)
|
63
|
+
values.map do |value|
|
64
|
+
restriction.humanized_value(value)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
values
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
54
71
|
end
|
55
72
|
end
|
56
73
|
|
57
|
-
def
|
74
|
+
def define_humanized_assignable_values_instance_method
|
58
75
|
restriction = self
|
76
|
+
multiple = @options[:multiple]
|
59
77
|
enhance_model do
|
60
|
-
define_method :"
|
61
|
-
restriction.
|
78
|
+
define_method :"humanized_assignable_#{restriction.property.to_s.pluralize}" do |*args|
|
79
|
+
restriction.humanized_assignable_values(self, *args)
|
80
|
+
end
|
81
|
+
|
82
|
+
unless multiple
|
83
|
+
define_method :"humanized_#{restriction.property.to_s.pluralize}" do
|
84
|
+
ActiveSupport::Deprecation.warn("humanized_<value>s is deprecated, use humanized_assignable_<value>s instead", caller)
|
85
|
+
restriction.humanized_assignable_values(self)
|
86
|
+
end
|
62
87
|
end
|
63
88
|
end
|
64
89
|
end
|
@@ -1,6 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
|
+
def save_without_validation(record)
|
5
|
+
if ActiveRecord::VERSION::MAJOR < 3
|
6
|
+
record.save(false)
|
7
|
+
else
|
8
|
+
record.save(:validate => false)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
describe AssignableValues::ActiveRecord do
|
5
13
|
|
6
14
|
describe '.assignable_values' do
|
@@ -17,24 +25,30 @@ describe AssignableValues::ActiveRecord do
|
|
17
25
|
|
18
26
|
before :each do
|
19
27
|
@klass = Song.disposable_copy do
|
20
|
-
assignable_values_for :
|
28
|
+
assignable_values_for :virtual_sub_genre do
|
29
|
+
%w[pop rock]
|
30
|
+
end
|
31
|
+
|
32
|
+
assignable_values_for :virtual_multi_genres, :multiple => true, :allow_blank => true do
|
21
33
|
%w[pop rock]
|
22
34
|
end
|
23
35
|
end
|
24
36
|
end
|
25
37
|
|
26
38
|
it 'should validate that the attribute is allowed' do
|
27
|
-
@klass.new(:
|
28
|
-
@klass.new(:
|
39
|
+
@klass.new(:virtual_sub_genre => 'pop').should be_valid
|
40
|
+
@klass.new(:virtual_sub_genre => 'disallowed value').should_not be_valid
|
29
41
|
end
|
30
42
|
|
31
43
|
it 'should not allow nil for the attribute value' do
|
32
|
-
@klass.new(:
|
44
|
+
@klass.new(:virtual_sub_genre => nil).should_not be_valid
|
33
45
|
end
|
34
46
|
|
35
47
|
it 'should generate a method returning the humanized value' do
|
36
|
-
song = @klass.new(:
|
37
|
-
song.
|
48
|
+
song = @klass.new(:virtual_sub_genre => 'pop')
|
49
|
+
song.humanized_virtual_sub_genre.should == 'Pop music'
|
50
|
+
song.humanized_virtual_sub_genre('rock').should == 'Rock music'
|
51
|
+
song.humanized_virtual_multi_genre('rock').should == 'Rock music'
|
38
52
|
end
|
39
53
|
|
40
54
|
end
|
@@ -45,21 +59,21 @@ describe AssignableValues::ActiveRecord do
|
|
45
59
|
|
46
60
|
before :each do
|
47
61
|
@klass = Song.disposable_copy do
|
48
|
-
assignable_values_for :
|
62
|
+
assignable_values_for :virtual_multi_genres, :multiple => true do
|
49
63
|
%w[pop rock]
|
50
64
|
end
|
51
65
|
end
|
52
66
|
end
|
53
67
|
|
54
68
|
it 'should validate that the attribute is a subset' do
|
55
|
-
@klass.new(:
|
56
|
-
@klass.new(:
|
57
|
-
@klass.new(:
|
69
|
+
@klass.new(:virtual_multi_genres => ['pop']).should be_valid
|
70
|
+
@klass.new(:virtual_multi_genres => ['pop', 'rock']).should be_valid
|
71
|
+
@klass.new(:virtual_multi_genres => ['pop', 'disallowed value']).should_not be_valid
|
58
72
|
end
|
59
73
|
|
60
74
|
it 'should not allow nil or [] for allow_blank: false' do
|
61
|
-
@klass.new(:
|
62
|
-
@klass.new(:
|
75
|
+
@klass.new(:virtual_multi_genres => nil).should_not be_valid
|
76
|
+
@klass.new(:virtual_multi_genres => []).should_not be_valid
|
63
77
|
end
|
64
78
|
|
65
79
|
end
|
@@ -68,15 +82,15 @@ describe AssignableValues::ActiveRecord do
|
|
68
82
|
|
69
83
|
before :each do
|
70
84
|
@klass = Song.disposable_copy do
|
71
|
-
assignable_values_for :
|
85
|
+
assignable_values_for :virtual_multi_genres, :multiple => true, :allow_blank => true do
|
72
86
|
%w[pop rock]
|
73
87
|
end
|
74
88
|
end
|
75
89
|
end
|
76
90
|
|
77
91
|
it 'should allow nil or [] for allow_blank: false' do
|
78
|
-
@klass.new(:
|
79
|
-
@klass.new(:
|
92
|
+
@klass.new(:virtual_multi_genres => nil).should be_valid
|
93
|
+
@klass.new(:virtual_multi_genres => []).should be_valid
|
80
94
|
end
|
81
95
|
|
82
96
|
end
|
@@ -92,6 +106,10 @@ describe AssignableValues::ActiveRecord do
|
|
92
106
|
assignable_values_for :genre do
|
93
107
|
%w[pop rock]
|
94
108
|
end
|
109
|
+
|
110
|
+
assignable_values_for :virtual_multi_genres, :multiple => true, :allow_blank => true do
|
111
|
+
%w[pop rock]
|
112
|
+
end
|
95
113
|
end
|
96
114
|
end
|
97
115
|
|
@@ -153,6 +171,31 @@ describe AssignableValues::ActiveRecord do
|
|
153
171
|
@klass.humanized_genre('rock').should == 'Rock music'
|
154
172
|
end
|
155
173
|
|
174
|
+
context 'for multiple: true' do
|
175
|
+
it 'should raise when trying to humanize a value without an argument' do
|
176
|
+
song = @klass.new
|
177
|
+
proc { song.humanized_virtual_multi_genre }.should raise_error(ArgumentError)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should generate an instance method to retrieve the humanization of any given value' do
|
181
|
+
song = @klass.new(:genre => 'pop')
|
182
|
+
song.humanized_virtual_multi_genre('rock').should == 'Rock music'
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should generate a class method to retrieve the humanization of any given value' do
|
186
|
+
@klass.humanized_virtual_multi_genre('rock').should == 'Rock music'
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should generate an instance method to retrieve the humanizations of all current values' do
|
190
|
+
song = @klass.new
|
191
|
+
song.virtual_multi_genres = nil
|
192
|
+
song.humanized_virtual_multi_genres.should == nil
|
193
|
+
song.virtual_multi_genres = []
|
194
|
+
song.humanized_virtual_multi_genres.should == []
|
195
|
+
song.virtual_multi_genres = ['pop', 'rock']
|
196
|
+
song.humanized_virtual_multi_genres.should == ['Pop music', 'Rock music']
|
197
|
+
end
|
198
|
+
end
|
156
199
|
end
|
157
200
|
|
158
201
|
context 'if the :allow_blank option is set to true' do
|
@@ -220,11 +263,11 @@ describe AssignableValues::ActiveRecord do
|
|
220
263
|
context 'if the :message option is set to a string' do
|
221
264
|
|
222
265
|
before :each do
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
266
|
+
@klass = Song.disposable_copy do
|
267
|
+
assignable_values_for :genre, :message => 'should be something different' do
|
268
|
+
%w[pop rock]
|
269
|
+
end
|
270
|
+
end
|
228
271
|
end
|
229
272
|
|
230
273
|
it 'should use this string as a custom error message' do
|
@@ -245,43 +288,39 @@ describe AssignableValues::ActiveRecord do
|
|
245
288
|
|
246
289
|
before :each do
|
247
290
|
@klass = Song.disposable_copy do
|
248
|
-
assignable_values_for :
|
291
|
+
assignable_values_for :multi_genres, :multiple => true do
|
249
292
|
%w[pop rock]
|
250
293
|
end
|
251
294
|
end
|
252
295
|
end
|
253
296
|
|
254
297
|
it 'should validate that the attribute is allowed' do
|
255
|
-
@klass.new(:
|
256
|
-
@klass.new(:
|
257
|
-
@klass.new(:
|
298
|
+
@klass.new(:multi_genres => ['pop']).should be_valid
|
299
|
+
@klass.new(:multi_genres => ['pop', 'rock']).should be_valid
|
300
|
+
@klass.new(:multi_genres => ['pop', 'invalid value']).should_not be_valid
|
258
301
|
end
|
259
302
|
|
260
303
|
it 'should not allow a scalar attribute' do
|
261
|
-
@klass.new(:
|
304
|
+
@klass.new(:multi_genres => 'pop').should_not be_valid
|
262
305
|
end
|
263
306
|
|
264
307
|
it 'should not allow nil or [] for the attribute value' do
|
265
|
-
@klass.new(:
|
266
|
-
@klass.new(:
|
308
|
+
@klass.new(:multi_genres => nil).should_not be_valid
|
309
|
+
@klass.new(:multi_genres => []).should_not be_valid
|
267
310
|
end
|
268
311
|
|
269
312
|
it 'should allow a subset of previously saved values even if that value is no longer allowed' do
|
270
|
-
record = @klass.create!(:
|
271
|
-
record.
|
272
|
-
|
273
|
-
record.save(false)
|
274
|
-
else
|
275
|
-
record.save(:validate => false) # update without validations for the sake of this test
|
276
|
-
end
|
313
|
+
record = @klass.create!(:multi_genres => ['pop'])
|
314
|
+
record.multi_genres = ['pretend', 'previously', 'valid', 'value']
|
315
|
+
save_without_validation(record) # update without validation for the sake of this test
|
277
316
|
record.reload.should be_valid
|
278
|
-
record.
|
317
|
+
record.multi_genres = ['valid', 'previously', 'pop']
|
279
318
|
record.should be_valid
|
280
319
|
end
|
281
320
|
|
282
321
|
it 'should allow a previously saved, blank value even if that value is no longer allowed' do
|
283
|
-
record = @klass.create!(:
|
284
|
-
@klass.update_all(:
|
322
|
+
record = @klass.create!(:multi_genres => ['pop'])
|
323
|
+
@klass.update_all(:multi_genres => []) # update without validations for the sake of this test
|
285
324
|
record.reload.should be_valid
|
286
325
|
end
|
287
326
|
|
@@ -291,18 +330,18 @@ describe AssignableValues::ActiveRecord do
|
|
291
330
|
|
292
331
|
before :each do
|
293
332
|
@klass = Song.disposable_copy do
|
294
|
-
assignable_values_for :
|
333
|
+
assignable_values_for :multi_genres, :multiple => true, :allow_blank => true do
|
295
334
|
%w[pop rock]
|
296
335
|
end
|
297
336
|
end
|
298
337
|
end
|
299
338
|
|
300
339
|
it 'should allow nil for the attribute value' do
|
301
|
-
@klass.new(:
|
340
|
+
@klass.new(:multi_genres => nil).should be_valid
|
302
341
|
end
|
303
342
|
|
304
343
|
it 'should allow an empty array as value' do
|
305
|
-
@klass.new(:
|
344
|
+
@klass.new(:multi_genres => []).should be_valid
|
306
345
|
end
|
307
346
|
|
308
347
|
end
|
@@ -409,7 +448,7 @@ describe AssignableValues::ActiveRecord do
|
|
409
448
|
record.should be_valid
|
410
449
|
end
|
411
450
|
|
412
|
-
it '
|
451
|
+
it 'should not allow nil for an association (the "previously saved value") if the record is new' do
|
413
452
|
allowed_association = Artist.create!
|
414
453
|
klass = Song.disposable_copy
|
415
454
|
record = klass.new(:artist => nil)
|
@@ -471,6 +510,47 @@ describe AssignableValues::ActiveRecord do
|
|
471
510
|
record.valid?
|
472
511
|
end
|
473
512
|
|
513
|
+
it 'should not load all records to memory when assignable values are scoped' do
|
514
|
+
unless ::ActiveRecord::VERSION::MAJOR < 3 # somehow rails 2 still initializes Objects during the scope.exists?-call
|
515
|
+
initialized_artists_count = 0
|
516
|
+
MyArtist = Artist.disposable_copy
|
517
|
+
|
518
|
+
MyArtist.class_eval do
|
519
|
+
after_initialize :increase_initialized_count
|
520
|
+
|
521
|
+
define_method :increase_initialized_count do
|
522
|
+
initialized_artists_count += 1
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
klass = Song.disposable_copy
|
527
|
+
|
528
|
+
klass.class_eval do
|
529
|
+
assignable_values_for :artist do
|
530
|
+
if ::ActiveRecord::VERSION::MAJOR < 4
|
531
|
+
MyArtist.scoped
|
532
|
+
else
|
533
|
+
MyArtist.all
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
artist = MyArtist.create!
|
539
|
+
initialized_artists_count.should == 1
|
540
|
+
|
541
|
+
song = klass.new(:artist => artist)
|
542
|
+
|
543
|
+
song.valid?
|
544
|
+
initialized_artists_count.should == 1
|
545
|
+
|
546
|
+
song.assignable_artists
|
547
|
+
initialized_artists_count.should == 1
|
548
|
+
|
549
|
+
song.assignable_artists.to_a
|
550
|
+
initialized_artists_count.should == 2
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
474
554
|
end
|
475
555
|
|
476
556
|
context 'when delegating using the :through option' do
|
@@ -479,7 +559,11 @@ describe AssignableValues::ActiveRecord do
|
|
479
559
|
klass = Song.disposable_copy do
|
480
560
|
assignable_values_for :genre, :through => :delegate
|
481
561
|
def delegate
|
482
|
-
|
562
|
+
Class.new do
|
563
|
+
def assignable_song_genres
|
564
|
+
%w[pop rock]
|
565
|
+
end
|
566
|
+
end.new
|
483
567
|
end
|
484
568
|
end
|
485
569
|
klass.new(:genre => 'pop').should be_valid
|
@@ -490,9 +574,14 @@ describe AssignableValues::ActiveRecord do
|
|
490
574
|
klass = Song.disposable_copy do
|
491
575
|
assignable_values_for :genre, :through => lambda { delegate }
|
492
576
|
def delegate
|
493
|
-
|
577
|
+
Class.new do
|
578
|
+
def assignable_song_genres
|
579
|
+
%w[pop rock]
|
580
|
+
end
|
581
|
+
end.new
|
494
582
|
end
|
495
583
|
end
|
584
|
+
|
496
585
|
klass.new(:genre => 'pop').should be_valid
|
497
586
|
klass.new(:genre => 'disallowed value').should_not be_valid
|
498
587
|
end
|
@@ -501,7 +590,11 @@ describe AssignableValues::ActiveRecord do
|
|
501
590
|
klass = Recording::Vinyl.disposable_copy do
|
502
591
|
assignable_values_for :year, :through => :delegate
|
503
592
|
def delegate
|
504
|
-
|
593
|
+
Class.new do
|
594
|
+
def assignable_recording_vinyl_years
|
595
|
+
[1977, 1980, 1983]
|
596
|
+
end
|
597
|
+
end.new
|
505
598
|
end
|
506
599
|
end
|
507
600
|
klass.new.assignable_years.should == [1977, 1980, 1983]
|
@@ -678,7 +771,7 @@ describe AssignableValues::ActiveRecord do
|
|
678
771
|
klass.new.assignable_genres.should == %w[pop rock]
|
679
772
|
end
|
680
773
|
|
681
|
-
it 'should
|
774
|
+
it 'should work with ranges' do
|
682
775
|
klass = Song.disposable_copy do
|
683
776
|
assignable_values_for :year do
|
684
777
|
1999..2001
|
@@ -704,10 +797,28 @@ describe AssignableValues::ActiveRecord do
|
|
704
797
|
assignable_values_for :genre do
|
705
798
|
%w[pop rock]
|
706
799
|
end
|
800
|
+
|
801
|
+
assignable_values_for :multi_genres, :multiple => true do
|
802
|
+
%w[pop rock]
|
803
|
+
end
|
707
804
|
end
|
708
|
-
record = klass.create!(:genre => 'pop')
|
805
|
+
record = klass.create!(:genre => 'pop', :multi_genres => ['rock'])
|
709
806
|
klass.update_all(:genre => 'ballad') # update without validation for the sake of this test
|
710
807
|
record.reload.assignable_genres.should == %w[ballad pop rock]
|
808
|
+
|
809
|
+
humanized_genres = record.humanized_assignable_genres
|
810
|
+
humanized_genres.collect(&:value).should == %w[ballad pop rock]
|
811
|
+
humanized_genres.collect(&:humanized).should == ['Ballad', 'Pop music', 'Rock music']
|
812
|
+
humanized_genres.collect(&:to_s).should == ['Ballad', 'Pop music', 'Rock music']
|
813
|
+
|
814
|
+
record.multi_genres = %w[ballad classic]
|
815
|
+
save_without_validation(record) # update without validation for the sake of this test
|
816
|
+
record.reload.multi_genres.should == %w[ballad classic]
|
817
|
+
|
818
|
+
humanized_multi_genres = record.humanized_assignable_multi_genres
|
819
|
+
humanized_multi_genres.collect(&:value).should == %w[ballad classic pop rock]
|
820
|
+
humanized_multi_genres.collect(&:humanized).should == ['Ballad', 'Classic', 'Pop music', 'Rock music']
|
821
|
+
humanized_multi_genres.collect(&:to_s).should == ['Ballad', 'Classic', 'Pop music', 'Rock music']
|
711
822
|
end
|
712
823
|
|
713
824
|
it 'should not prepend a previously saved value to the top of the list if it is still allowed (bugfix)' do
|
@@ -747,10 +858,28 @@ describe AssignableValues::ActiveRecord do
|
|
747
858
|
assignable_values_for :genre do
|
748
859
|
%w[pop rock]
|
749
860
|
end
|
861
|
+
|
862
|
+
assignable_values_for :multi_genres, :multiple => true do
|
863
|
+
%w[pop rock]
|
864
|
+
end
|
750
865
|
end
|
751
|
-
record = klass.create!(:genre => 'pop')
|
866
|
+
record = klass.create!(:genre => 'pop', :multi_genres => ['rock'])
|
752
867
|
klass.update_all(:genre => 'ballad') # update without validation for the sake of this test
|
753
868
|
record.reload.assignable_genres(:include_old_value => false).should == %w[pop rock]
|
869
|
+
|
870
|
+
humanized_genres = record.humanized_assignable_genres(:include_old_value => false)
|
871
|
+
humanized_genres.collect(&:value).should == %w[pop rock]
|
872
|
+
humanized_genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
873
|
+
humanized_genres.collect(&:to_s).should == ['Pop music', 'Rock music']
|
874
|
+
|
875
|
+
record.multi_genres = %w[ballad classic]
|
876
|
+
save_without_validation(record) # update without validation for the sake of this test
|
877
|
+
record.reload.multi_genres.should == %w[ballad classic]
|
878
|
+
|
879
|
+
humanized_multi_genres = record.humanized_assignable_multi_genres(:include_old_value => false)
|
880
|
+
humanized_multi_genres.collect(&:value).should == %w[pop rock]
|
881
|
+
humanized_multi_genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
882
|
+
humanized_multi_genres.collect(&:to_s).should == ['Pop music', 'Rock music']
|
754
883
|
end
|
755
884
|
|
756
885
|
it 'should allow omitting a previously saved association' do
|
@@ -791,11 +920,18 @@ describe AssignableValues::ActiveRecord do
|
|
791
920
|
assignable_values_for :genre do
|
792
921
|
%w[pop rock]
|
793
922
|
end
|
923
|
+
|
924
|
+
assignable_values_for :multi_genres, :multiple => true do
|
925
|
+
%w[pop rock]
|
926
|
+
end
|
794
927
|
end
|
795
|
-
genres = klass.new.
|
928
|
+
genres = klass.new.humanized_assignable_genres
|
796
929
|
genres.collect(&:value).should == ['pop', 'rock']
|
797
930
|
genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
798
931
|
genres.collect(&:to_s).should == ['Pop music', 'Rock music']
|
932
|
+
|
933
|
+
multi_genres = klass.new.humanized_assignable_multi_genres
|
934
|
+
multi_genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
799
935
|
end
|
800
936
|
|
801
937
|
it 'should use String#humanize as a default translation' do
|
@@ -804,7 +940,7 @@ describe AssignableValues::ActiveRecord do
|
|
804
940
|
%w[electronic]
|
805
941
|
end
|
806
942
|
end
|
807
|
-
klass.new.
|
943
|
+
klass.new.humanized_assignable_genres.collect(&:humanized).should == ['Electronic']
|
808
944
|
end
|
809
945
|
|
810
946
|
it 'should allow to define humanizations for values that are not strings' do
|
@@ -813,7 +949,7 @@ describe AssignableValues::ActiveRecord do
|
|
813
949
|
[1977, 1980, 1983]
|
814
950
|
end
|
815
951
|
end
|
816
|
-
years = klass.new.
|
952
|
+
years = klass.new.humanized_assignable_years
|
817
953
|
years.collect(&:value).should == [1977, 1980, 1983]
|
818
954
|
years.collect(&:humanized).should == ['The year a new hope was born', 'The year the Empire stroke back', 'The year the Jedi returned']
|
819
955
|
end
|
@@ -824,18 +960,30 @@ describe AssignableValues::ActiveRecord do
|
|
824
960
|
[1977, 1980, 1983]
|
825
961
|
end
|
826
962
|
end
|
827
|
-
years = klass.new.
|
963
|
+
years = klass.new.humanized_assignable_years
|
828
964
|
years.collect(&:humanized).should == ['The year a new hope was born', 'The year the Empire stroke back', 'The year the Jedi returned']
|
829
965
|
end
|
830
966
|
|
831
967
|
context 'legacy methods for API compatibility' do
|
832
968
|
|
969
|
+
it 'should define a method that return pairs of values and their humanization' do
|
970
|
+
klass = Song.disposable_copy do
|
971
|
+
assignable_values_for :genre do
|
972
|
+
%w[pop rock]
|
973
|
+
end
|
974
|
+
end
|
975
|
+
ActiveSupport::Deprecation.should_receive(:warn)
|
976
|
+
genres = klass.new.humanized_genres
|
977
|
+
genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
978
|
+
end
|
979
|
+
|
833
980
|
it "should define a method #humanized on assignable string values, which return up the value's' translation" do
|
834
981
|
klass = Song.disposable_copy do
|
835
982
|
assignable_values_for :genre do
|
836
983
|
%w[pop rock]
|
837
984
|
end
|
838
985
|
end
|
986
|
+
ActiveSupport::Deprecation.should_receive(:warn).at_least(:once)
|
839
987
|
klass.new.assignable_genres.collect(&:humanized).should == ['Pop music', 'Rock music']
|
840
988
|
end
|
841
989
|
|
@@ -872,7 +1020,7 @@ describe AssignableValues::ActiveRecord do
|
|
872
1020
|
delegate = Object.new
|
873
1021
|
def delegate.assignable_song_genres(record)
|
874
1022
|
record_received(record)
|
875
|
-
|
1023
|
+
%w[pop rock]
|
876
1024
|
end
|
877
1025
|
klass = Song.disposable_copy do
|
878
1026
|
assignable_values_for :genre, :through => :delegate
|
@@ -885,6 +1033,55 @@ describe AssignableValues::ActiveRecord do
|
|
885
1033
|
record.assignable_genres.should == %w[pop rock]
|
886
1034
|
end
|
887
1035
|
|
1036
|
+
it "should call the given method on the delegate if the delegate's query method takes no arguments" do
|
1037
|
+
delegate = Object.new
|
1038
|
+
def delegate.assignable_song_genres
|
1039
|
+
no_record_received
|
1040
|
+
%w[pop rock]
|
1041
|
+
end
|
1042
|
+
klass = Song.disposable_copy do
|
1043
|
+
assignable_values_for :genre, :through => :delegate
|
1044
|
+
define_method :delegate do
|
1045
|
+
delegate
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
record = klass.new
|
1049
|
+
delegate.should_receive(:no_record_received)
|
1050
|
+
record.assignable_genres.should == %w[pop rock]
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
it "should pass the record to the given method if the delegate's query method takes variable arguments" do
|
1054
|
+
delegate = Object.new
|
1055
|
+
def delegate.assignable_song_genres(*records)
|
1056
|
+
record_received(*records)
|
1057
|
+
%w[pop rock]
|
1058
|
+
end
|
1059
|
+
klass = Song.disposable_copy do
|
1060
|
+
assignable_values_for :genre, :through => :delegate
|
1061
|
+
define_method :delegate do
|
1062
|
+
delegate
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
record = klass.new
|
1066
|
+
delegate.should_receive(:record_received).with(record)
|
1067
|
+
record.assignable_genres.should == %w[pop rock]
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it "should raise an error if the delegate's query method takes more than one argument" do
|
1071
|
+
delegate = Object.new
|
1072
|
+
def delegate.assignable_song_genres(record, other_arg)
|
1073
|
+
%w[pop rock]
|
1074
|
+
end
|
1075
|
+
klass = Song.disposable_copy do
|
1076
|
+
assignable_values_for :genre, :through => :delegate
|
1077
|
+
define_method :delegate do
|
1078
|
+
delegate
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
record = klass.new
|
1082
|
+
expect{record.assignable_genres}.to raise_error(ArgumentError)
|
1083
|
+
end
|
1084
|
+
|
888
1085
|
it 'should raise an error if the given method returns nil' do
|
889
1086
|
klass = Song.disposable_copy do
|
890
1087
|
assignable_values_for :genre, :through => :delegate
|
@@ -894,11 +1091,7 @@ describe AssignableValues::ActiveRecord do
|
|
894
1091
|
end
|
895
1092
|
expect { klass.new.assignable_genres }.to raise_error(AssignableValues::DelegateUnavailable)
|
896
1093
|
end
|
897
|
-
|
898
1094
|
end
|
899
|
-
|
900
1095
|
end
|
901
|
-
|
902
1096
|
end
|
903
|
-
|
904
1097
|
end
|