default_value_for 0.1.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.
Files changed (8) hide show
  1. data/.gitignore +1 -0
  2. data/LICENSE.TXT +19 -0
  3. data/README.rdoc +421 -0
  4. data/Rakefile +27 -0
  5. data/VERSION +1 -0
  6. data/init.rb +1 -0
  7. data/test.rb +279 -0
  8. metadata +62 -0
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ test.sqlite3
data/LICENSE.TXT ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 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.
data/README.rdoc ADDED
@@ -0,0 +1,421 @@
1
+ = Introduction
2
+
3
+ The default_value_for plugin allows one to define default values for ActiveRecord
4
+ models in a declarative manner. For example:
5
+
6
+ class User < ActiveRecord::Base
7
+ default_value_for :name, "(no name)"
8
+ default_value_for :last_seen do
9
+ Time.now
10
+ end
11
+ end
12
+
13
+ u = User.new
14
+ u.name # => "(no name)"
15
+ u.last_seen # => Mon Sep 22 17:28:38 +0200 2008
16
+
17
+ *Note*: critics might be interested in the "When (not) to use default_value_for?"
18
+ section. Please read on.
19
+
20
+
21
+ == Installation
22
+
23
+ Install with:
24
+
25
+ ./script/plugin install git://github.com/FooBarWidget/default_value_for.git
26
+
27
+
28
+ == The default_value_for method
29
+
30
+ The +default_value_for+ method is available in all ActiveRecord model classes.
31
+
32
+ The first argument is the name of the attribute for which a default value should
33
+ be set. This may either be a Symbol or a String.
34
+
35
+ The default value itself may either be passed as the second argument:
36
+
37
+ default_value_for :age, 20
38
+
39
+ ...or it may be passed as the return value of a block:
40
+
41
+ default_value_for :age do
42
+ if today_is_sunday?
43
+ 20
44
+ else
45
+ 30
46
+ end
47
+ end
48
+
49
+ If you pass a value argument, then the default value is static and never
50
+ changes. However, if you pass a block, then the default value is retrieved by
51
+ calling the block. This block is called not once, but every time a new record is
52
+ instantiated and default values need to be filled in.
53
+
54
+ The latter form is especially useful if your model has a UUID column. One can
55
+ generate a new, random UUID for every newly instantiated record:
56
+
57
+ class User < ActiveRecord::Base
58
+ default_value_for :uuid do
59
+ UuidGenerator.new.generate_uuid
60
+ end
61
+ end
62
+
63
+ User.new.uuid # => "51d6d6846f1d1b5c9a...."
64
+ User.new.uuid # => "ede292289e3484cb88...."
65
+
66
+ Note that record is passed to the block as an argument, in case you need it for
67
+ whatever reason:
68
+
69
+ class User < ActiveRecord::Base
70
+ default_value_for :uuid do |x|
71
+ x # <--- a User object
72
+ UuidGenerator.new.generate_uuid
73
+ end
74
+ end
75
+
76
+ == The default_values method
77
+
78
+ As a shortcut, you can use +default_values+ to set multiple default values at once.
79
+
80
+ default_values :age => 20
81
+ :uuid => lambda { UuidGenerator.new.generate_uuid }
82
+
83
+ 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.
84
+
85
+ As a side note, due to specifics of Ruby's parser, you cannot say,
86
+
87
+ default_value :uuid { UuidGenerator.new.generate_uuid }
88
+
89
+ because it will not parse. This is in part the inspiration for the +default_values+ syntax.
90
+
91
+ == Rules
92
+
93
+ === Instantiation of new record
94
+
95
+ Upon instantiating a new record, the declared default values are filled into
96
+ the record. You've already seen this in the above examples.
97
+
98
+ === Retrieval of existing record
99
+
100
+ Upon retrieving an existing record, the declared default values are _not_
101
+ filled into the record. Consider the example with the UUID:
102
+
103
+ user = User.create
104
+ user.uuid # => "529c91b8bbd3e..."
105
+
106
+ user = User.find(user.id)
107
+ # UUID remains unchanged because it's retrieved from the database!
108
+ user.uuid # => "529c91b8bbd3e..."
109
+
110
+ === Mass-assignment
111
+
112
+ If a certain attribute is being assigned via the model constructor's
113
+ mass-assignment argument, that the default value for that attribute will _not_
114
+ be filled in:
115
+
116
+ user = User.new(:uuid => "hello")
117
+ user.uuid # => "hello"
118
+
119
+ However, if that attribute is protected by +attr_protected+ or +attr_accessible+,
120
+ then it will be filled in:
121
+
122
+ class User < ActiveRecord::Base
123
+ default_value_for :name, 'Joe'
124
+ attr_protected :name
125
+ end
126
+
127
+ user = User.new(:name => "Jane")
128
+ user.name # => "Joe"
129
+
130
+ === Inheritance
131
+
132
+ Inheritance works as expected. All default values are inherited by the child
133
+ class:
134
+
135
+ class User < ActiveRecord::Base
136
+ default_value_for :name, 'Joe'
137
+ end
138
+
139
+ class SuperUser < User
140
+ end
141
+
142
+ SuperUser.new.name # => "Joe"
143
+
144
+ === Attributes that aren't database columns
145
+
146
+ +default_value_for+ also works with attributes that aren't database columns.
147
+ It works with anything for which there's an assignment method:
148
+
149
+ # Suppose that your 'users' table only has a 'name' column.
150
+ class User < ActiveRecord::Base
151
+ default_value_for :name, 'Joe'
152
+ default_value_for :age, 20
153
+ default_value_for :registering, true
154
+
155
+ attr_accessor :age
156
+
157
+ def registering=(value)
158
+ @registering = true
159
+ end
160
+ end
161
+
162
+ user = User.new
163
+ user.age # => 20
164
+ user.instance_variable_get('@registering') # => true
165
+
166
+ === Default values are *not* duplicated
167
+
168
+ The given default values are *not* duplicated when they are filled in, so if
169
+ you mutate a value that was filled in with a default value, then it will affect
170
+ all subsequent default values:
171
+
172
+ class Author < ActiveRecord::Base
173
+ # This model only has a 'name' attribute.
174
+ end
175
+
176
+ class Book < ActiveRecord::Base
177
+ belongs_to :author
178
+
179
+ # By default, a Book belongs to a new, unsaved author.
180
+ default_value_for :author, Author.new
181
+ end
182
+
183
+ book1 = Book.new
184
+ book1.author.name # => nil
185
+ # This mutates the default value:
186
+ book1.author.name = "John"
187
+
188
+ book2 = Book.new
189
+ book2.author.name # => "John"
190
+
191
+ You can prevent this from happening by passing a block to +default_value_for+,
192
+ which returns a new object instance every time:
193
+
194
+ class Book < ActiveRecord::Base
195
+ belongs_to :author
196
+
197
+ default_value_for :author do
198
+ Author.new
199
+ end
200
+ end
201
+
202
+ book1 = Book.new
203
+ book1.author.name # => nil
204
+ book1.author.name = "John"
205
+
206
+ book2 = Book.new
207
+ book2.author.name # => nil
208
+
209
+ The main reason why default values are not duplicated is because not all
210
+ objects can be duplicated. For example, +Fixnum+ responds to +dup+, but calling
211
+ +dup+ on a Fixnum will raise an exception.
212
+
213
+ === Caveats
214
+
215
+ A conflict can occur if your model class overrides the 'initialize' method,
216
+ because this plugin overrides 'initialize' as well to do its job.
217
+
218
+ class User < ActiveRecord::Base
219
+ def initialize # <-- this constructor causes problems
220
+ super(:name => 'Name cannot be changed in constructor')
221
+ end
222
+ end
223
+
224
+ We recommend you to alias chain your initialize method in models where you use
225
+ +default_value_for+:
226
+
227
+ class User < ActiveRecord::Base
228
+ default_value_for :age, 20
229
+
230
+ def initialize_with_my_app
231
+ initialize_without_my_app(:name => 'Name cannot be changed in constructor')
232
+ end
233
+
234
+ alias_method_chain :initialize, :my_app
235
+ end
236
+
237
+ Also, stick with the following rules:
238
+ - There is no need to +alias_method_chain+ your initialize method in models that
239
+ don't use +default_value_for+.
240
+ - Make sure that +alias_method_chain+ is called *after* the last
241
+ +default_value_for+ occurance.
242
+
243
+
244
+ == When (not) to use default_value_for?
245
+
246
+ You can also specify default values in the database schema. For example, you
247
+ can specify a default value in a migration as follows:
248
+
249
+ create_table :users do |t|
250
+ t.string :username, :null => false, :default => 'default username'
251
+ t.integer :age, :null => false, :default => 20
252
+ t.timestamp :last_seen, :null => false, :default => Time.now
253
+ end
254
+
255
+ This has the same effect as passing the default value as the second argument to
256
+ +default_value_for+:
257
+
258
+ user = User.new
259
+ user.username # => 'default username'
260
+ user.age # => 20
261
+ user.timestamp # => Mon Sep 22 18:31:47 +0200 2008
262
+
263
+ It's recommended that you use this over +default_value_for+ whenever possible.
264
+
265
+ However, it's not possible to specify a schema default for serialized columns.
266
+ With +default_value_for+, you can:
267
+
268
+ class User < ActiveRecord::Base
269
+ serialize :color
270
+ default_value_for :color, [255, 0, 0]
271
+ end
272
+
273
+ And if schema defaults don't provide the flexibility that you need, then
274
+ +default_value_for+ is the perfect choice. For example, with +default_value_for+
275
+ you could specify a per-environment default:
276
+
277
+ class User < ActiveRecord::Base
278
+ if RAILS_ENV == "development"
279
+ default_value_for :is_admin, true
280
+ end
281
+ end
282
+
283
+ Or, as you've seen in an earlier example, you can use +default_value_for+ to
284
+ generate a default random UUID:
285
+
286
+ class User < ActiveRecord::Base
287
+ default_value_for :uuid do
288
+ UuidGenerator.new.generate_uuid
289
+ end
290
+ end
291
+
292
+ Or you could use it to generate a timestamp that's relative to the time at which
293
+ the record is instantiated:
294
+
295
+ class User < ActiveRecord::Base
296
+ default_value_for :account_expires_at do
297
+ 3.years.from_now
298
+ end
299
+ end
300
+
301
+ User.new.account_expires_at # => Mon Sep 22 18:43:42 +0200 2008
302
+ sleep(2)
303
+ User.new.account_expires_at # => Mon Sep 22 18:43:44 +0200 2008
304
+
305
+ Finally, it's also possible to specify a default via an association:
306
+
307
+ # Has columns: 'name' and 'default_price'
308
+ class SuperMarket < ActiveRecord::Base
309
+ has_many :products
310
+ end
311
+
312
+ # Has columns: 'name' and 'price'
313
+ class Product < ActiveRecord::Base
314
+ belongs_to :super_market
315
+
316
+ default_value_for :price do |product|
317
+ product.super_market.default_price
318
+ end
319
+ end
320
+
321
+ super_market = SuperMarket.create(:name => 'Albert Zwijn', :default_price => 100)
322
+ soap = super_market.products.create(:name => 'Soap')
323
+ soap.price # => 100
324
+
325
+ === What about before_validate/before_save?
326
+
327
+ True, +before_validate+ and +before_save+ does what we want if we're only
328
+ interested in filling in a default before saving. However, if one wants to be
329
+ able to access the default value even before saving, then be prepared to write
330
+ a lot of code. Suppose that we want to be able to access a new record's UUID,
331
+ even before it's saved. We could end up with the following code:
332
+
333
+ # In the controller
334
+ def create
335
+ @user = User.new(params[:user])
336
+ @user.generate_uuid
337
+ email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
338
+ @user.save!
339
+ end
340
+
341
+ # Model
342
+ class User < ActiveRecord::Base
343
+ before_save :generate_uuid_if_necessary
344
+
345
+ def generate_uuid
346
+ self.uuid = ...
347
+ end
348
+
349
+ private
350
+ def generate_uuid_if_necessary
351
+ if uuid.blank?
352
+ generate_uuid
353
+ end
354
+ end
355
+ end
356
+
357
+ The need to manually call +generate_uuid+ here is ugly, and one can easily forget
358
+ to do that. Can we do better? Let's see:
359
+
360
+ # Controller
361
+ def create
362
+ @user = User.new(params[:user])
363
+ email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
364
+ @user.save!
365
+ end
366
+
367
+ # Model
368
+ class User < ActiveRecord::Base
369
+ before_save :generate_uuid_if_necessary
370
+
371
+ def uuid
372
+ value = read_attribute('uuid')
373
+ if !value
374
+ value = generate_uuid
375
+ write_attribute('uuid', value)
376
+ end
377
+ value
378
+ end
379
+
380
+ # We need to override this too, otherwise User.new.attributes won't return
381
+ # a default UUID value. I've never tested with User.create() so maybe we
382
+ # need to override even more things.
383
+ def attributes
384
+ uuid
385
+ super
386
+ end
387
+
388
+ private
389
+ def generate_uuid_if_necessary
390
+ uuid # Reader method automatically generates UUID if it doesn't exist
391
+ end
392
+ end
393
+
394
+ That's an awful lot of code. Using +default_value_for+ is easier, don't you think?
395
+
396
+ === What about other plugins?
397
+
398
+ I've only been able to find 2 similar plugins:
399
+
400
+ - Default Value: http://agilewebdevelopment.com/plugins/default_value
401
+ - ActiveRecord Defaults: http://agilewebdevelopment.com/plugins/activerecord_defaults
402
+
403
+ 'Default Value' appears to be unmaintained; its SVN link is broken. This leaves
404
+ only 'ActiveRecord Defaults'. However, it is semantically dubious, which leaves
405
+ it wide open for corner cases. For example, it is not clearly specified what
406
+ ActiveRecord Defaults will do when attributes are protected by +attr_protected+
407
+ or +attr_accessible+. It is also not clearly specified what one is supposed to
408
+ do if one needs a custom +initialize+ method in the model.
409
+
410
+ I've taken my time to thoroughly document default_value_for's behavior.
411
+
412
+
413
+ == Credits
414
+
415
+ I've wanted such functionality for a while now and it baffled me that ActiveRecord
416
+ doesn't provide a clean way for me to specify default values. After reading
417
+ http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935,
418
+ it became clear that someone needs to write a plugin. This is the result.
419
+
420
+ Thanks to Pratik Naik for providing the initial code snippet on which this plugin
421
+ is based on: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'rake'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'rake'
6
+ end
7
+
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gemspec|
11
+ gemspec.name = "default_value_for"
12
+ gemspec.summary = "Provides a way to specify default values for ActiveRecord models"
13
+ gemspec.description = "The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner"
14
+ gemspec.email = "info@phusion.nl"
15
+ gemspec.homepage = "http://github.com/FooBarWidget/default_value_for"
16
+ gemspec.authors = ["Hongli Lai"]
17
+ end
18
+ rescue LoadError
19
+ puts "default_value_for not available. Install it with: sudo gem install default_value_for"
20
+ end
21
+
22
+ task :default => :test
23
+
24
+ desc "Run unit tests."
25
+ task :test do
26
+ ruby "test.rb"
27
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'lib/default_value_for.rb'
data/test.rb ADDED
@@ -0,0 +1,279 @@
1
+ # Copyright (c) 2008, 2009 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 'rubygems'
22
+ require 'active_record'
23
+ require 'test/unit'
24
+ require File.dirname(__FILE__) + '/init'
25
+ Dir.chdir(File.dirname(__FILE__))
26
+
27
+ if RUBY_PLATFORM == "java"
28
+ database_adapter = "jdbcsqlite3"
29
+ else
30
+ database_adapter = "sqlite3"
31
+ end
32
+
33
+ File.unlink('test.sqlite3') rescue nil
34
+ ActiveRecord::Base.logger = Logger.new(STDERR)
35
+ ActiveRecord::Base.logger.level = Logger::WARN
36
+ ActiveRecord::Base.establish_connection(
37
+ :adapter => database_adapter,
38
+ :database => 'test.sqlite3'
39
+ )
40
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
41
+ t.string :username
42
+ t.integer :default_number
43
+ end
44
+ ActiveRecord::Base.connection.create_table(:numbers, :force => true) do |t|
45
+ t.string :type
46
+ t.integer :number
47
+ t.integer :count, :null => false, :default => 1
48
+ t.integer :user_id
49
+ t.timestamp :timestamp
50
+ end
51
+
52
+ class User < ActiveRecord::Base
53
+ has_many :numbers, :class_name => 'TestClass'
54
+ end
55
+
56
+ class Number < ActiveRecord::Base
57
+ end
58
+
59
+ class DefaultValuePluginTest < Test::Unit::TestCase
60
+ def setup
61
+ Number.create(:number => 9876)
62
+ end
63
+
64
+ def teardown
65
+ Number.delete_all
66
+ end
67
+
68
+ def define_model_class(name = "TestClass", parent_class_name = "ActiveRecord::Base", &block)
69
+ Object.send(:remove_const, name) rescue nil
70
+ eval("class #{name} < #{parent_class_name}; end", TOPLEVEL_BINDING)
71
+ klass = eval(name, TOPLEVEL_BINDING)
72
+ klass.class_eval do
73
+ set_table_name 'numbers'
74
+ end
75
+ klass.class_eval(&block) if block_given?
76
+ end
77
+
78
+ def test_default_value_can_be_passed_as_argument
79
+ define_model_class do
80
+ default_value_for(:number, 1234)
81
+ end
82
+ object = TestClass.new
83
+ assert_equal 1234, object.number
84
+ end
85
+
86
+ def test_default_value_can_be_passed_as_block
87
+ define_model_class do
88
+ default_value_for(:number) { 1234 }
89
+ end
90
+ object = TestClass.new
91
+ assert_equal 1234, object.number
92
+ end
93
+
94
+ def test_works_with_create
95
+ define_model_class do
96
+ default_value_for :number, 1234
97
+ end
98
+ TestClass.create
99
+ assert_not_nil TestClass.find_by_number(1234)
100
+ end
101
+
102
+ def test_overwrites_db_default
103
+ define_model_class do
104
+ default_value_for :count, 1234
105
+ end
106
+ object = TestClass.new
107
+ assert_equal 1234, object.count
108
+ end
109
+
110
+ def test_doesnt_overwrite_values_provided_by_mass_assignment
111
+ define_model_class do
112
+ default_value_for :number, 1234
113
+ end
114
+ object = TestClass.new(:number => 1, :count => 2)
115
+ assert_equal 1, object.number
116
+ end
117
+
118
+ def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
119
+ define_model_class do
120
+ default_value_for :timestamp, Time.mktime(2000, 1, 1)
121
+ end
122
+ timestamp = Time.mktime(2009, 1, 1)
123
+ object = TestClass.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
124
+ assert_equal timestamp, object.timestamp
125
+ end
126
+
127
+ def test_doesnt_overwrite_values_provided_by_constructor_block
128
+ define_model_class do
129
+ default_value_for :number, 1234
130
+ end
131
+ object = TestClass.new do |x|
132
+ x.number = 1
133
+ x.count = 2
134
+ end
135
+ assert_equal 1, object.number
136
+ end
137
+
138
+ def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
139
+ define_model_class do
140
+ default_value_for :number, 1234
141
+ end
142
+ object = TestClass.new(:number => nil)
143
+ assert_nil object.number
144
+ end
145
+
146
+ def test_default_values_are_inherited
147
+ define_model_class("TestSuperClass") do
148
+ default_value_for :number, 1234
149
+ end
150
+ define_model_class("TestClass", "TestSuperClass")
151
+ object = TestClass.new
152
+ assert_equal 1234, object.number
153
+ end
154
+
155
+ def test_doesnt_set_default_on_saved_records
156
+ define_model_class do
157
+ default_value_for :number, 1234
158
+ end
159
+ assert_equal 9876, TestClass.find(:first).number
160
+ end
161
+
162
+ def test_also_works_on_attributes_that_arent_database_columns
163
+ define_model_class do
164
+ default_value_for :hello, "hi"
165
+ attr_accessor :hello
166
+ end
167
+ object = TestClass.new
168
+ assert_equal 'hi', object.hello
169
+ end
170
+
171
+ def test_constructor_ignores_forbidden_mass_assignment_attributes
172
+ define_model_class do
173
+ default_value_for :number, 1234
174
+ attr_protected :number
175
+ end
176
+ object = TestClass.new(:number => 5678, :count => 987)
177
+ assert_equal 1234, object.number
178
+ assert_equal 987, object.count
179
+ end
180
+
181
+ def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
182
+ define_model_class do
183
+ def initialize(attrs = {})
184
+ @initialized = true
185
+ super(:count => 5678)
186
+ end
187
+
188
+ default_value_for :number, 1234
189
+ end
190
+ object = TestClass.new
191
+ assert_equal 1234, object.number
192
+ assert_equal 5678, object.count
193
+ assert object.instance_variable_get('@initialized')
194
+ end
195
+
196
+ def test_model_instance_is_passed_to_the_given_block
197
+ $instance = nil
198
+ define_model_class do
199
+ default_value_for :number do |n|
200
+ $instance = n
201
+ end
202
+ end
203
+ object = TestClass.new
204
+ assert_same object, $instance
205
+ end
206
+
207
+ def test_can_specify_default_value_via_association
208
+ user = User.create(:username => 'Kanako', :default_number => 123)
209
+ define_model_class do
210
+ belongs_to :user
211
+
212
+ default_value_for :number do |n|
213
+ n.user.default_number
214
+ end
215
+ end
216
+ object = user.numbers.create
217
+ assert_equal 123, object.number
218
+ end
219
+
220
+ def test_default_values
221
+ define_model_class do
222
+ default_values :type => "normal",
223
+ :number => lambda { 10 + 5 }
224
+ end
225
+
226
+ object = TestClass.new
227
+ assert_equal("normal", object.type)
228
+ assert_equal(15, object.number)
229
+ end
230
+
231
+ def test_default_value_order
232
+ define_model_class do
233
+ default_value_for :count, 5
234
+ default_value_for :number do |this|
235
+ this.count * 2
236
+ end
237
+ end
238
+ object = TestClass.new
239
+ assert_equal(5, object.count)
240
+ assert_equal(10, object.number)
241
+ end
242
+
243
+ def test_attributes_with_default_values_are_not_marked_as_changed
244
+ define_model_class do
245
+ default_value_for :count, 5
246
+ default_value_for :number, 2
247
+ end
248
+
249
+ object = TestClass.new
250
+ assert(!object.changed?)
251
+ assert_equal([], object.changed)
252
+
253
+ object.type = "foo"
254
+ assert(object.changed?)
255
+ assert_equal(["type"], object.changed)
256
+ end
257
+
258
+ def test_default_values_are_not_duplicated
259
+ define_model_class do
260
+ set_table_name "users"
261
+ default_value_for :username, "hello"
262
+ end
263
+ user1 = TestClass.new
264
+ user1.username << " world"
265
+ user2 = TestClass.new
266
+ assert_equal("hello world", user2.username)
267
+ end
268
+
269
+ def test_constructor_does_not_affect_the_hash_passed_to_it
270
+ define_model_class do
271
+ default_value_for :count, 5
272
+ end
273
+
274
+ options = { :count => 5, :user_id => 1 }
275
+ options_dup = options.dup
276
+ object = TestClass.new(options)
277
+ assert_equal(options_dup, options)
278
+ end
279
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: default_value_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hongli Lai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-20 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner
17
+ email: info@phusion.nl
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE.TXT
24
+ - README.rdoc
25
+ files:
26
+ - .gitignore
27
+ - LICENSE.TXT
28
+ - README.rdoc
29
+ - Rakefile
30
+ - VERSION
31
+ - init.rb
32
+ - test.rb
33
+ has_rdoc: true
34
+ homepage: http://github.com/FooBarWidget/default_value_for
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.3.5
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Provides a way to specify default values for ActiveRecord models
61
+ test_files: []
62
+