assignable_values 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -103,6 +103,18 @@ Defaults can be lambdas:
103
103
 
104
104
  The lambda will be evaluated in the context of the record instance.
105
105
 
106
+ You can also default a secondary default that is only set if the primary default value is not assignable:
107
+
108
+ class Song < ActiveRecord::Base
109
+ assignable_values_for :year, :default => 1999, :secondary_default => lambda { Date.today.year } do
110
+ (Date.today.year - 2) .. Date.today.year
111
+ end
112
+ end
113
+
114
+ If called in 2013 the code above will fall back to:
115
+
116
+ Song.new.year # => 2013
117
+
106
118
 
107
119
  ### Allowing blank values
108
120
 
@@ -3,7 +3,7 @@ module AssignableValues
3
3
  module Restriction
4
4
  class Base
5
5
 
6
- attr_reader :model, :property, :options, :values, :default
6
+ attr_reader :model, :property, :options, :values, :default, :secondary_default
7
7
 
8
8
  def initialize(model, property, options, &values)
9
9
  @model = model
@@ -11,7 +11,7 @@ module AssignableValues
11
11
  @options = options
12
12
  @values = values
13
13
  ensure_values_given
14
- setup_default if default?
14
+ setup_default
15
15
  define_assignable_values_method
16
16
  setup_validation
17
17
  end
@@ -20,8 +20,9 @@ module AssignableValues
20
20
  value = current_value(record)
21
21
  unless allow_blank? && value.blank?
22
22
  begin
23
- assignable_values = assignable_values(record)
24
- assignable_values.include?(value) or record.errors.add(property, not_included_error_message)
23
+ unless assignable_value?(record, value)
24
+ record.errors.add(property, not_included_error_message)
25
+ end
25
26
  rescue DelegateUnavailable
26
27
  # if the delegate is unavailable, the validation is skipped
27
28
  end
@@ -32,6 +33,10 @@ module AssignableValues
32
33
  I18n.t('errors.messages.inclusion', :default => 'is not included in the list')
33
34
  end
34
35
 
36
+ def assignable_value?(record, value)
37
+ assignable_values(record).include?(value)
38
+ end
39
+
35
40
  def assignable_values(record)
36
41
  assignable_values = []
37
42
  old_value = previously_saved_value(record)
@@ -43,8 +48,13 @@ module AssignableValues
43
48
 
44
49
  def set_default(record)
45
50
  if record.new_record? && record.send(property).nil?
46
- default_value = default
47
- default_value = record.instance_eval(&default_value) if default_value.is_a?(Proc)
51
+ default_value = evaluate_default(record, default)
52
+ if secondary_default? && !assignable_value?(record, default_value)
53
+ secondary_default_value = evaluate_default(record, secondary_default)
54
+ if assignable_value?(record, secondary_default_value)
55
+ default_value = secondary_default_value
56
+ end
57
+ end
48
58
  record.send("#{property}=", default_value)
49
59
  end
50
60
  true
@@ -52,6 +62,14 @@ module AssignableValues
52
62
 
53
63
  private
54
64
 
65
+ def evaluate_default(record, value_or_proc)
66
+ if value_or_proc.is_a?(Proc)
67
+ record.instance_eval(&value_or_proc)
68
+ else
69
+ value_or_proc
70
+ end
71
+ end
72
+
55
73
  def parse_values(values)
56
74
  values.to_a
57
75
  end
@@ -76,6 +94,10 @@ module AssignableValues
76
94
  @options.has_key?(:default)
77
95
  end
78
96
 
97
+ def secondary_default?
98
+ @options.has_key?(:secondary_default)
99
+ end
100
+
79
101
  def allow_blank?
80
102
  @options[:allow_blank]
81
103
  end
@@ -89,15 +111,20 @@ module AssignableValues
89
111
  end
90
112
 
91
113
  def setup_default
