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