attr_default 0.5.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/.gitignore +20 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/README.rdoc +106 -0
- data/Rakefile +9 -0
- data/attr_default.gemspec +20 -0
- data/lib/attr_default.rb +88 -0
- data/lib/attr_default/version.rb +3 -0
- data/test/test_attr_default.rb +255 -0
- metadata +119 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Colin Kelley, RingRevenue
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
= AttrDefault
|
2
|
+
|
3
|
+
Dynamic Ruby defaults for ActiveRecord attributes.
|
4
|
+
These are lazy evaluated just in time: when first accessed, or just before validation or save.
|
5
|
+
This allows dynamic defaults to depend on attributes that are assigned after initialization, or on other dynamic defaults.
|
6
|
+
|
7
|
+
Example:
|
8
|
+
|
9
|
+
class User < ActiveRecord::Base
|
10
|
+
attr_default :middle_name, ''
|
11
|
+
attr_default :guid, lambda { GuidGenerator.new }
|
12
|
+
attr_default :managed, lambda { organization.managed? }
|
13
|
+
|
14
|
+
belongs_to :organization
|
15
|
+
...
|
16
|
+
end
|
17
|
+
|
18
|
+
== Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
gem 'attr_default'
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install attr_default
|
31
|
+
|
32
|
+
== Usage
|
33
|
+
|
34
|
+
require 'attr_default'
|
35
|
+
|
36
|
+
This makes the +attr_default+ macro available to all objects derived fromActiveRecord::Base.
|
37
|
+
|
38
|
+
=== The attr_default Macro
|
39
|
+
|
40
|
+
The +attr_default+ macro takes 2 arguments:
|
41
|
+
|
42
|
+
[attr_name] The name of the attribute, given as a symbol or string.
|
43
|
+
[default] The default value to use, either as a simple value or a Proc. If a Proc, attr_default will call it in the context of the object.
|
44
|
+
This makes it convenient for dynamic defaults to be computed based on other attributes or associations.
|
45
|
+
|
46
|
+
+attr_default+ can be used for persistent or non-persistent attributes.
|
47
|
+
|
48
|
+
=== Timing of Default Computation
|
49
|
+
|
50
|
+
Defaults are lazy computed, just in time, whenever the first of these happens:
|
51
|
+
|
52
|
+
* The attribute is read.
|
53
|
+
* The object's before_validation callback is called.
|
54
|
+
* The object's before_save callback is called.
|
55
|
+
|
56
|
+
This allows dynamic defaults to depend on other attributes that may be assigned after the initializer, and even other dynamic defaults.
|
57
|
+
For example:
|
58
|
+
|
59
|
+
class User < ActiveRecord::Base
|
60
|
+
attr_default :first_name, 'First'
|
61
|
+
attr_default :last_name, 'Last'
|
62
|
+
attr_default :name_addr, lambda { "#{full_name} <#{email}>" }
|
63
|
+
|
64
|
+
def full_name
|
65
|
+
[first_name, middle_name, last_name].select { |name| !name.blank? } * ' '
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
user1 = User.create :email => 'joe@yahoo.com', :first_name => 'Joe'
|
70
|
+
user1.name_addr # => "Joe Last <joe@yahoo.com>"
|
71
|
+
|
72
|
+
user2 = User.create :email => 'jane@yahoo.com'
|
73
|
+
user2.last_name = 'Doe'
|
74
|
+
user2.name_addr # => "First Doe <jane@yahoo.com>"
|
75
|
+
|
76
|
+
=== Use with Hobofields
|
77
|
+
|
78
|
+
With Hobofields, defaults can be set using the +:ruby_default+ option:
|
79
|
+
|
80
|
+
class User < ActiveRecord::Base
|
81
|
+
fields do
|
82
|
+
first_name :string, :ruby_default => 'First'
|
83
|
+
last_name :string, :ruby_default => 'Last'
|
84
|
+
email :string
|
85
|
+
name_addr :string, :ruby_default => lambda { "#{full_name} <#{email}>" }
|
86
|
+
...
|
87
|
+
end
|
88
|
+
|
89
|
+
def full_name
|
90
|
+
[first_name, middle_name, last_name].select { |name| name unless name.blank? } * ' '
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
The +:default+ option controls the default in SQL, unless a Ruby Proc is given in which case it is treated as +:ruby_default+.
|
95
|
+
|
96
|
+
=== Interaction with +clone+
|
97
|
+
|
98
|
+
Dynamic defaults work with +clone+, following the same timing given above.
|
99
|
+
|
100
|
+
== Contributing
|
101
|
+
|
102
|
+
1. Fork it
|
103
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
104
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
105
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
106
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../lib/attr_default/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.add_dependency 'rake'
|
5
|
+
gem.add_dependency 'rails'
|
6
|
+
gem.add_development_dependency 'sqlite3'
|
7
|
+
gem.add_development_dependency 'hobofields'
|
8
|
+
gem.authors = ["Colin Kelley", "Nick Burwell"]
|
9
|
+
gem.email = ["colindkelley@gmail.com"]
|
10
|
+
gem.description = %q{Dynamic Ruby defaults for ActiveRecord attributes}
|
11
|
+
gem.summary = %q{Dynamic Ruby defaults for ActiveRecord attributes. These are lazy evaluated just in time: when first accessed, or just before validation or save. This allows dynamic defaults to depend on attributes that are assigned after initialization, or on other dynamic defaults.}
|
12
|
+
gem.homepage = ""
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/.*\.rb})
|
17
|
+
gem.name = "attr_default"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.version = AttrDefault::VERSION
|
20
|
+
end
|
data/lib/attr_default.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module AttrDefault
|
2
|
+
module ClassMethods
|
3
|
+
def attr_default attr_name, default
|
4
|
+
if !method_defined?(:_attr_default_set)
|
5
|
+
include AttrDefault
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_name = attr_name.to_s
|
9
|
+
define_method attr_name do
|
10
|
+
if new_record? && !@_attr_defaults_set_from_clone && !_attr_default_set[attr_name]
|
11
|
+
default_value = Proc === default ? instance_eval(&default) : default.dup
|
12
|
+
send "#{attr_name}=", default_value
|
13
|
+
end
|
14
|
+
read_attribute_with_fixups( attr_name )
|
15
|
+
end
|
16
|
+
|
17
|
+
define_method "#{attr_name}=" do |*args|
|
18
|
+
_attr_default_set[attr_name] = true
|
19
|
+
write_attribute_with_fixups( attr_name, args )
|
20
|
+
end
|
21
|
+
|
22
|
+
touch_proc = lambda { |obj| obj.send(attr_name); true }
|
23
|
+
before_validation touch_proc
|
24
|
+
before_save touch_proc
|
25
|
+
end
|
26
|
+
|
27
|
+
# Hobo Fields field declaration
|
28
|
+
def field_added(name, type, args, options)
|
29
|
+
if (default = options[:ruby_default]) && Proc === default
|
30
|
+
attr_default name, default
|
31
|
+
elsif (default = options[:default]) && Proc === default
|
32
|
+
attr_default name, default
|
33
|
+
options.delete(:default)
|
34
|
+
options[:ruby_default] = default
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def _attr_default_set
|
40
|
+
@_attr_default_set ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_attribute_with_fixups(attr_name)
|
44
|
+
if needs_time_zone_fixup?(attr_name)
|
45
|
+
cached = @attributes_cache[attr_name] and return cached
|
46
|
+
time = read_attribute(attr_name)
|
47
|
+
@attributes_cache[attr_name] = time.acts_like?(:time) ? time.in_time_zone : time
|
48
|
+
else
|
49
|
+
read_attribute(attr_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_attribute_with_fixups(attr_name, args)
|
54
|
+
if needs_time_zone_fixup?(attr_name)
|
55
|
+
time = args.first
|
56
|
+
unless time.acts_like?(:time)
|
57
|
+
time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
|
58
|
+
end
|
59
|
+
time = time.in_time_zone rescue nil if time
|
60
|
+
write_attribute(attr_name, time)
|
61
|
+
else
|
62
|
+
write_attribute(attr_name, *args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def needs_time_zone_fixup?(attr_name)
|
67
|
+
self.class.send(:create_time_zone_conversion_attribute?, attr_name, self.class.columns_hash[attr_name])
|
68
|
+
end
|
69
|
+
|
70
|
+
def clone
|
71
|
+
result = super
|
72
|
+
result.created_at = nil unless !result.class.columns_hash.has_key?('created_at')
|
73
|
+
result.updated_at = nil unless !result.class.columns_hash.has_key?('updated_at')
|
74
|
+
if self.new_record?
|
75
|
+
result.instance_variable_set(:@_attr_default_set, self._attr_default_set.dup)
|
76
|
+
else
|
77
|
+
result.instance_variable_set(:@_attr_defaults_set_from_clone, true)
|
78
|
+
end
|
79
|
+
result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if defined?(Rails::Railtie)
|
84
|
+
require 'attr_default/railtie'
|
85
|
+
else
|
86
|
+
# Rails 2 initialization
|
87
|
+
ActiveRecord::Base.extend(AttrDefault::ClassMethods)
|
88
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
WANT_RAILS_VERSION = "~> #{ENV.fetch('WANT_RAILS_VERSION', '2.3.4')}"
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'rails', WANT_RAILS_VERSION
|
5
|
+
gem 'activerecord', WANT_RAILS_VERSION
|
6
|
+
begin
|
7
|
+
require 'rails/railtie'
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
require 'active_record'
|
11
|
+
ActiveRecord::ActiveRecordError # work-around from https://rails.lighthouseapp.com/projects/8994/tickets/2577-when-using-activerecordassociations-outside-of-rails-a-nameerror-is-thrown
|
12
|
+
require 'test/unit'
|
13
|
+
require 'active_support/dependencies'
|
14
|
+
require 'active_support/core_ext/logger'
|
15
|
+
require 'hobofields' if ENV['INCLUDE_HOBO']
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift File.expand_path("lib", File.dirname(__FILE__))
|
18
|
+
require 'attr_default'
|
19
|
+
Dir.chdir(File.dirname(__FILE__))
|
20
|
+
|
21
|
+
if RUBY_PLATFORM == "java"
|
22
|
+
database_adapter = "jdbcsqlite3"
|
23
|
+
else
|
24
|
+
database_adapter = "sqlite3"
|
25
|
+
end
|
26
|
+
|
27
|
+
File.unlink('test.sqlite3') rescue nil
|
28
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
29
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
30
|
+
ActiveRecord::Base.establish_connection(
|
31
|
+
:adapter => database_adapter,
|
32
|
+
:database => 'test.sqlite3'
|
33
|
+
)
|
34
|
+
|
35
|
+
ActiveRecord::Base.connection.create_table(:test_users, :force => true) do |t|
|
36
|
+
t.string :first_name
|
37
|
+
t.string :last_name
|
38
|
+
t.boolean :managed
|
39
|
+
t.timestamp :timestamp
|
40
|
+
end
|
41
|
+
|
42
|
+
ActiveRecord::Base.connection.create_table(:test_numbers, :force => true) do |t|
|
43
|
+
t.string :type
|
44
|
+
t.integer :test_user_id
|
45
|
+
t.integer :number
|
46
|
+
t.boolean :managed
|
47
|
+
t.timestamp :created_at
|
48
|
+
end
|
49
|
+
|
50
|
+
if defined?(Rails::Railtie)
|
51
|
+
DefaultValueFor.initialize_railtie
|
52
|
+
DefaultValueFor.initialize_active_record_extensions
|
53
|
+
end
|
54
|
+
|
55
|
+
class TestUser < ActiveRecord::Base
|
56
|
+
attr_accessor :password
|
57
|
+
attr_default :password, '<none>'
|
58
|
+
|
59
|
+
if ENV['INCLUDE_HOBO']
|
60
|
+
fields do
|
61
|
+
first_name :string, :default => '', :ruby_default => 'John'
|
62
|
+
last_name :string, :default => 'Doe'
|
63
|
+
timestamp :timestamp, :default => lambda { (Time.zone || ActiveSupport::TimeZone['Pacific Time (US & Canada)']).now }
|
64
|
+
end
|
65
|
+
else
|
66
|
+
attr_default :first_name, 'John'
|
67
|
+
attr_default :last_name, 'Doe'
|
68
|
+
attr_default :timestamp, lambda { (Time.zone || ActiveSupport::TimeZone['Pacific Time (US & Canada)']).now }
|
69
|
+
end
|
70
|
+
|
71
|
+
has_many :test_numbers
|
72
|
+
has_many :test_numbers_subclass, :class_name => 'TestNumberSubclass'
|
73
|
+
end
|
74
|
+
|
75
|
+
class TestNumber < ActiveRecord::Base
|
76
|
+
if ENV['INCLUDE_HOBO']
|
77
|
+
fields do
|
78
|
+
managed :boolean, :default => lambda { test_user.managed }
|
79
|
+
end
|
80
|
+
else
|
81
|
+
attr_default :managed, lambda { test_user.managed }
|
82
|
+
end
|
83
|
+
|
84
|
+
belongs_to :test_user
|
85
|
+
end
|
86
|
+
|
87
|
+
class TestNumberSubclass < TestNumber
|
88
|
+
if ENV['INCLUDE_HOBO']
|
89
|
+
fields do
|
90
|
+
managed :boolean, :default => lambda { false }
|
91
|
+
end
|
92
|
+
else
|
93
|
+
attr_default :managed, lambda { false }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
class AttrDefaultTest < Test::Unit::TestCase
|
99
|
+
def define_model_class(name = "TestClass", parent_class_name = "ActiveRecord::Base", &block)
|
100
|
+
Object.send(:remove_const, name) rescue nil
|
101
|
+
eval("class #{name} < #{parent_class_name}; end", TOPLEVEL_BINDING)
|
102
|
+
klass = eval(name, TOPLEVEL_BINDING)
|
103
|
+
klass.class_eval do
|
104
|
+
if respond_to?(:table_name=)
|
105
|
+
self.table_name = 'numbers'
|
106
|
+
else
|
107
|
+
set_table_name 'numbers'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
klass.class_eval(&block) if block_given?
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_use_default_if_not_set
|
114
|
+
u = TestUser.new
|
115
|
+
assert_equal nil, u.read_attribute(:last_name)
|
116
|
+
assert_equal "Doe", u.last_name
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_return_the_ActiveRecord_native_type_not_the_lambda_type
|
120
|
+
u = TestUser.new
|
121
|
+
assert_equal 'ActiveSupport::TimeWithZone', u.timestamp.class.name
|
122
|
+
begin
|
123
|
+
old_time_zone, Time.zone = Time.zone, 'Central Time (US & Canada)'
|
124
|
+
u = TestUser.new
|
125
|
+
assert_equal 'ActiveSupport::TimeWithZone', u.timestamp.class.name
|
126
|
+
assert_match /Central Time/, u.timestamp.time_zone.to_s
|
127
|
+
ensure
|
128
|
+
Time.zone = old_time_zone
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_allow_an_override_to_be_specified
|
133
|
+
u = TestUser.new( :last_name => "override" )
|
134
|
+
assert_equal "override", u.read_attribute(:last_name)
|
135
|
+
assert_equal "override", u.last_name
|
136
|
+
end
|
137
|
+
|
138
|
+
if ENV['INCLUDE_HOBO']
|
139
|
+
def test_hobo_allow_default_and_ruby_default
|
140
|
+
u = TestUser.new
|
141
|
+
assert_equal nil, u.read_attribute(:first_name)
|
142
|
+
assert_equal "", TestUser.field_specs['first_name'].options[:default]
|
143
|
+
assert_equal "John", TestUser.field_specs['first_name'].options[:ruby_default].call
|
144
|
+
assert_equal "John", u.first_name
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_handle_mutating_the_default_string
|
149
|
+
u = TestUser.new
|
150
|
+
u2 = TestUser.new
|
151
|
+
|
152
|
+
assert_equal "Doe", u2.last_name
|
153
|
+
u.last_name.upcase!
|
154
|
+
assert_equal "Doe", u2.last_name # should not be DOE
|
155
|
+
|
156
|
+
u3 = TestUser.new
|
157
|
+
assert_equal "Doe", u3.last_name
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_use_default_when_saved_if_not_touched
|
161
|
+
user = TestUser.create! :managed => true
|
162
|
+
number = user.test_numbers.build
|
163
|
+
|
164
|
+
number.save!
|
165
|
+
number.reload
|
166
|
+
assert_equal true, number.read_attribute(:managed)
|
167
|
+
assert_equal true, number.managed
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_clone_touched_state_when_cloned_before_save_new_record_true
|
171
|
+
u = TestUser.new :first_name => 'John', :last_name => 'Doe'
|
172
|
+
u.last_name = 'overridden'
|
173
|
+
u2 = u.clone
|
174
|
+
assert_equal 'overridden', u2.read_attribute(:last_name)
|
175
|
+
assert_equal 'overridden', u2.last_name
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_clone_touched_state_when_cloned_after_save_new_record_false
|
179
|
+
u = TestUser.new :first_name => 'John', :last_name => 'Doe'
|
180
|
+
u.last_name = 'overridden'
|
181
|
+
u2 = u.clone
|
182
|
+
u2.save!
|
183
|
+
u.save!
|
184
|
+
assert u.clone.instance_variable_get(:@_attr_defaults_set_from_clone)
|
185
|
+
assert_equal 'overridden', u.clone.last_name
|
186
|
+
ufind = TestUser.find(u.id)
|
187
|
+
u3 = ufind.clone
|
188
|
+
assert_equal 'overridden', u3.read_attribute(:last_name), u3.attributes.inspect
|
189
|
+
assert_equal 'overridden', u3.last_name
|
190
|
+
u3.save!
|
191
|
+
assert_equal 'overridden', u2.read_attribute(:last_name)
|
192
|
+
assert_equal 'overridden', u2.last_name
|
193
|
+
assert_equal 'overridden', u3.read_attribute(:last_name)
|
194
|
+
assert_equal 'overridden', u3.last_name
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_use_default_when_saved_if_not_touched_and_validation_turned_off
|
198
|
+
user = TestUser.create! :managed => true
|
199
|
+
number = user.test_numbers.build :number => 42
|
200
|
+
|
201
|
+
# not touched or saved yet, still empty
|
202
|
+
assert_equal nil, number.read_attribute(:managed)
|
203
|
+
|
204
|
+
number.save(false)
|
205
|
+
|
206
|
+
# now it should be true
|
207
|
+
assert_equal true, number.read_attribute(:managed)
|
208
|
+
assert_equal true, number.managed
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_use_value_set_on_object_even_when_first_loaded_from_db
|
212
|
+
user = TestUser.create! :managed => true
|
213
|
+
number = user.test_numbers.create! :number => 42, :managed => false
|
214
|
+
number_find = TestNumber.find(number.id)
|
215
|
+
assert_equal false, number_find.managed
|
216
|
+
end
|
217
|
+
|
218
|
+
[false, true].each do |user_managed|
|
219
|
+
define_method "test_default_#{user_managed}_and_param_not_specified" do
|
220
|
+
user = TestUser.create! :managed => user_managed
|
221
|
+
number = user.test_numbers.build
|
222
|
+
assert_equal user_managed, number.managed
|
223
|
+
end
|
224
|
+
|
225
|
+
define_method "test_default_#{user_managed}_and_#{!user_managed}_specified" do
|
226
|
+
user = TestUser.create! :managed => true
|
227
|
+
number = user.test_numbers.build :managed => !user_managed
|
228
|
+
assert_equal !user_managed, number.managed
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_allow_subclass_to_override_the_default
|
233
|
+
user = TestUser.create! :managed => true
|
234
|
+
number = user.test_numbers.new
|
235
|
+
assert_equal true, number.managed
|
236
|
+
number_subclass = user.test_numbers_subclass.new
|
237
|
+
assert_equal false, number_subclass.managed
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_non_persistent_use_default_if_not_set
|
241
|
+
user = TestUser.new
|
242
|
+
assert_equal "<none>", user.password
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_non_persistent_use_value_if_set_in_initialize
|
246
|
+
user = TestUser.new :password => "supersecret"
|
247
|
+
assert_equal "supersecret", user.password
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_non_persistent_use_value_if_set_after_initialize
|
251
|
+
user = TestUser.new
|
252
|
+
user.password = "supersecret"
|
253
|
+
assert_equal "supersecret", user.password
|
254
|
+
end
|
255
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_default
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Colin Kelley
|
13
|
+
- Nick Burwell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-06-10 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rails
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :runtime
|
44
|
+
version_requirements: *id002
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: sqlite3
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
type: :development
|
56
|
+
version_requirements: *id003
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: hobofields
|
59
|
+
prerelease: false
|
60
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id004
|
69
|
+
description: Dynamic Ruby defaults for ActiveRecord attributes
|
70
|
+
email:
|
71
|
+
- colindkelley@gmail.com
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files: []
|
77
|
+
|
78
|
+
files:
|
79
|
+
- .gitignore
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE
|
82
|
+
- README.rdoc
|
83
|
+
- Rakefile
|
84
|
+
- attr_default.gemspec
|
85
|
+
- lib/attr_default.rb
|
86
|
+
- lib/attr_default/version.rb
|
87
|
+
- test/test_attr_default.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: ""
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.6
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: "Dynamic Ruby defaults for ActiveRecord attributes. These are lazy evaluated just in time: when first accessed, or just before validation or save. This allows dynamic defaults to depend on attributes that are assigned after initialization, or on other dynamic defaults."
|
118
|
+
test_files:
|
119
|
+
- test/test_attr_default.rb
|