default_value_for 1.0.7 → 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.
data/README.rdoc CHANGED
@@ -20,21 +20,18 @@ section. Please read on.
20
20
 
21
21
  == Installation
22
22
 
23
- === Rails 2
24
-
25
- Install with:
26
-
27
- ./script/plugin install git://github.com/FooBarWidget/default_value_for.git
28
-
29
23
  === Rails 3
30
24
 
31
- You can either install it as a plugin:
25
+ Add it to your Gemfile:
32
26
 
33
- rails plugin install git://github.com/FooBarWidget/default_value_for.git
27
+ gem "default_value_for"
34
28
 
35
- or install it by adding it to your Gemfile:
29
+ === Rails 2
36
30
 
37
- gem "default_value_for"
31
+ default_value_for no longer supports Rails 2! The last version that supported Rails
32
+ 2 is version 1.0.7. Install that with:
33
+
34
+ ./script/plugin install git://github.com/FooBarWidget/default_value_for.git -r release-1.0.7
38
35
 
39
36
 
40
37
  == The default_value_for method
@@ -84,6 +81,20 @@ whatever reason:
84
81
  UuidGenerator.new.generate_uuid
85
82
  end
86
83
  end
84
+
85
+ == default_value_for options
86
+
87
+ * allows_nil (default: true) - Sets explicitly passed nil values if option is set to true.
88
+
89
+ You can pass this options hash as 2nd parameter and have to pass the default value through the :value option in this case e.g.:
90
+
91
+ default_value_for :age, :value => 20, :allows_nil => false
92
+
93
+ You can still pass the default value through a block:
94
+
95
+ default_value_for :uuid, :allows_nil => false do
96
+ UuidGenerator.new.generate_uuid
97
+ end
87
98
 
88
99
  == The default_values method
89
100
 
@@ -92,6 +103,11 @@ As a shortcut, you can use +default_values+ to set multiple default values at on
92
103
  default_values :age => 20,
93
104
  :uuid => lambda { UuidGenerator.new.generate_uuid }
94
105
 
106
+ If you like to override default_value_for options for each attribute you can do so:
107
+
108
+ default_values :age => { :value => 20 },
109
+ :uuid => { :value => lambda { UuidGenerator.new.generate_uuid }, :allows_nil => false }
110
+
95
111
  The difference is purely aesthetic. If you have lots of default values which are constants or constructed with one-line blocks, +default_values+ may look nicer. If you have default values constructed by longer blocks, +default_value_for+ suit you better. Feel free to mix and match.
96
112
 
97
113
  As a side note, due to specifics of Ruby's parser, you cannot say,
@@ -103,7 +119,7 @@ because it will not parse. One needs to write
103
119
  default_value_for(:uuid) { UuidGenerator.new.generate_uuid }
104
120
 
105
121
  instead. This is in part the inspiration for the +default_values+ syntax.
106
-
122
+
107
123
  == Rules
108
124
 
109
125
  === Instantiation of new record
@@ -113,7 +129,7 @@ the record. You've already seen this in the above examples.
113
129
 
114
130
  === Retrieval of existing record
115
131
 
116
- Upon retrieving an existing record, the declared default values are _not_
132
+ Upon retrieving an existing record in the following case, the declared default values are _not_
117
133
  filled into the record. Consider the example with the UUID:
118
134
 
119
135
  user = User.create
@@ -123,6 +139,19 @@ filled into the record. Consider the example with the UUID:
123
139
  # UUID remains unchanged because it's retrieved from the database!
124
140
  user.uuid # => "529c91b8bbd3e..."
125
141
 
142
+ But when the declared default value is set to not allow nil and nil is passed the default values will be set on retrieval.
143
+ Consider this example:
144
+
145
+ default_value_for(:number, :allows_nil => false) { 123 }
146
+
147
+ user = User.create
148
+
149
+ # manual SQL by-passing active record and the default value for gem logic through ActiveRecord's after_initialize callback
150
+ user.update_attribute(:number, nil)
151
+
152
+ # declared default value should be set
153
+ User.find(user.id).number # => 123 # = declared default value
154
+
126
155
  === Mass-assignment
127
156
 
128
157
  If a certain attribute is being assigned via the model constructor's
@@ -142,6 +171,28 @@ then it will be filled in:
142
171
 
143
172
  user = User.new(:name => "Jane")
144
173
  user.name # => "Joe"
174
+
175
+ # the without protection option will work as expected
176
+ user = User.new({:name => "Jane"}, :without_protection => true)
177
+ user.name # => "Jane"
178
+
179
+ Explicitly set nil values for accessible attributes will be accepted:
180
+
181
+ class User < ActiveRecord::Base
182
+ default_value_for :name, 'Joe'
183
+ end
184
+
185
+ user = User(:name => nil)
186
+ user.name # => nil
187
+
188
+ ... unless the accessible attribute is set to not allowing nil:
189
+
190
+ class User < ActiveRecord::Base
191
+ default_value_for :name, 'Joe', :allows_nil => false
192
+ end
193
+
194
+ user = User(:name => nil)
195
+ user.name # => "Joe"
145
196
 