92
- ensure_after_initialize_callback_enabled
93
- @default = options[:default]
94
- restriction = self
95
- enhance_model do
96
- set_default_method = "set_default_#{restriction.property}"
97
- define_method set_default_method do
98
- restriction.set_default(self)
114
+ if default?
115
+ @default = options[:default] # for attr_reader
116
+ @secondary_default = options[:secondary_default] # for attr_reader
117
+ ensure_after_initialize_callback_enabled
118
+ restriction = self
119
+ enhance_model do
120
+ set_default_method = "set_default_#{restriction.property}"
121
+ define_method set_default_method do
122
+ restriction.set_default(self)
123
+ end
124
+ after_initialize set_default_method
99
125
  end
100
- after_initialize set_default_method
126
+ elsif secondary_default?
127
+ raise AssignableValues::NoDefault, "cannot use the :secondary_default option without a :default option"
101
128
  end
102
129
  end
103
130
 
@@ -2,4 +2,5 @@ module AssignableValues
2
2
  class Error < StandardError; end
3
3
  class DelegateUnavailable < Error; end
4
4
  class NoValuesGiven < Error; end
5
+ class NoDefault < Error; end
5
6
  end
@@ -1,3 +1,3 @@
1
1
  module AssignableValues
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -261,6 +261,79 @@ describe AssignableValues::ActiveRecord do
261
261
 
262
262
  end
263
263
 
264
+ context 'with :secondary_default option' do
265
+
266
+ it 'should set a secondary default value if the primary value is not assignable' do
267
+ klass = disposable_song_class do
268
+ assignable_values_for :genre, :default => 'techno', :secondary_default => 'rock' do
269
+ %w[pop rock]
270
+ end
271
+ end
272
+ klass.new.genre.should == 'rock'
273
+ end
274
+
275
+ it 'should not change the default value if the default value is assignable' do
276
+ klass = disposable_song_class do
277
+ assignable_values_for :genre, :default => 'pop', :secondary_default => 'rock' do
278
+ %w[pop rock]
279
+ end
280
+ end
281
+ klass.new.genre.should == 'pop'
282
+ end
283
+
284
+ it "should not change the primary default if the secondary default value isn't assignable either" do
285
+ klass = disposable_song_class do
286
+ assignable_values_for :genre, :default => 'techno', :secondary_default => 'jazz' do
287
+ %w[pop rock]
288
+ end
289
+ end
290
+ klass.new.genre.should == 'techno'
291
+ end
292
+
293
+ it 'should raise an error if used without a :default option' do
294
+ expect do
295
+ disposable_song_class do
296
+ assignable_values_for :genre, :secondary_default => 'pop' do
297
+ %w[pop rock]
298
+ end
299
+ end
300
+ end.to raise_error(AssignableValues::NoDefault)
301
+ end
302
+
303
+ it 'should allow to set a secondary default through a lambda' do
304
+ klass = disposable_song_class do
305
+ assignable_values_for :genre, :default => 'techno', :secondary_default => lambda { 'pop' } do
306
+ %w[pop rock]
307
+ end
308
+ end
309
+ klass.new.genre.should == 'pop'
310
+ end
311
+
312
+ it 'should evaluate a secondary lambda default in the context of the record instance' do
313
+ klass = disposable_song_class do
314
+ assignable_values_for :genre, :default => 'techno', :secondary_default => lambda { default_genre } do
315
+ %w[pop rock]
316
+ end
317
+ def default_genre
318
+ 'pop'
319
+ end
320
+ end
321
+ klass.new.genre.should == 'pop'
322
+ end
323
+
324
+ it 'should not cause the list of assignable values to be evaluated if the :secondary_default option is not used' do
325
+ klass = disposable_song_class do
326
+ assignable_values_for :genre, :default => 'techno' do
327
+ raise "block called!"
328
+ end
329
+ end
330
+ expect do
331
+ klass.new.genre.should == 'techno'
332
+ end.to_not raise_error
333
+ end
334
+
335
+ end
336
+
264
337
  context 'when generating methods to list assignable values' do
265
338
 
266
339
  it 'should generate an instance method returning a list of assignable values' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: assignable_values
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Henning Koch
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-31 00:00:00 +02:00
18
+ date: 2012-08-02 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency