default_value_for 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+