146
197
  === Inheritance
147
198
 
@@ -267,6 +318,9 @@ Also, stick with the following rules:
267
318
  - Make sure that +alias_method_chain+ is called *after* the last
268
319
  +default_value_for+ occurance.
269
320
 
321
+ If your default value is accidentally similar to default_value_for's options hash wrap your default value like this:
322
+
323
+ default_value_for :attribute_name, :value => { :value => 123, :other_value => 1234 }
270
324
 
271
325
  == When (not) to use default_value_for?
272
326
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{default_value_for}
3
- s.version = "1.0.7"
3
+ s.version = "2.0.0"
4
4
  s.summary = %q{Provides a way to specify default values for ActiveRecord models}
5
5
  s.description = %q{The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner}
6
6
  s.email = %q{info@phusion.nl}
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008, 2009, 2010, 2011 Phusion
1
+ # Copyright (c) 2008-2012 Phusion
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -19,104 +19,144 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module DefaultValueFor
22
- class NormalValueContainer
23
- def initialize(value)
24
- @value = value
25
- end
22
+ class NormalValueContainer
23
+ def initialize(value)
24
+ @value = value
25
+ end
26
26
 
27
- def evaluate(instance)
28
- if @value.duplicable?
29
- return @value.dup
30
- else
31
- return @value
32
- end
33
- end
34
- end
27
+ def evaluate(instance)
28
+ if @value.duplicable?
29
+ return @value.dup
30
+ else
31
+ return @value
32
+ end
33
+ end
34
+ end
35
35
 
36
- class BlockValueContainer
37
- def initialize(block)
38
- @block = block
39
- end
36
+ class BlockValueContainer
37
+ def initialize(block)
38
+ @block = block
39
+ end
40
40
 
41
- def evaluate(instance)
42
- if @block.arity == 0
43
- return @block.call
44
- else
45
- return @block.call(instance)
46
- end
47
- end
48
- end
41
+ def evaluate(instance)
42
+ if @block.arity == 0
43
+ return @block.call
44
+ else
45
+ return @block.call(instance)
46
+ end
47
+ end
48
+ end
49
49
 
50
- module ClassMethods
51
- def default_value_for(attribute, value = nil, &block)
52
- if !method_defined?(:initialize_with_defaults)
53
- include(InstanceMethods)
54
- alias_method_chain :initialize, :defaults
55
- if respond_to?(:class_attribute)
56
- class_attribute :_default_attribute_values
57
- else
58
- class_inheritable_accessor :_default_attribute_values
59
- end
60
- extend(DelayedClassMethods)
61
- init_hash = true
62
- end
63
- if init_hash || !singleton_methods(false).to_s.include?("_default_attribute_values")
64
- self._default_attribute_values = ActiveSupport::OrderedHash.new
65
- end
66
- if block_given?
67
- container = BlockValueContainer.new(block)
68
- else
69
- container = NormalValueContainer.new(value)
70
- end
71
- _default_attribute_values[attribute.to_s] = container
72
- end
50
+ module ClassMethods
51
+ # Declares a default value for the given attribute.
52
+ #
53
+ # Sets the default value to the given options parameter unless the given options equal { :value => ... }
54
+ #
55
+ # The <tt>options</tt> can be used to specify the following things:
56
+ # * <tt>value</tt> - Sets the default value.
57
+ # * <tt>allows_nil (default: true)</tt> - Sets explicitly passed nil values if option is set to true.
58
+ def default_value_for(attribute, options = {}, &block)
59
+ value = options.is_a?(Hash) && options.stringify_keys.has_key?('value') ? options.stringify_keys['value'] : options
60
+ allows_nil = options.is_a?(Hash) && options.stringify_keys.has_key?('allows_nil') ? options.stringify_keys['allows_nil'] : true
61
+
62
+ if !method_defined?(:set_default_values)
63
+ include(InstanceMethods)
73
64
 
74
- def default_values(values)
75
- values.each_pair do |key, value|
76
- if value.kind_of? Proc
77
- default_value_for(key, &value)
78
- else
79
- default_value_for(key, value)
80
- end
81
- end
82
- end
83
- end
65
+ after_initialize :set_default_values
66
+
67
+ if respond_to?(:class_attribute)
68
+ class_attribute :_default_attribute_values
69
+ class_attribute :_default_attribute_values_not_allowing_nil
70
+ else
71
+ class_inheritable_accessor :_default_attribute_values
72
+ class_inheritable_accessor :_default_attribute_values_not_allowing_nil
73
+ end
74
+
75
+ extend(DelayedClassMethods)
76
+ init_hash = true
77
+ end
78
+ if init_hash || !singleton_methods(false).to_s.include?("_default_attribute_values")
79
+ self._default_attribute_values = ActiveSupport::OrderedHash.new
80
+ self._default_attribute_values_not_allowing_nil = []
81
+ end
82
+ if block_given?
83
+ container = BlockValueContainer.new(block)
84
+ else
85
+ container = NormalValueContainer.new(value)
86
+ end
87
+ _default_attribute_values[attribute.to_s] = container
88
+ _default_attribute_values_not_allowing_nil << attribute.to_s unless allows_nil
89
+ end
84
90
 
