gitlab-default_value_for 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :test
4
+
5
+ desc "Run unit tests."
6
+ task :test do
7
+ ruby "test.rb"
8
+ end
9
+
10
+ ['3.2', '4.0', '4.1', '4.2', '5.0', '5.1', '5.2'].each do |version|
11
+ dotless = version.delete('.')
12
+
13
+ namespace :bundle do
14
+ desc "Bundle with Rails #{version}.x"
15
+ task :"rails#{dotless}" do
16
+ ENV['BUNDLE_GEMFILE'] = "gemfiles/rails_#{dotless}.gemfile"
17
+ sh "bundle"
18
+ end
19
+ end
20
+
21
+ namespace :test do
22
+ desc "Test with Rails #{version}.x"
23
+ task :"rails#{dotless}" do
24
+ ENV['BUNDLE_GEMFILE'] = "gemfiles/rails_#{dotless}.gemfile"
25
+ ruby "test.rb"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{gitlab-default_value_for}
3
+ s.version = "3.1.1"
4
+ s.summary = %q{Provides a way to specify default values for ActiveRecord models}
5
+ s.description = %q{The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner}
6
+ s.email = %q{software-signing@phusion.nl}
7
+ s.homepage = %q{https://github.com/gitlabhq/default_value_for}
8
+ s.authors = ["Hongli Lai"]
9
+ s.license = 'MIT'
10
+ s.required_ruby_version = '>= 1.9.3'
11
+ s.files = ['default_value_for.gemspec',
12
+ 'LICENSE.TXT', 'Rakefile', 'README.md', 'test.rb',
13
+ 'init.rb',
14
+ 'lib/default_value_for.rb',
15
+ 'lib/default_value_for/railtie.rb'
16
+ ]
17
+ s.add_dependency 'activerecord', '>= 3.2.0', '< 6.0'
18
+ s.add_development_dependency 'railties', '>= 3.2.0', '< 6.0'
19
+ s.add_development_dependency 'minitest', '>= 4.2'
20
+ s.add_development_dependency 'minitest-around'
21
+ s.add_development_dependency 'appraisal'
22
+ end
data/init.rb ADDED
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2008, 2009, 2010 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'default_value_for'
@@ -0,0 +1,201 @@
1
+ # Copyright (c) 2008-2012 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module DefaultValueFor
22
+ class NormalValueContainer
23
+ def initialize(value)
24
+ @value = value
25
+ end
26
+
27
+ def evaluate(instance)
28
+ if @value.duplicable?
29
+ return @value.dup
30
+ else
31
+ return @value
32
+ end
33
+ end
34
+ end
35
+
36
+ class BlockValueContainer
37
+ def initialize(block)
38
+ @block = block
39
+ end
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
49
+
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
60
+ allows_nil = true
61
+
62
+ if options.is_a?(Hash)
63
+ opts = options.stringify_keys
64
+ value = opts.fetch('value', options)
65
+ allows_nil = opts.fetch('allows_nil', true)
66
+ end
67
+
68
+ if !method_defined?(:set_default_values)
69
+ include(InstanceMethods)
70
+
71
+ after_initialize :set_default_values
72
+
73
+ class_attribute :_default_attribute_values
74
+ class_attribute :_default_attribute_values_not_allowing_nil
75
+
76
+ extend(DelayedClassMethods)
77
+ init_hash = true
78
+ else
79
+ init_hash = !singleton_methods(false).include?(:_default_attribute_values)
80
+ end
81
+
82
+ if init_hash
83
+ self._default_attribute_values = {}
84
+ self._default_attribute_values_not_allowing_nil = []
85
+ end
86
+
87
+ if block_given?
88
+ container = BlockValueContainer.new(block)
89
+ else
90
+ container = NormalValueContainer.new(value)
91
+ end
92
+ _default_attribute_values[attribute.to_s] = container
93
+ _default_attribute_values_not_allowing_nil << attribute.to_s unless allows_nil
94
+ end
95
+
96
+ def default_values(values)
97
+ values.each_pair do |key, options|
98
+ options = options.stringify_keys if options.is_a?(Hash)
99
+
100
+ value = options.is_a?(Hash) && options.has_key?('value') ? options['value'] : options
101
+
102
+ if value.kind_of? Proc
103
+ default_value_for(key, options.is_a?(Hash) ? options : {}, &value)
104
+ else
105
+ default_value_for(key, options)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ module DelayedClassMethods
112
+ def _all_default_attribute_values
113
+ return _default_attribute_values unless superclass.respond_to?(:_default_attribute_values)
114
+ superclass._all_default_attribute_values.merge(_default_attribute_values)
115
+ end
116
+
117
+ def _all_default_attribute_values_not_allowing_nil
118
+ return _default_attribute_values_not_allowing_nil unless superclass.respond_to?(:_default_attribute_values_not_allowing_nil)
119
+ result = superclass._all_default_attribute_values_not_allowing_nil + _default_attribute_values_not_allowing_nil
120
+ result.uniq!
121
+ result
122
+ end
123
+ end
124
+
125
+ module InstanceMethods
126
+ def initialize(attributes = nil, options = {})
127
+ attributes = attributes.to_h if attributes.is_a?(ActionController::Parameters)
128
+ @initialization_attributes = attributes.is_a?(Hash) ? attributes.stringify_keys : {}
129
+
130
+ unless options[:without_protection]
131
+ if respond_to?(:mass_assignment_options, true) && options.has_key?(:as)
132
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes, options[:as])
133
+ elsif respond_to?(:sanitize_for_mass_assignment, true)
134
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes)
135
+ else
136
+ @initialization_attributes = remove_attributes_protected_from_mass_assignment(@initialization_attributes)
137
+ end
138
+ end
139
+
140
+ if self.class.respond_to? :protected_attributes
141
+ super(attributes, options)
142
+ else
143
+ super(attributes)
144
+ end
145
+ end
146
+
147
+ def attributes_for_create(attribute_names)
148
+ attribute_names += self.class._all_default_attribute_values.keys.map(&:to_s).find_all { |name|
149
+ self.class.columns_hash.key?(name)
150
+ }
151
+ super
152
+ end
153
+
154
+ def set_default_values
155
+ self.class._all_default_attribute_values.each do |attribute, container|
156
+ next unless new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
157
+
158
+ connection_default_value_defined = new_record? && respond_to?("#{attribute}_changed?") && !__send__("#{attribute}_changed?")
159
+
160
+ attribute_blank = if attributes.has_key?(attribute)
161
+ column = self.class.columns_hash[attribute]
162
+ if column && column.type == :boolean
163
+ attributes[attribute].nil?
164
+ else
165
+ attributes[attribute].blank?
166
+ end
167
+ elsif respond_to?(attribute)
168
+ send(attribute).nil?
169
+ else
170
+ instance_variable_get("@#{attribute}").nil?
171
+ end
172
+ next unless connection_default_value_defined || attribute_blank
173
+
174
+ # allow explicitly setting nil through allow nil option
175
+ next if @initialization_attributes.is_a?(Hash) &&
176
+ (
177
+ @initialization_attributes.has_key?(attribute) ||
178
+ (
179
+ @initialization_attributes.has_key?("#{attribute}_attributes") &&
180
+ nested_attributes_options.stringify_keys[attribute]
181
+ )
182
+ ) &&
183
+ !self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
184
+
185
+ __send__("#{attribute}=", container.evaluate(self))
186
+ if respond_to?(:clear_attribute_changes, true)
187
+ clear_attribute_changes [attribute] if has_attribute?(attribute)
188
+ else
189
+ changed_attributes.delete(attribute)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ if defined?(Rails::Railtie)
197
+ require 'default_value_for/railtie'
198
+ else
199
+ # For anybody is using AS and AR without Railties, i.e. Padrino.
200
+ ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
201
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2008, 2009, 2010, 2011 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module DefaultValueFor
22
+ def self.initialize_railtie
23
+ ActiveSupport.on_load :active_record do
24
+ DefaultValueFor.initialize_active_record_extensions
25
+ end
26
+ end
27
+
28
+ def self.initialize_active_record_extensions
29
+ ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
30
+ end
31
+
32
+ class Railtie < Rails::Railtie
33
+ initializer 'default_value_for.insert_into_active_record' do
34
+ DefaultValueFor.initialize_railtie
35
+ end
36
+ end
37
+ end
data/test.rb ADDED
@@ -0,0 +1,395 @@
1
+ # Copyright (c) 2008-2012 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'bundler/setup'
22
+ require 'minitest/autorun'
23
+ require 'minitest/around/unit'
24
+ require 'active_record'
25
+
26
+ if ActiveSupport::VERSION::MAJOR == 3
27
+ require 'active_support/core_ext/logger'
28
+ end
29
+
30
+ begin
31
+ TestCaseClass = MiniTest::Test
32
+ rescue NameError
33
+ TestCaseClass = MiniTest::Unit::TestCase
34
+ end
35
+
36
+ require 'default_value_for'
37
+
38
+ puts "\nTesting with Active Record version #{ActiveRecord::VERSION::STRING}\n\n"
39
+
40
+ ActiveRecord::Base.default_timezone = :local
41
+ ActiveRecord::Base.logger = Logger.new(STDERR)
42
+ ActiveRecord::Base.logger.level = Logger::WARN
43
+
44
+ ActiveRecord::Base.establish_connection(
45
+ :adapter => RUBY_PLATFORM == 'java' ? 'jdbcsqlite3' : 'sqlite3',
46
+ :database => ':memory:'
47
+ )
48
+
49
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
50
+ t.string :username
51
+ t.integer :default_number
52
+ t.text :settings
53
+ end
54
+
55
+ ActiveRecord::Base.connection.create_table(:books, :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
61
+ t.text :stuff
62
+ t.boolean :flag
63
+ end
64
+
65
+ if defined?(Rails::Railtie)
66
+ DefaultValueFor.initialize_railtie
67
+ DefaultValueFor.initialize_active_record_extensions
68
+ end
69
+
70
+ class DefaultValuePluginTest < TestCaseClass
71
+ def around
72
+ Object.const_set(:User, Class.new(ActiveRecord::Base))
73
+ Object.const_set(:Book, Class.new(ActiveRecord::Base))
74
+ Object.const_set(:Novel, Class.new(Book))
75
+ User.has_many :books
76
+ Book.belongs_to :user
77
+
78
+ ActiveRecord::Base.transaction do
79
+ yield
80
+ raise ActiveRecord::Rollback
81
+ end
82
+ ensure
83
+ Object.send(:remove_const, :User)
84
+ Object.send(:remove_const, :Book)
85
+ Object.send(:remove_const, :Novel)
86
+ ActiveSupport::Dependencies.clear
87
+ end
88
+
89
+ def test_default_value_on_attribute_methods
90
+ Book.class_eval do
91
+ serialize :stuff
92
+ default_value_for :color, :green
93
+ def color; (self.stuff || {})[:color]; end
94
+ def color=(val)
95
+ self.stuff ||= {}
96
+ self.stuff[:color] = val
97
+ end
98
+ end
99
+ assert_equal :green, Book.create.color
100
+ end
101
+
102
+ def test_default_value_can_be_passed_as_argument
103
+ Book.default_value_for(:number, 1234)
104
+ assert_equal 1234, Book.new.number
105
+ end
106
+
107
+ def test_default_value_can_be_passed_as_block
108
+ Book.default_value_for(:number) { 1234 }
109
+ assert_equal 1234, Book.new.number
110
+ end
111
+
112
+ def test_works_with_create
113
+ Book.default_value_for :number, 1234
114
+
115
+ object = Book.create
116
+ refute_nil Book.find_by_number(1234)
117
+
118
+ # allows nil for existing records
119
+ object.update_attribute(:number, nil)
120
+ assert_nil Book.find_by_number(1234)
121
+ assert_nil Book.find(object.id).number
122
+ end
123
+
124
+ def test_does_not_allow_nil_sets_default_value_on_existing_nils
125
+ Book.default_value_for(:number, :allows_nil => false) { 1234 }
126
+ object = Book.create
127
+ object.update_attribute(:number, nil)
128
+ assert_nil Book.find_by_number(1234)
129
+ assert_equal 1234, Book.find(object.id).number
130
+ end
131
+
132
+ def test_overwrites_db_default
133
+ Book.default_value_for :count, 1234
134
+ assert_equal 1234, Book.new.count
135
+ end
136
+
137
+ def test_doesnt_overwrite_values_provided_by_mass_assignment
138
+ Book.default_value_for :number, 1234
139
+ assert_equal 1, Book.new(:number => 1, :count => 2).number
140
+ end
141
+
142
+ def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
143
+ Book.default_value_for :timestamp, Time.mktime(2000, 1, 1)
144
+ timestamp = Time.mktime(2009, 1, 1)
145
+ object = Book.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
146
+ assert_equal timestamp, object.timestamp
147
+ end
148
+
149
+ def test_doesnt_overwrite_values_provided_by_constructor_block
150
+ Book.default_value_for :number, 1234
151
+ object = Book.new do |x|
152
+ x.number = 1
153
+ x.count = 2
154
+ end
155
+ assert_equal 1, object.number
156
+ end
157
+
158
+ def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
159
+ Book.default_value_for :number, 1234
160
+ assert_nil Book.new(:number => nil).number
161
+ end
162
+
163
+ def test_overwrites_explicitly_provided_nil_values_in_mass_assignment
164
+ Book.default_value_for :number, :value => 1234, :allows_nil => false
165
+ assert_equal 1234, Book.new(:number => nil).number
166
+ end
167
+
168
+ def test_default_values_are_inherited
169
+ Book.default_value_for :number, 1234
170
+ assert_equal 1234, Novel.new.number
171
+ end
172
+
173
+ def test_default_values_in_superclass_are_saved_in_subclass
174
+ Book.default_value_for :number, 1234
175
+ Novel.default_value_for :flag, true
176
+ object = Novel.create!
177
+ assert_equal object.id, Novel.find_by_number(1234).id
178
+ assert_equal object.id, Novel.find_by_flag(true).id
179
+ end
180
+
181
+ def test_default_values_in_subclass
182
+ Novel.default_value_for :number, 5678
183
+ assert_equal 5678, Novel.new.number
184
+ assert_nil Book.new.number
185
+ end
186
+
187
+ def test_multiple_default_values_in_subclass_with_default_values_in_parent_class
188
+ Book.class_eval do
189
+ default_value_for :other_number, nil
190
+ attr_accessor :other_number
191
+ end
192
+ Novel.default_value_for :number, 5678
193
+
194
+ # Ensure second call in this class doesn't reset _default_attribute_values,
195
+ # and also doesn't consider the parent class' _default_attribute_values when
196
+ # making that check.
197
+ Novel.default_value_for :user_id, 9999
198
+
199
+ object = Novel.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
+ Book.default_value_for :number, 1234
207
+ Novel.default_value_for :number, 5678
208
+ assert_equal 5678, Novel.new.number
209
+ assert_equal 1234, Book.new.number
210
+ end
211
+
212
+ def test_default_values_in_subclass_do_not_affect_parent_class
213
+ Book.default_value_for :number, 1234
214
+ Novel.class_eval do
215
+ default_value_for :hello, "hi"
216
+ attr_accessor :hello
217
+ end
218
+
219
+ assert Book.new
220
+ assert !Book._default_attribute_values.include?(:hello)
221
+ end
222
+
223
+ def test_doesnt_set_default_on_saved_records
224
+ Book.create(:number => 9876)
225
+ Book.default_value_for :number, 1234
226
+ assert_equal 9876, Book.first.number
227
+ end
228
+
229
+ def test_also_works_on_attributes_that_arent_database_columns
230
+ Book.class_eval do
231
+ default_value_for :hello, "hi"
232
+ attr_accessor :hello
233
+ end
234
+ assert_equal 'hi', Book.new.hello
235
+ end
236
+
237
+ def test_works_on_attributes_that_only_have_writers
238
+ Book.class_eval do
239
+ default_value_for :hello, "hi"
240
+ attr_writer :hello
241
+ end
242
+ assert_equal 'hi', Book.new.instance_variable_get('@hello')
243
+ end
244
+
245
+ def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
246
+ Book.class_eval do
247
+ def initialize(attrs = {})
248
+ @initialized = true
249
+ super(:count => 5678)
250
+ end
251
+
252
+ default_value_for :number, 1234
253
+ end
254
+ object = Book.new
255
+ assert_equal 1234, object.number
256
+ assert_equal 5678, object.count
257
+ assert object.instance_variable_get('@initialized')
258
+ end
259
+
260
+ def test_model_instance_is_passed_to_the_given_block
261
+ instance = nil
262
+ Book.default_value_for :number do |n|
263
+ instance = n
264
+ end
265
+ object = Book.new
266
+ assert_same object.object_id, instance.object_id
267
+ end
268
+
269
+ def test_can_specify_default_value_via_association
270
+ user = User.create(:username => 'Kanako', :default_number => 123)
271
+ Book.default_value_for :number do |n|
272
+ n.user.default_number
273
+ end
274
+ assert_equal 123, user.books.create!.number
275
+ end
276
+
277
+ def test_default_values
278
+ Book.default_values({
279
+ :type => "normal",
280
+ :number => lambda { 10 + 5 },
281
+ :timestamp => lambda {|_| Time.now }
282
+ })
283
+
284
+ object = Book.new
285
+ assert_equal("normal", object.type)
286
+ assert_equal(15, object.number)
287
+ end
288
+
289
+ def test_default_value_order
290
+ Book.default_value_for :count, 5
291
+ Book.default_value_for :number do |this|
292
+ this.count * 2
293
+ end
294
+ object = Book.new
295
+ assert_equal(5, object.count)
296
+ assert_equal(10, object.number)
297
+ end
298
+
299
+ def test_attributes_with_default_values_are_not_marked_as_changed
300
+ Book.default_value_for :count, 5
301
+ Book.default_value_for :number, 2
302
+
303
+ object = Book.new
304
+ assert(!object.changed?)
305
+ assert_equal([], object.changed)
306
+
307
+ object.type = "foo"
308
+ assert(object.changed?)
309
+ assert_equal(["type"], object.changed)
310
+ end
311
+
312
+ def test_default_values_are_duplicated
313
+ User.default_value_for :username, "hello"
314
+ user1 = User.new
315
+ user1.username << " world"
316
+ user2 = User.new
317
+ assert_equal("hello", user2.username)
318
+ end
319
+
320
+ def test_default_values_are_shallow_copied
321
+ User.class_eval do
322
+ attr_accessor :hash
323
+ default_value_for :hash, { 1 => [] }
324
+ end
325
+ user1 = User.new
326
+ user1.hash[1] << 1
327
+ user2 = User.new
328
+ assert_equal([1], user2.hash[1])
329
+ end
330
+
331
+ def test_constructor_does_not_affect_the_hash_passed_to_it
332
+ Book.default_value_for :count, 5
333
+ options = { :count => 5, :user_id => 1 }
334
+ options_dup = options.dup
335
+ Book.new(options)
336
+ assert_equal(options_dup, options)
337
+ end
338
+
339
+ def test_subclass_find
340
+ Book.default_value_for :number, 5678
341
+ n = Novel.create
342
+ assert Novel.find(n.id)
343
+ end
344
+
345
+ def test_does_not_see_false_as_blank_at_boolean_columns_for_existing_records
346
+ Book.default_value_for(:flag, :allows_nil => false) { true }
347
+
348
+ object = Book.create
349
+
350
+ # allows nil for existing records
351
+ object.update_attribute(:flag, false)
352
+ assert_equal false, Book.find(object.id).flag
353
+ end
354
+
355
+ def test_works_with_nested_attributes
356
+ User.accepts_nested_attributes_for :books
357
+ User.default_value_for :books do
358
+ [Book.create!(:number => 0)]
359
+ end
360
+
361
+ user = User.create! :books_attributes => [{:number => 1}]
362
+ assert_equal 1, Book.all.first.number
363
+ end
364
+
365
+ def test_works_with_stored_attribute_accessors_when_initializing_value_that_does_not_allow_nil
366
+ User.store :settings, :accessors => :bio
367
+ User.default_value_for :bio, :value => 'None given', :allows_nil => false
368
+
369
+ user = User.create!(:bio => 'This is a bio')
370
+ assert_equal 'This is a bio', user.bio
371
+ end
372
+
373
+ if ActiveRecord::VERSION::MAJOR == 3
374
+ def test_constructor_ignores_forbidden_mass_assignment_attributes
375
+ Book.class_eval do
376
+ default_value_for :number, 1234
377
+ attr_protected :number
378
+ end
379
+ object = Book.new(:number => 5678, :count => 987)
380
+ assert_equal 1234, object.number
381
+ assert_equal 987, object.count
382
+ end
383
+
384
+ def test_constructor_respects_without_protection_option
385
+ Book.class_eval do
386
+ default_value_for :number, 1234
387
+ attr_protected :number
388
+ end
389
+
390
+ object = Book.create!({:number => 5678, :count => 987}, :without_protection => true)
391
+ assert_equal 5678, object.number
392
+ assert_equal 987, object.count
393
+ end
394
+ end
395
+ end