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.
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
+ require 'active_support/deprecation'
2
3
  require 'assignable_values/errors'
3
4
  require 'assignable_values/active_record'
4
5
  require 'assignable_values/active_record/restriction/base'
@@ -48,25 +48,31 @@ module AssignableValues
48
48
  end
49
49
 
50
50
  def assignable_values(record, options = {})
51
- assignable_values = []
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
- assignable_values |= old_value
58
+ additional_assignable_values |= old_value
59
59
  end
60
60
  elsif !old_value.blank? && !current_values.include?(old_value)
61
- assignable_values << old_value
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
- assignable_values = decorate_values(assignable_values)
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
- assignable_values(record, :include_old_value => false).include?(value)
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).to_a
240
+ assignable_values_from_delegate(record)
221
241
  else
222
- record.instance_exec(&@values).to_a
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 == 1 ? [record] : []
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
- define_humanized_values_instance_method
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 humanized_values(record)
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 define_humanized_values_instance_method
74
+ def define_humanized_assignable_values_instance_method
58
75
  restriction = self
76
+ multiple = @options[:multiple]
59
77
  enhance_model do
60
- define_method :"humanized_#{restriction.property.to_s.pluralize}" do
61
- restriction.humanized_values(self)
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
@@ -8,7 +8,8 @@ class HumanizableString < String
8
8
  end
9
9
 
10
10
  def humanized
11
+ ActiveSupport::Deprecation.warn("assignable_<value>.humanized is deprecated, use humanized_assignable_<value>s.humanized instead", caller)
11
12
  @humanization
12
13
  end
13
14
 
14
- end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module AssignableValues
2
- VERSION = '0.14.0'
2
+ VERSION = '0.16.2'
3
3
  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 :sub_genre do
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(:sub_genre => 'pop').should be_valid
28
- @klass.new(:sub_genre => 'disallowed value').should_not be_valid
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(:sub_genre => nil).should_not be_valid
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(:sub_genre => 'pop')
37
- song.humanized_sub_genre.should == 'Pop music'
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 :sub_genres,:multiple => true do
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(:sub_genres => ['pop']).should be_valid
56
- @klass.new(:sub_genres => ['pop', 'rock']).should be_valid
57
- @klass.new(:sub_genres => ['pop', 'disallowed value']).should_not be_valid
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(:sub_genres => nil).should_not be_valid
62
- @klass.new(:sub_genres => []).should_not be_valid
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 :sub_genres, :multiple => true, :allow_blank => true do
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(:sub_genres => nil).should be_valid
79
- @klass.new(:sub_genres => []).should be_valid
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
- @klass = Song.disposable_copy do
224
- assignable_values_for :genre, :message => 'should be something different' do
225
- %w[pop rock]
226
- end
227
- end
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 :genres, :multiple => true do
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(:genres => ['pop']).should be_valid
256
- @klass.new(:genres => ['pop', 'rock']).should be_valid
257
- @klass.new(:genres => ['pop', 'invalid value']).should_not be_valid
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(:genres => 'pop').should_not be_valid
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(:genres => nil).should_not be_valid
266
- @klass.new(:genres => []).should_not be_valid
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!(:genres => ['pop'])
271
- record.genres = ['pretend', 'previously', 'valid', 'value']
272
- if ActiveRecord::VERSION::MAJOR < 3
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.genres = ['valid', 'previously', 'pop']
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!(:genres => ['pop'])
284
- @klass.update_all(:genres => []) # update without validations for the sake of this test
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 :genres, :multiple => true, :allow_blank => true do
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(:genres => nil).should be_valid
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(:genres => []).should be_valid
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 'sould not allow nil for an association (the "previously saved value") if the record is new' do
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
- OpenStruct.new(:assignable_song_genres => %w[pop rock])
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
- OpenStruct.new(:assignable_song_genres => %w[pop rock])
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
- OpenStruct.new(:assignable_recording_vinyl_years => [1977, 1980, 1983])
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 call #to_a on the list of assignable values, allowing ranges and scopes to be passed as allowed value descriptors' do
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.humanized_genres
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.humanized_genres.collect(&:humanized).should == ['Electronic']
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.humanized_years
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.humanized_years
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
- %w[pop rock]
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