85
- module DelayedClassMethods
86
- def _all_default_attribute_values
87
- return _default_attribute_values unless superclass.respond_to?(:_default_attribute_values)
88
- superclass._all_default_attribute_values.merge(_default_attribute_values)
89
- end
90
- end
91
+ def default_values(values)
92
+ values.each_pair do |key, options|
93
+ options = options.stringify_keys if options.is_a?(Hash)
94
+
95
+ value = options.is_a?(Hash) && options.has_key?('value') ? options['value'] : options
96
+
97
+ if value.kind_of? Proc
98
+ default_value_for(key, options.is_a?(Hash) ? options : {}, &value)
99
+ else
100
+ default_value_for(key, options)
101
+ end
102
+ end
103
+ end
104
+ end
91
105
 
92
- module InstanceMethods
93
- def initialize_with_defaults(attrs = nil, *args, &block)
94
- initialize_without_defaults(attrs, *args, &block)
95
- if attrs
96
- stringified_attrs = attrs.stringify_keys
97
- safe_attrs = if respond_to? :sanitize_for_mass_assignment
98
- sanitize_for_mass_assignment(stringified_attrs)
99
- else
100
- remove_attributes_protected_from_mass_assignment(stringified_attrs)
101
- end
102
- safe_attribute_names = safe_attrs.keys.map do |x|
103
- x.to_s
104
- end
105
- end
106
- self.class._all_default_attribute_values.each do |attribute, container|
107
- if safe_attribute_names.nil? || !safe_attribute_names.any? { |attr_name| attr_name =~ /^#{attribute}($|\()/ }
108
- __send__("#{attribute}=", container.evaluate(self))
109
- changed_attributes.delete(attribute)
110
- end
111
- end
112
- yield(self) if block_given?
113
- end
114
- end
106
+ module DelayedClassMethods
107
+ def _all_default_attribute_values
108
+ return _default_attribute_values unless superclass.respond_to?(:_default_attribute_values)
109
+ superclass._all_default_attribute_values.merge(_default_attribute_values)
110
+ end
111
+
112
+ def _all_default_attribute_values_not_allowing_nil
113
+ return _default_attribute_values_not_allowing_nil unless superclass.respond_to?(:_default_attribute_values_not_allowing_nil)
114
+ superclass._all_default_attribute_values_not_allowing_nil.merge(_default_attribute_values_not_allowing_nil)
115
+ end
116
+ end
117
+
118
+ module InstanceMethods
119
+ def initialize(attributes = nil, options = {})
120
+ @initialization_attributes = attributes.is_a?(Hash) ? attributes.stringify_keys : {}
121
+
122
+ unless options[:without_protection]
123
+ if respond_to?(:mass_assignment_options) && options.has_key?(:as)
124
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes, options[:as])
125
+ elsif respond_to?(:sanitize_for_mass_assignment)
126
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes)
127
+ else
128
+ @initialization_attributes = remove_attributes_protected_from_mass_assignment(@initialization_attributes)
129
+ end
130
+ end
131
+
132
+ if ActiveRecord::VERSION::MAJOR > 3 || (ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR > 0)
133
+ super(attributes, options)
134
+ else
135
+ super(attributes)
136
+ end
137
+ end
138
+
139
+ def set_default_values
140
+ self.class._all_default_attribute_values.each do |attribute, container|
141
+ next unless self.new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
142
+
143
+ connection_default_value_defined = new_record? && respond_to?("#{attribute}_changed?") && !__send__("#{attribute}_changed?")
144
+
145
+ next unless connection_default_value_defined || self.attributes[attribute].blank?
146
+
147
+ # allow explicitly setting nil through allow nil option
148
+ next if @initialization_attributes.is_a?(Hash) && @initialization_attributes.has_key?(attribute) && !self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
149
+
150
+ __send__("#{attribute}=", container.evaluate(self))
151
+ changed_attributes.delete(attribute)
152
+ end
153
+ end
154
+ end
115
155
  end
116
156
 
117
157
  if defined?(Rails::Railtie)
118
- require 'default_value_for/railtie'
158
+ require 'default_value_for/railtie'
119
159
  else
120
- # Rails 2 initialization
121
- ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
160
+ # Rails 2 initialization
161
+ ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
122
162
  end
