gitlab-default_value_for 3.1.1

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.
@@ -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