data/test.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008, 2009 Phusion
1
+ # Copyright (c) 2008-2012 Phusion
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -18,13 +18,13 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- want_rails_version = '~> 3.1.0'
21
+ want_rails_version = '~> ' + ENV.fetch('WANT_RAILS_VERSION', '3.2.0')
22
22
 
23
23
  require 'rubygems'
24
24
  gem 'rails', want_rails_version
25
25
  gem 'activerecord', want_rails_version
26
26
  begin
27
- require 'rails/railtie'
27
+ require 'rails/railtie'
28
28
  rescue LoadError
29
29
  end
30
30
  require 'active_record'
@@ -36,335 +36,392 @@ require 'default_value_for'
36
36
  Dir.chdir(File.dirname(__FILE__))
37
37
 
38
38
  if RUBY_PLATFORM == "java"
39
- database_adapter = "jdbcsqlite3"
39
+ database_adapter = "jdbcsqlite3"
40
40
  else
41
- database_adapter = "sqlite3"
41
+ database_adapter = "sqlite3"
42
42
  end
43
43
 
44
44
  File.unlink('test.sqlite3') rescue nil
45
45
  ActiveRecord::Base.logger = Logger.new(STDERR)
46
46
  ActiveRecord::Base.logger.level = Logger::WARN
47
47
  ActiveRecord::Base.establish_connection(
48
- :adapter => database_adapter,
49
- :database => 'test.sqlite3'
48
+ :adapter => database_adapter,
49
+ :database => 'test.sqlite3'
50
50
  )
51
51
  ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
52
- t.string :username
53
- t.integer :default_number
52
+ t.string :username
53
+ t.integer :default_number
54
54
  end
55
55
  ActiveRecord::Base.connection.create_table(:numbers, :force => true) do |t|
56
- t.string :type
57
- t.integer :number
58
- t.integer :count, :null => false, :default => 1
59
- t.integer :user_id
60
- t.timestamp :timestamp
56
+ t.string :type
57
+ t.integer :number
58
+ t.integer :count, :null => false, :default => 1
59
+ t.integer :user_id
60
+ t.timestamp :timestamp
61
61
  end
62
62
 
63
63
  if defined?(Rails::Railtie)
64
- DefaultValueFor.initialize_railtie
65
- DefaultValueFor.initialize_active_record_extensions
64
+ DefaultValueFor.initialize_railtie
65
+ DefaultValueFor.initialize_active_record_extensions
66
66
  end
67
67
 
68
68
  class User < ActiveRecord::Base
69
- has_many :numbers, :class_name => 'TestClass'
69
+ has_many :numbers, :class_name => 'TestClass'
70
70
  end
71
71
 
72
72
  class Number < ActiveRecord::Base
73
73
  end
74
74
 
75
75
  class DefaultValuePluginTest < Test::Unit::TestCase
76
- def setup
77
- Number.create(:number => 9876)
78
- end
79
-
80
- def teardown
81
- Number.delete_all
82
- end
83
-
84
- def define_model_class(name = "TestClass", parent_class_name = "ActiveRecord::Base", &block)
85
- Object.send(:remove_const, name) rescue nil
86
- eval("class #{name} < #{parent_class_name}; end", TOPLEVEL_BINDING)
87
- klass = eval(name, TOPLEVEL_BINDING)
88
- klass.class_eval do
89
- set_table_name 'numbers'
90
- end
91
- klass.class_eval(&block) if block_given?
92
- end
93
-
94
- def test_default_value_can_be_passed_as_argument
95
- define_model_class do
96
- default_value_for(:number, 1234)
97
- end
98
- object = TestClass.new
99
- assert_equal 1234, object.number
100
- end
101
-
102
- def test_default_value_can_be_passed_as_block
103
- define_model_class do
104
- default_value_for(:number) { 1234 }
105
- end
106
- object = TestClass.new
107
- assert_equal 1234, object.number
108
- end
109
-
110
- def test_works_with_create
111
- define_model_class do
112
- default_value_for :number, 1234
113
- end
114
- TestClass.create
115
- assert_not_nil TestClass.find_by_number(1234)
116
- end
117
-
118
- def test_overwrites_db_default
119
- define_model_class do
120
- default_value_for :count, 1234
121
- end
122
- object = TestClass.new
123
- assert_equal 1234, object.count
124
- end
125
-
126
- def test_doesnt_overwrite_values_provided_by_mass_assignment
127
- define_model_class do
128
- default_value_for :number, 1234
129
- end
130
- object = TestClass.new(:number => 1, :count => 2)
131
- assert_equal 1, object.number
132
- end
133
-
134
- def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
135
- define_model_class do
136
- default_value_for :timestamp, Time.mktime(2000, 1, 1)
137
- end
138
- timestamp = Time.mktime(2009, 1, 1)
139
- object = TestClass.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
140
- assert_equal timestamp, object.timestamp
141
- end
142
-
143
- def test_doesnt_overwrite_values_provided_by_constructor_block
144
- define_model_class do
145
- default_value_for :number, 1234
146
- end
147
- object = TestClass.new do |x|
148
- x.number = 1
149
- x.count = 2
150
- end
151
- assert_equal 1, object.number
152
- end
153
-
154
- def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
155
- define_model_class do
156
- default_value_for :number, 1234
157
- end
158
- object = TestClass.new(:number => nil)
159
- assert_nil object.number
160
- end
161
-
162
- def test_default_values_are_inherited
163
- define_model_class("TestSuperClass") do
164
- default_value_for :number, 1234
165
- end
166
- define_model_class("TestClass", "TestSuperClass")
167
- object = TestClass.new
168
- assert_equal 1234, object.number
169
- end
170
-
171
- def test_default_values_in_subclass
172
- define_model_class("TestSuperClass") do
173
- end
174
- define_model_class("TestClass", "TestSuperClass") do
175
- default_value_for :number, 5678
176
- end
177
-
178
- object = TestClass.new
179
- assert_equal 5678, object.number
180
-
181
- object = TestSuperClass.new
182
- assert_nil object.number
183
- end
184
-
185
- def test_multiple_default_values_in_subclass_with_default_values_in_parent_class
186
- define_model_class("TestSuperClass") do
187
- default_value_for :other_number, nil
188
- attr_accessor :other_number
189
- end
190
- define_model_class("TestClass", "TestSuperClass") do
191
- default_value_for :number, 5678
192
-
193
- # Ensure second call in this class doesn't reset _default_attribute_values,
194
- # and also doesn't consider the parent class' _default_attribute_values when
195
- # making that check.
196
- default_value_for :user_id, 9999
197
- end
198
-
199
- object = TestClass.new
200
- assert_nil object.other_number
201
- assert_equal 5678, object.number
202
- assert_equal 9999, object.user_id
203
- end
204
-
205
- def test_override_default_values_in_subclass
206
- define_model_class("TestSuperClass") do
207
- default_value_for :number, 1234
208
- end
209
- define_model_class("TestClass", "TestSuperClass") do
210
- default_value_for :number, 5678
211
- end
212
-
213
- object = TestClass.new
214
- assert_equal 5678, object.number
215
-
216
- object = TestSuperClass.new
217
- assert_equal 1234, object.number
218
- end
219
-
220
- def test_default_values_in_subclass_do_not_affect_parent_class
221
- define_model_class("TestSuperClass") do
222
- default_value_for :number, 1234
223
- end
224
- define_model_class("TestClass", "TestSuperClass") do
225
- default_value_for :hello, "hi"
226
- attr_accessor :hello
227
- end
228
-
229
- assert_nothing_raised { TestSuperClass.new }
230
- assert !TestSuperClass._default_attribute_values.include?(:hello)
231
- end
232
-
233
- def test_doesnt_set_default_on_saved_records
234
- define_model_class do
235
- default_value_for :number, 1234
236
- end
237
- assert_equal 9876, TestClass.find(:first).number
238
- end
239
-
240
- def test_also_works_on_attributes_that_arent_database_columns
241
- define_model_class do
242
- default_value_for :hello, "hi"
243
- attr_accessor :hello
244
- end
245
- object = TestClass.new
246
- assert_equal 'hi', object.hello
247
- end
248
-
249
- def test_constructor_ignores_forbidden_mass_assignment_attributes
250
- define_model_class do
251
- default_value_for :number, 1234
252
- attr_protected :number
253
- end
254
- object = TestClass.new(:number => 5678, :count => 987)
255
- assert_equal 1234, object.number
256
- assert_equal 987, object.count
257
- end
258
-
259
- def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
260
- define_model_class do
261
- def initialize(attrs = {})
262
- @initialized = true
263
- super(:count => 5678)
264
- end
265
-
266
- default_value_for :number, 1234
267
- end
268
- object = TestClass.new
269
- assert_equal 1234, object.number
270
- assert_equal 5678, object.count
271
- assert object.instance_variable_get('@initialized')
272
- end
273
-
274
- def test_model_instance_is_passed_to_the_given_block
275
- $instance = nil
276
- define_model_class do
277
- default_value_for :number do |n|
278
- $instance = n
279
- end
280
- end
281
- object = TestClass.new
282
- assert_same object, $instance
283
- end
284
-
285
- def test_can_specify_default_value_via_association
286
- user = User.create(:username => 'Kanako', :default_number => 123)
287
- define_model_class do
288
- belongs_to :user
289
-
290
- default_value_for :number do |n|
291
- n.user.default_number
292
- end
293
- end
294
- object = user.numbers.create
295
- assert_equal 123, object.number
296
- end
297
-
298
- def test_default_values
299
- define_model_class do
300
- default_values :type => "normal",
301
- :number => lambda { 10 + 5 },
302
- :timestamp => lambda {|_| Time.now }
303
- end
304
-
305
- object = TestClass.new
306
- assert_equal("normal", object.type)
307
- assert_equal(15, object.number)
308
- end
309
-
310
- def test_default_value_order
311
- define_model_class do
312
- default_value_for :count, 5
313
- default_value_for :number do |this|
314
- this.count * 2
315
- end
316
- end
317
- object = TestClass.new
318
- assert_equal(5, object.count)
319
- assert_equal(10, object.number)
320
- end
321
-
322
- def test_attributes_with_default_values_are_not_marked_as_changed
323
- define_model_class do
324
- default_value_for :count, 5
325
- default_value_for :number, 2
326
- end
327
-
328
- object = TestClass.new
329
- assert(!object.changed?)
330
- assert_equal([], object.changed)
331
-
332
- object.type = "foo"
333
- assert(object.changed?)
334
- assert_equal(["type"], object.changed)
335
- end
336
-
337
- def test_default_values_are_duplicated
338
- define_model_class do
339
- set_table_name "users"
340
- default_value_for :username, "hello"
341
- end
342
- user1 = TestClass.new
343
- user1.username << " world"
344
- user2 = TestClass.new
345
- assert_equal("hello", user2.username)
346
- end
347
-
348
- def test_default_values_are_shallow_copied
349
- define_model_class do
350
- set_table_name "users"
351
- attr_accessor :hash
352
- default_value_for :hash, { 1 => [] }
353
- end
354
- user1 = TestClass.new
355
- user1.hash[1] << 1
356
- user2 = TestClass.new
357
- assert_equal([1], user2.hash[1])
358
- end
359
-
360
- def test_constructor_does_not_affect_the_hash_passed_to_it
361
- define_model_class do
362
- default_value_for :count, 5
363
- end
364
-
365
- options = { :count => 5, :user_id => 1 }
366
- options_dup = options.dup
367
- object = TestClass.new(options)
368
- assert_equal(options_dup, options)
369
- end
76
+ def setup
77
+ Number.create(:number => 9876)
78
+ end
79
+
80
+ def teardown
81
+ Number.delete_all
82
+ end
83
+
84
+ def define_model_class(name = "TestClass", parent_class_name = "ActiveRecord::Base", &block)
85
+ Object.send(:remove_const, name) rescue nil
86
+ eval("class #{name} < #{parent_class_name}; end", TOPLEVEL_BINDING)
87
+ klass = eval(name, TOPLEVEL_BINDING)
88
+ klass.class_eval do
89
+ if respond_to?(:table_name=)
90
+ self.table_name = 'numbers'
91
+ else
92
+ set_table_name 'numbers'
93
+ end
94
+ end
95
+ klass.class_eval(&block) if block_given?
96
+ end
97
+
98
+ def test_default_value_can_be_passed_as_argument
99
+ define_model_class do
100
+ default_value_for(:number, 1234)
101
+ end
102
+ object = TestClass.new
103
+ assert_equal 1234, object.number
104
+ end
105
+
106
+ def test_default_value_can_be_passed_as_block
107
+ define_model_class do
108
+ default_value_for(:number) { 1234 }
109
+ end
110
+ object = TestClass.new
111
+ assert_equal 1234, object.number
112
+ end
113
+
114
+ def test_works_with_create
115
+ define_model_class do
116
+ default_value_for :number, 1234
117
+ end
118
+
119
+ object = TestClass.create
120
+ assert_not_nil TestClass.find_by_number(1234)
121
+
122
+ # allows nil for existing records
123
+ object.update_attribute(:number, nil)
124
+ assert_nil TestClass.find_by_number(1234)
125
+ assert_nil TestClass.find(object.id).number
126
+ end
127
+
128
+ def test_does_not_allow_nil_for_existing_record
129
+ define_model_class do
130
+ default_value_for(:number, :allows_nil => false) { 1234 }
131
+ end
132
+
133
+ object = TestClass.create
134
+
135
+ # allows nil for existing records
136
+ object.update_attribute(:number, nil)
137
+ assert_nil TestClass.find_by_number(1234)
138
+ assert_equal 1234, TestClass.find(object.id).number
139
+ end
140
+
141
+ def test_overwrites_db_default
142
+ define_model_class do
143
+ default_value_for :count, 1234
144
+ end
145
+ object = TestClass.new
146
+ assert_equal 1234, object.count
147
+ end
148
+
149
+ def test_doesnt_overwrite_values_provided_by_mass_assignment
150
+ define_model_class do
151
+ default_value_for :number, 1234
152
+ end
153
+ object = TestClass.new(:number => 1, :count => 2)
154
+ assert_equal 1, object.number
155
+ end
156
+
157
+ def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
158
+ define_model_class do
159
+ default_value_for :timestamp, Time.mktime(2000, 1, 1)
160
+ end
161
+ timestamp = Time.mktime(2009, 1, 1)
162
+ object = TestClass.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
163
+ assert_equal timestamp, object.timestamp
164
+ end
165
+
166
+ def test_doesnt_overwrite_values_provided_by_constructor_block
167
+ define_model_class do
168
+ default_value_for :number, 1234
169
+ end
170
+ object = TestClass.new do |x|
171
+ x.number = 1
172
+ x.count = 2
173
+ end
174
+ assert_equal 1, object.number
175
+ end
176
+
177
+ def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
178
+ define_model_class do
179
+ default_value_for :number, 1234
180
+ end
181
+ object = TestClass.new(:number => nil)
182
+ assert_equal nil, object.number
183
+ end
184
+
185
+ def test_overwrites_explicitly_provided_nil_values_in_mass_assignment
186
+ define_model_class do
187
+ default_value_for :number, :value => 1234, :allows_nil => false
188
+ end
189
+ object = TestClass.new(:number => nil)
190
+ assert_equal 1234, object.number
191
+ end
192
+
193
+ def test_default_values_are_inherited
194
+ define_model_class("TestSuperClass") do
195
+ default_value_for :number, 1234
196
+ end
197
+ define_model_class("TestClass", "TestSuperClass")
198
+ object = TestClass.new
199
+ assert_equal 1234, object.number
200
+ end
201
+
202
+ def test_default_values_in_subclass
203
+ define_model_class("TestSuperClass") do
204
+ end
205
+ define_model_class("TestClass", "TestSuperClass") do
206
+ default_value_for :number, 5678
207
+ end
208
+
209
+ object = TestClass.new
210
+ assert_equal 5678, object.number
211
+
212
+ object = TestSuperClass.new
213
+ assert_nil object.number
214
+ end
215
+
216
+ def test_multiple_default_values_in_subclass_with_default_values_in_parent_class
217
+ define_model_class("TestSuperClass") do
218
+ default_value_for :other_number, nil
219
+ attr_accessor :other_number
220
+ end
221
+ define_model_class("TestClass", "TestSuperClass") do
222
+ default_value_for :number, 5678
223
+
224
+ # Ensure second call in this class doesn't reset _default_attribute_values,
225
+ # and also doesn't consider the parent class' _default_attribute_values when
226
+ # making that check.
227
+ default_value_for :user_id, 9999
228
+ end
229
+
230
+ object = TestClass.new
231
+ assert_nil object.other_number
232
+ assert_equal 5678, object.number
233
+ assert_equal 9999, object.user_id
234
+ end
235
+
236
+ def test_override_default_values_in_subclass
237
+ define_model_class("TestSuperClass") do
238
+ default_value_for :number, 1234
239
+ end
240
+ define_model_class("TestClass", "TestSuperClass") do
241
+ default_value_for :number, 5678
242
+ end
243
+
244
+ object = TestClass.new
245
+ assert_equal 5678, object.number
246
+
247
+ object = TestSuperClass.new
248
+ assert_equal 1234, object.number
249
+ end
250
+
251
+ def test_default_values_in_subclass_do_not_affect_parent_class
252
+ define_model_class("TestSuperClass") do
253
+ default_value_for :number, 1234
254
+ end
255
+ define_model_class("TestClass", "TestSuperClass") do
256
+ default_value_for :hello, "hi"
257
+ attr_accessor :hello
258
+ end
259
+
260
+ assert_nothing_raised { TestSuperClass.new }
261
+ assert !TestSuperClass._default_attribute_values.include?(:hello)
262
+ end
263
+
264
+ def test_doesnt_set_default_on_saved_records
265
+ define_model_class do
266
+ default_value_for :number, 1234
267
+ end
268
+ assert_equal 9876, TestClass.find(:first).number
269
+ end
270
+
271
+ def test_also_works_on_attributes_that_arent_database_columns
272
+ define_model_class do
273
+ default_value_for :hello, "hi"
274
+ attr_accessor :hello
275
+ end
276
+ object = TestClass.new
277
+ assert_equal 'hi', object.hello
278
+ end
279
+
280
+ def test_constructor_ignores_forbidden_mass_assignment_attributes
281
+ define_model_class do
282
+ default_value_for :number, 1234
283
+ attr_protected :number
284
+ end
285
+ object = TestClass.new(:number => 5678, :count => 987)
286
+ assert_equal 1234, object.number
287
+ assert_equal 987, object.count
288
+ end
289
+
290
+ def test_constructor_respects_without_protection_option
291
+ define_model_class do
292
+ default_value_for :number, 1234
293
+ attr_protected :number
294
+
295
+ def respond_to_mass_assignment_options?
296
+ respond_to? :mass_assignment_options
297
+ end
298
+ end
299
+
300
+ if TestClass.new.respond_to_mass_assignment_options?
301
+ # test without protection feature if available in current ActiveRecord version
302
+ object = TestClass.create!({:number => 5678, :count => 987}, :without_protection => true)
303
+ assert_equal 5678, object.number
304
+ assert_equal 987, object.count
305
+ end
306
+ end
307
+
308
+ def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
309
+ define_model_class do
310
+ def initialize(attrs = {})
311
+ @initialized = true
312
+ super(:count => 5678)
313
+ end
314
+
315
+ default_value_for :number, 1234
316
+ end
317
+ object = TestClass.new
318
+ assert_equal 1234, object.number
319
+ assert_equal 5678, object.count
320
+ assert object.instance_variable_get('@initialized')
321
+ end
322
+
323
+ def test_model_instance_is_passed_to_the_given_block
324
+ $instance = nil
325
+ define_model_class do
326
+ default_value_for :number do |n|
327
+ $instance = n
328
+ end
329
+ end
330
+ object = TestClass.new
331
+ assert_same object, $instance
332
+ end
333
+
334
+ def test_can_specify_default_value_via_association
335
+ user = User.create(:username => 'Kanako', :default_number => 123)
336
+ define_model_class do
337
+ belongs_to :user
338
+
339
+ default_value_for :number do |n|
340
+ n.user.default_number
341
+ end
342
+ end
343
+ object = user.numbers.create
344
+ assert_equal 123, object.number
345
+ end
346
+
347
+ def test_default_values
348
+ define_model_class do
349
+ default_values :type => "normal",
350
+ :number => lambda { 10 + 5 },
351
+ :timestamp => lambda {|_| Time.now }
352
+ end
353
+
354
+ object = TestClass.new
355
+ assert_equal("normal", object.type)
356
+ assert_equal(15, object.number)
357
+ end
358
+
359
+ def test_default_value_order
360
+ define_model_class do
361
+ default_value_for :count, 5
362
+ default_value_for :number do |this|
363
+ this.count * 2
364
+ end
365
+ end
366
+ object = TestClass.new
367
+ assert_equal(5, object.count)
368
+ assert_equal(10, object.number)
369
+ end
370
+
371
+ def test_attributes_with_default_values_are_not_marked_as_changed
372
+ define_model_class do
373
+ default_value_for :count, 5
374
+ default_value_for :number, 2
375
+ end
376
+
377
+ object = TestClass.new
378
+ assert(!object.changed?)
379
+ assert_equal([], object.changed)
380
+
381
+ object.type = "foo"
382
+ assert(object.changed?)
383
+ assert_equal(["type"], object.changed)
384
+ end
385
+
386
+ def test_default_values_are_duplicated
387
+ define_model_class do
388
+ if respond_to?(:table_name=)
389
+ self.table_name = "users"
390
+ else
391
+ set_table_name "users"
392
+ end
393
+ default_value_for :username, "hello"
394
+ end
395
+ user1 = TestClass.new
396
+ user1.username << " world"
397
+ user2 = TestClass.new
398
+ assert_equal("hello", user2.username)
399
+ end
400
+
401
+ def test_default_values_are_shallow_copied
402
+ define_model_class do
403
+ if respond_to?(:table_name=)
404
+ self.table_name = "users"
405
+ else
406
+ set_table_name "users"
407
+ end
408
+ attr_accessor :hash
409
+ default_value_for :hash, { 1 => [] }
410
+ end
411
+ user1 = TestClass.new
412
+ user1.hash[1] << 1
413
+ user2 = TestClass.new
414
+ assert_equal([1], user2.hash[1])
415
+ end
416
+
417
+ def test_constructor_does_not_affect_the_hash_passed_to_it
418
+ define_model_class do
419
+ default_value_for :count, 5
420
+ end
421
+
422
+ options = { :count => 5, :user_id => 1 }
423
+ options_dup = options.dup
424
+ object = TestClass.new(options)
425
+ assert_equal(options_dup, options)
426
+ end
370
427
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: default_value_for
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
- - 1
7
+ - 2
8
8
  - 0
9
- - 7
10
- version: 1.0.7
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Hongli Lai
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-12-02 00:00:00 +01:00
19
- default_executable:
18
+ date: 2012-05-27 00:00:00 Z
20
19
  dependencies: []
21
20
 
22
21
  description: The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner
@@ -36,7 +35,6 @@ files:
36
35
  - init.rb
37
36
  - lib/default_value_for.rb
38
37
  - lib/default_value_for/railtie.rb
39
- has_rdoc: true
40
38
  homepage: http://github.com/FooBarWidget/default_value_for
41
39
  licenses: []
42
40
 
@@ -66,9 +64,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
64
  requirements: []
67
65
 
68
66
  rubyforge_project:
69
- rubygems_version: 1.5.2
67
+ rubygems_version: 1.8.15
70
68
  signing_key:
71
69
  specification_version: 3
72
70
  summary: Provides a way to specify default values for ActiveRecord models
73
71
  test_files: []
74
72
 
73
+ has_rdoc: