pax_global_header 0000666 0000000 0000000 00000000064 12457447254 0014530 g ustar 00root root 0000000 0000000 52 comment=a7366465bf8f0c327519564de377e276b41114db
ruby-default-value-for-3.0.1/ 0000775 0000000 0000000 00000000000 12457447254 0016032 5 ustar 00root root 0000000 0000000 ruby-default-value-for-3.0.1/LICENSE.TXT 0000664 0000000 0000000 00000002047 12457447254 0017520 0 ustar 00root root 0000000 0000000 Copyright (c) 2008, 2009, 2010 Phusion
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
ruby-default-value-for-3.0.1/README.md 0000664 0000000 0000000 00000037171 12457447254 0017322 0 ustar 00root root 0000000 0000000 # Introduction
The default_value_for plugin allows one to define default values for ActiveRecord
models in a declarative manner. For example:
```ruby
class User < ActiveRecord::Base
default_value_for :name, "(no name)"
default_value_for :last_seen do
Time.now
end
end
u = User.new
u.name # => "(no name)"
u.last_seen # => Mon Sep 22 17:28:38 +0200 2008
```
*Note*: critics might be interested in the "When (not) to use default_value_for?" section. Please read on.
## Installation
### Rails 3.2 - 4.2 / Ruby 1.9.3 and higher
The current version of default_value_for (3.0.x) is compatible with Rails 3.2 or higher, and Ruby 1.9.3 and higher.
Add it to your Gemfile:
```ruby
gem "default_value_for", "~> 3.0.0"
```
This gem is signed using PGP with the Phusion Software Signing key: http://www.phusion.nl/about/gpg. That key in turn is signed by the rubygems-openpgp Certificate Authority: http://www.rubygems-openpgp-ca.org/.
You can verify the authenticity of the gem by following The Complete Guide to Verifying Gems with rubygems-openpgp: http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-gems-with-rubygems-openpgp.html
## Rails 3.0 - 3.1 / Ruby 1.9.3 and lower
To use default_value_for with older versions of Ruby and Rails, you must use the previous stable release, 2.0.3. This version works with Rails 3.0, 3.1, and 3.2; and Ruby 1.8.7 and higher. It **does not** work with Rails 4.
```ruby
gem "default_value_for", "~> 2.0.3"
```
### Rails 2
To use default_value_for with Rails 2.x you must use an older version:
```shell
./script/plugin install git://github.com/FooBarWidget/default_value_for.git -r release-1.0.7
```
## The default_value_for method
The `default_value_for` method is available in all ActiveRecord model classes.
The first argument is the name of the attribute for which a default value should
be set. This may either be a Symbol or a String.
The default value itself may either be passed as the second argument:
```ruby
default_value_for :age, 20
```
...or it may be passed as the return value of a block:
```ruby
default_value_for :age do
if today_is_sunday?
20
else
30
end
end
```
If you pass a value argument, then the default value is static and never changes. However, if you pass a block, then the default value is retrieved by calling the block. This block is called not once, but every time a new record is instantiated and default values need to be filled in.
The latter form is especially useful if your model has a UUID column. One can generate a new, random UUID for every newly instantiated record:
```ruby
class User < ActiveRecord::Base
default_value_for :uuid do
UuidGenerator.new.generate_uuid
end
end
User.new.uuid # => "51d6d6846f1d1b5c9a...."
User.new.uuid # => "ede292289e3484cb88...."
```
Note that record is passed to the block as an argument, in case you need it for whatever reason:
```ruby
class User < ActiveRecord::Base
default_value_for :uuid do |x|
x # <--- a User object
UuidGenerator.new.generate_uuid
end
end
```
## default_value_for options
* allows_nil (default: true) - Sets explicitly passed nil values if option is set to true.
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.:
```ruby
default_value_for :age, :value => 20, :allows_nil => false
```
You can still pass the default value through a block:
```ruby
default_value_for :uuid, :allows_nil => false do
UuidGenerator.new.generate_uuid
end
````
## The default_values method
As a shortcut, you can use +default_values+ to set multiple default values at once.
```ruby
default_values :age => 20,
:uuid => lambda { UuidGenerator.new.generate_uuid }
```
If you like to override default_value_for options for each attribute you can do so:
```ruby
default_values :age => { :value => 20 },
:uuid => { :value => lambda { UuidGenerator.new.generate_uuid }, :allows_nil => false }
```
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.
As a side note, due to specifics of Ruby's parser, you cannot say,
```ruby
default_value_for :uuid { UuidGenerator.new.generate_uuid }
```
because it will not parse. One needs to write
```ruby
default_value_for(:uuid) { UuidGenerator.new.generate_uuid }
```
instead. This is in part the inspiration for the +default_values+ syntax.
## Rules
### Instantiation of new record
Upon instantiating a new record, the declared default values are filled into
the record. You've already seen this in the above examples.
### Retrieval of existing record
Upon retrieving an existing record in the following case, the declared default values are _not_ filled into the record. Consider the example with the UUID:
```ruby
user = User.create
user.uuid # => "529c91b8bbd3e..."
user = User.find(user.id)
# UUID remains unchanged because it's retrieved from the database!
user.uuid # => "529c91b8bbd3e..."
```
But when the declared default value is set to not allow nil and nil is passed the default values will be set on retrieval.
Consider this example:
```ruby
default_value_for(:number, :allows_nil => false) { 123 }
user = User.create
# manual SQL by-passing active record and the default value for gem logic through ActiveRecord's after_initialize callback
user.update_attribute(:number, nil)
# declared default value should be set
User.find(user.id).number # => 123 # = declared default value
```
### Mass-assignment
If a certain attribute is being assigned via the model constructor's
mass-assignment argument, that the default value for that attribute will _not_
be filled in:
```ruby
user = User.new(:uuid => "hello")
user.uuid # => "hello"
```
However, if that attribute is protected by +attr_protected+ or +attr_accessible+,
then it will be filled in:
```ruby
class User < ActiveRecord::Base
default_value_for :name, 'Joe'
attr_protected :name
end
user = User.new(:name => "Jane")
user.name # => "Joe"
# the without protection option will work as expected
user = User.new({:name => "Jane"}, :without_protection => true)
user.name # => "Jane"
```
Explicitly set nil values for accessible attributes will be accepted:
```ruby
class User < ActiveRecord::Base
default_value_for :name, 'Joe'
end
user = User(:name => nil)
user.name # => nil
... unless the accessible attribute is set to not allowing nil:
class User < ActiveRecord::Base
default_value_for :name, 'Joe', :allows_nil => false
end
user = User(:name => nil)
user.name # => "Joe"
```
### Inheritance
Inheritance works as expected. All default values are inherited by the child
class:
```ruby
class User < ActiveRecord::Base
default_value_for :name, 'Joe'
end
class SuperUser < User
end
SuperUser.new.name # => "Joe"
```
### Attributes that aren't database columns
`default_value_for` also works with attributes that aren't database columns.
It works with anything for which there's an assignment method:
```ruby
# Suppose that your 'users' table only has a 'name' column.
class User < ActiveRecord::Base
default_value_for :name, 'Joe'
default_value_for :age, 20
default_value_for :registering, true
attr_accessor :age
def registering=(value)
@registering = true
end
end
user = User.new
user.age # => 20
user.instance_variable_get('@registering') # => true
```
### Default values are duplicated
The given default values are duplicated when they are filled in, so if you mutate a value that was filled in with a default value, then it will not affect all subsequent default values:
```ruby
class Author < ActiveRecord::Base
# This model only has a 'name' attribute.
end
class Book < ActiveRecord::Base
belongs_to :author
# By default, a Book belongs to a new, unsaved author.
default_value_for :author, Author.new
end
book1 = Book.new
book1.author.name # => nil
# This does not mutate the default value:
book1.author.name = "John"
book2 = Book.new
book2.author.name # => nil
```
However the duplication is shallow. If you modify any objects that are referenced by the default value then it will affect subsequent default values:
```ruby
class Author < ActiveRecord::Base
attr_accessor :useless_hash
default_value_for :useless_hash, { :foo => [] }
end
author1 = Author.new
author1.useless_hash # => { :foo => [] }
# This mutates the referred array:
author1.useless_hash[:foo] << 1
author2 = Author.new
author2.useless_hash # => { :foo => [1] }
```
You can prevent this from happening by passing a block to `default_value_for`, which returns a new object instance with fresh references every time:
```ruby
class Author < ActiveRecord::Base
attr_accessor :useless_hash
default_value_for :useless_hash do
{ :foo => [] }
end
end
author1 = Author.new
author1.useless_hash # => { :foo => [] }
author1.useless_hash[:foo] << 1
author2 = Author.new
author2.useless_hash # => { :foo => [] }
```
### Caveats
A conflict can occur if your model class overrides the 'initialize' method, because this plugin overrides 'initialize' as well to do its job.
```ruby
class User < ActiveRecord::Base
def initialize # <-- this constructor causes problems
super(:name => 'Name cannot be changed in constructor')
end
end
```
We recommend you to alias chain your initialize method in models where you use `default_value_for`:
```ruby
class User < ActiveRecord::Base
default_value_for :age, 20
def initialize_with_my_app
initialize_without_my_app(:name => 'Name cannot be changed in constructor')
end
alias_method_chain :initialize, :my_app
end
```
Also, stick with the following rules:
* There is no need to +alias_method_chain+ your initialize method in models that don't use `default_value_for`.
* Make sure that +alias_method_chain+ is called *after* the last `default_value_for` occurance.
If your default value is accidentally similar to default_value_for's options hash wrap your default value like this:
```ruby
default_value_for :attribute_name, :value => { :value => 123, :other_value => 1234 }
```
## When (not) to use default_value_for?
You can also specify default values in the database schema. For example, you can specify a default value in a migration as follows:
```ruby
create_table :users do |t|
t.string :username, :null => false, :default => 'default username'
t.integer :age, :null => false, :default => 20
end
```
This has similar effects as passing the default value as the second argument to `default_value_for`:
```ruby
default_value_for(:username, 'default_username')
default_value_for(:age, 20)
```
Default values are filled in whether you use the schema defaults or the default_value_for defaults:
```ruby
user = User.new
user.username # => 'default username'
user.age # => 20
```
It's recommended that you use this over `default_value_for` whenever possible.
However, it's not possible to specify a schema default for serialized columns. With `default_value_for`, you can:
```ruby
class User < ActiveRecord::Base
serialize :color
default_value_for :color, [255, 0, 0]
end
```
And if schema defaults don't provide the flexibility that you need, then `default_value_for` is the perfect choice. For example, with `default_value_for` you could specify a per-environment default:
```ruby
class User < ActiveRecord::Base
if Rails.env ## "development"
default_value_for :is_admin, true
end
end
```
Or, as you've seen in an earlier example, you can use `default_value_for` to generate a default random UUID:
```ruby
class User < ActiveRecord::Base
default_value_for :uuid do
UuidGenerator.new.generate_uuid
end
end
```
Or you could use it to generate a timestamp that's relative to the time at which the record is instantiated:
```ruby
class User < ActiveRecord::Base
default_value_for :account_expires_at do
3.years.from_now
end
end
User.new.account_expires_at # => Mon Sep 22 18:43:42 +0200 2008
sleep(2)
User.new.account_expires_at # => Mon Sep 22 18:43:44 +0200 2008
```
Finally, it's also possible to specify a default via an association:
```ruby
# Has columns: 'name' and 'default_price'
class SuperMarket < ActiveRecord::Base
has_many :products
end
# Has columns: 'name' and 'price'
class Product < ActiveRecord::Base
belongs_to :super_market
default_value_for :price do |product|
product.super_market.default_price
end
end
super_market = SuperMarket.create(:name => 'Albert Zwijn', :default_price => 100)
soap = super_market.products.create(:name => 'Soap')
soap.price # => 100
```
### What about before_validate/before_save?
True, +before_validate+ and +before_save+ does what we want if we're only interested in filling in a default before saving. However, if one wants to be able to access the default value even before saving, then be prepared to write a lot of code. Suppose that we want to be able to access a new record's UUID, even before it's saved. We could end up with the following code:
```ruby
# In the controller
def create
@user = User.new(params[:user])
@user.generate_uuid
email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
@user.save!
end
# Model
class User < ActiveRecord::Base
before_save :generate_uuid_if_necessary
def generate_uuid
self.uuid = ...
end
private
def generate_uuid_if_necessary
if uuid.blank?
generate_uuid
end
end
end
```
The need to manually call +generate_uuid+ here is ugly, and one can easily forget to do that. Can we do better? Let's see:
```ruby
# Controller
def create
@user = User.new(params[:user])
email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
@user.save!
end
# Model
class User < ActiveRecord::Base
before_save :generate_uuid_if_necessary
def uuid
value = read_attribute('uuid')
if !value
value = generate_uuid
write_attribute('uuid', value)
end
value
end
# We need to override this too, otherwise User.new.attributes won't return
# a default UUID value. I've never tested with User.create() so maybe we
# need to override even more things.
def attributes
uuid
super
end
private
def generate_uuid_if_necessary
uuid # Reader method automatically generates UUID if it doesn't exist
end
end
```
That's an awful lot of code. Using `default_value_for` is easier, don't you think?
### What about other plugins?
I've only been able to find 2 similar plugins:
* Default Value: http://agilewebdevelopment.com/plugins/default_value
* ActiveRecord Defaults: http://agilewebdevelopment.com/plugins/activerecord_defaults
'Default Value' appears to be unmaintained; its SVN link is broken. This leaves only 'ActiveRecord Defaults'. However, it is semantically dubious, which leaves it wide open for corner cases. For example, it is not clearly specified what ActiveRecord Defaults will do when attributes are protected by +attr_protected+ or +attr_accessible+. It is also not clearly specified what one is supposed to do if one needs a custom +initialize+ method in the model.
I've taken my time to thoroughly document default_value_for's behavior.
## Credits
I've wanted such functionality for a while now and it baffled me that ActiveRecord doesn't provide a clean way for me to specify default values. After reading http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935, it became clear that someone needs to write a plugin. This is the result.
Thanks to Pratik Naik for providing the initial code snippet on which this plugin is based on: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model
Thanks to Norman Clarke and Tom Mango for Rails 4 support. ruby-default-value-for-3.0.1/Rakefile 0000664 0000000 0000000 00000001037 12457447254 0017500 0 ustar 00root root 0000000 0000000 task :default => :test
desc "Run unit tests."
task :test do
ruby "test.rb"
end
['3.2', '4.0', '4.1', '4.2'].each do |version|
dotless = version.delete('.')
namespace :bundle do
desc "Bundle with Rails #{version}.x"
task :"rails#{dotless}" do
ENV['BUNDLE_GEMFILE'] = "Gemfile.rails.#{version}.rb"
sh "bundle"
end
end
namespace :test do
desc "Test with Rails #{version}.x"
task :"rails#{dotless}" do
ENV['BUNDLE_GEMFILE'] = "Gemfile.rails.#{version}.rb"
ruby "test.rb"
end
end
end
ruby-default-value-for-3.0.1/default_value_for.gemspec 0000664 0000000 0000000 00000002075 12457447254 0023071 0 ustar 00root root 0000000 0000000 Gem::Specification.new do |s|
s.name = %q{default_value_for}
s.version = "3.0.1"
s.summary = %q{Provides a way to specify default values for ActiveRecord models}
s.description = %q{The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner}
s.email = %q{software-signing@phusion.nl}
s.homepage = %q{https://github.com/FooBarWidget/default_value_for}
s.authors = ["Hongli Lai"]
s.license = 'MIT'
s.required_ruby_version = '>= 1.9.3'
s.files = ['default_value_for.gemspec',
'LICENSE.TXT', 'Rakefile', 'README.md', 'test.rb',
'init.rb',
'lib/default_value_for.rb',
'lib/default_value_for/railtie.rb'
]
s.add_dependency 'activerecord', '>= 3.2.0', '< 5.0'
s.add_development_dependency 'railties', '>= 3.2.0', '< 5.0'
s.add_development_dependency 'minitest', '>= 4.2'
s.add_development_dependency 'minitest-around'
s.add_development_dependency 'appraisal'
end
ruby-default-value-for-3.0.1/init.rb 0000664 0000000 0000000 00000002147 12457447254 0017326 0 ustar 00root root 0000000 0000000 # Copyright (c) 2008, 2009, 2010 Phusion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
require 'default_value_for'
ruby-default-value-for-3.0.1/lib/ 0000775 0000000 0000000 00000000000 12457447254 0016600 5 ustar 00root root 0000000 0000000 ruby-default-value-for-3.0.1/lib/default_value_for.rb 0000664 0000000 0000000 00000015427 12457447254 0022624 0 ustar 00root root 0000000 0000000 # Copyright (c) 2008-2012 Phusion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
module DefaultValueFor
class NormalValueContainer
def initialize(value)
@value = value
end
def evaluate(instance)
if @value.duplicable?
return @value.dup
else
return @value
end
end
end
class BlockValueContainer
def initialize(block)
@block = block
end
def evaluate(instance)
if @block.arity == 0
return @block.call
else
return @block.call(instance)
end
end
end
module ClassMethods
# Declares a default value for the given attribute.
#
# Sets the default value to the given options parameter unless the given options equal { :value => ... }
#
# The options can be used to specify the following things:
# * value - Sets the default value.
# * allows_nil (default: true) - Sets explicitly passed nil values if option is set to true.
def default_value_for(attribute, options = {}, &block)
value = options
allows_nil = true
if options.is_a?(Hash)
opts = options.stringify_keys
value = opts.fetch('value', options)
allows_nil = opts.fetch('allows_nil', true)
end
if !method_defined?(:set_default_values)
include(InstanceMethods)
after_initialize :set_default_values
class_attribute :_default_attribute_values
class_attribute :_default_attribute_values_not_allowing_nil
extend(DelayedClassMethods)
init_hash = true
else
init_hash = !singleton_methods(false).include?(:_default_attribute_values)
end
if init_hash
self._default_attribute_values = {}
self._default_attribute_values_not_allowing_nil = []
end
if block_given?
container = BlockValueContainer.new(block)
else
container = NormalValueContainer.new(value)
end
_default_attribute_values[attribute.to_s] = container
_default_attribute_values_not_allowing_nil << attribute.to_s unless allows_nil
end
def default_values(values)
values.each_pair do |key, options|
options = options.stringify_keys if options.is_a?(Hash)
value = options.is_a?(Hash) && options.has_key?('value') ? options['value'] : options
if value.kind_of? Proc
default_value_for(key, options.is_a?(Hash) ? options : {}, &value)
else
default_value_for(key, options)
end
end
end
end
module DelayedClassMethods
def _all_default_attribute_values
return _default_attribute_values unless superclass.respond_to?(:_default_attribute_values)
superclass._all_default_attribute_values.merge(_default_attribute_values)
end
def _all_default_attribute_values_not_allowing_nil
return _default_attribute_values_not_allowing_nil unless superclass.respond_to?(:_default_attribute_values_not_allowing_nil)
result = superclass._all_default_attribute_values_not_allowing_nil.concat(_default_attribute_values_not_allowing_nil)
result.uniq!
result
end
end
module InstanceMethods
def initialize(attributes = nil, options = {})
@initialization_attributes = attributes.is_a?(Hash) ? attributes.stringify_keys : {}
unless options[:without_protection]
if respond_to?(:mass_assignment_options, true) && options.has_key?(:as)
@initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes, options[:as])
elsif respond_to?(:sanitize_for_mass_assignment, true)
@initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes)
else
@initialization_attributes = remove_attributes_protected_from_mass_assignment(@initialization_attributes)
end
end
if self.class.respond_to? :protected_attributes
super(attributes, options)
else
super(attributes)
end
end
def attributes_for_create(attribute_names)
attribute_names += self.class._all_default_attribute_values.keys.map(&:to_s).find_all { |name|
self.class.columns_hash.key?(name)
}
super
end
def set_default_values
self.class._all_default_attribute_values.each do |attribute, container|
next unless new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
connection_default_value_defined = new_record? && respond_to?("#{attribute}_changed?") && !__send__("#{attribute}_changed?")
column = self.class.columns.detect {|c| c.name == attribute}
attribute_blank = if column && column.type == :boolean
attributes[attribute].nil?
else
attributes[attribute].blank?
end
next unless connection_default_value_defined || attribute_blank
# allow explicitly setting nil through allow nil option
next if @initialization_attributes.is_a?(Hash) &&
(
@initialization_attributes.has_key?(attribute) ||
(
@initialization_attributes.has_key?("#{attribute}_attributes") &&
nested_attributes_options.stringify_keys[attribute]
)
) &&
!self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
__send__("#{attribute}=", container.evaluate(self))
if self.class.private_instance_methods.include? :clear_attribute_changes
clear_attribute_changes attribute
else
changed_attributes.delete(attribute)
end
end
end
end
end
if defined?(Rails::Railtie)
require 'default_value_for/railtie'
else
# For anybody is using AS and AR without Railties, i.e. Padrino.
ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
end
ruby-default-value-for-3.0.1/lib/default_value_for/ 0000775 0000000 0000000 00000000000 12457447254 0022266 5 ustar 00root root 0000000 0000000 ruby-default-value-for-3.0.1/lib/default_value_for/railtie.rb 0000664 0000000 0000000 00000003013 12457447254 0024241 0 ustar 00root root 0000000 0000000 # Copyright (c) 2008, 2009, 2010, 2011 Phusion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
module DefaultValueFor
def self.initialize_railtie
ActiveSupport.on_load :active_record do
DefaultValueFor.initialize_active_record_extensions
end
end
def self.initialize_active_record_extensions
ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
end
class Railtie < Rails::Railtie
initializer 'default_value_for.insert_into_active_record' do
DefaultValueFor.initialize_railtie
end
end
end
ruby-default-value-for-3.0.1/metadata.yml 0000664 0000000 0000000 00000006402 12457447254 0020337 0 ustar 00root root 0000000 0000000 --- !ruby/object:Gem::Specification
name: default_value_for
version: !ruby/object:Gem::Version
version: 3.0.1
platform: ruby
authors:
- Hongli Lai
autorequire:
bindir: bin
cert_chain: []
date: 2014-12-23 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: activerecord
requirement: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 3.2.0
- - <
- !ruby/object:Gem::Version
version: '5.0'
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 3.2.0
- - <
- !ruby/object:Gem::Version
version: '5.0'
- !ruby/object:Gem::Dependency
name: railties
requirement: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 3.2.0
- - <
- !ruby/object:Gem::Version
version: '5.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 3.2.0
- - <
- !ruby/object:Gem::Version
version: '5.0'
- !ruby/object:Gem::Dependency
name: minitest
requirement: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '4.2'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '4.2'
- !ruby/object:Gem::Dependency
name: minitest-around
requirement: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
- !ruby/object:Gem::Dependency
name: appraisal
requirement: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
description: The default_value_for plugin allows one to define default values for
ActiveRecord models in a declarative manner
email: software-signing@phusion.nl
executables: []
extensions: []
extra_rdoc_files: []
files:
- LICENSE.TXT
- README.md
- Rakefile
- default_value_for.gemspec
- init.rb
- lib/default_value_for.rb
- lib/default_value_for/railtie.rb
- test.rb
homepage: https://github.com/FooBarWidget/default_value_for
licenses:
- MIT
metadata: {}
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 1.9.3
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
rubygems_version: 2.2.2
signing_key:
specification_version: 4
summary: Provides a way to specify default values for ActiveRecord models
test_files: []
ruby-default-value-for-3.0.1/test.rb 0000664 0000000 0000000 00000025661 12457447254 0017350 0 ustar 00root root 0000000 0000000 # Copyright (c) 2008-2012 Phusion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
require 'bundler/setup'
require 'minitest/autorun'
require 'minitest/around/unit'
require 'active_record'
if ActiveSupport::VERSION::MAJOR == 3
require 'active_support/core_ext/logger'
end
begin
TestCaseClass = MiniTest::Test
rescue NameError
TestCaseClass = MiniTest::Unit::TestCase
end
require 'default_value_for'
puts "\nTesting with Active Record version #{ActiveRecord::VERSION::STRING}\n\n"
ActiveRecord::Base.default_timezone = :local
ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.logger.level = Logger::WARN
ActiveRecord::Base.establish_connection(
:adapter => RUBY_PLATFORM == 'java' ? 'jdbcsqlite3' : 'sqlite3',
:database => ':memory:'
)
ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
t.string :username
t.integer :default_number
end
ActiveRecord::Base.connection.create_table(:books, :force => true) do |t|
t.string :type
t.integer :number
t.integer :count, :null => false, :default => 1
t.integer :user_id
t.timestamp :timestamp
t.text :stuff
t.boolean :flag
end
if defined?(Rails::Railtie)
DefaultValueFor.initialize_railtie
DefaultValueFor.initialize_active_record_extensions
end
class DefaultValuePluginTest < TestCaseClass
def around
Object.const_set(:User, Class.new(ActiveRecord::Base))
Object.const_set(:Book, Class.new(ActiveRecord::Base))
Object.const_set(:Novel, Class.new(Book))
User.has_many :books
Book.belongs_to :user
ActiveRecord::Base.transaction do
yield
raise ActiveRecord::Rollback
end
ensure
Object.send(:remove_const, :User)
Object.send(:remove_const, :Book)
Object.send(:remove_const, :Novel)
ActiveSupport::Dependencies.clear
end
def test_default_value_on_attribute_methods
Book.class_eval do
serialize :stuff
default_value_for :color, :green
def color; (self.stuff || {})[:color]; end
def color=(val)
self.stuff ||= {}
self.stuff[:color] = val
end
end
assert_equal :green, Book.create.color
end
def test_default_value_can_be_passed_as_argument
Book.default_value_for(:number, 1234)
assert_equal 1234, Book.new.number
end
def test_default_value_can_be_passed_as_block
Book.default_value_for(:number) { 1234 }
assert_equal 1234, Book.new.number
end
def test_works_with_create
Book.default_value_for :number, 1234
object = Book.create
refute_nil Book.find_by_number(1234)
# allows nil for existing records
object.update_attribute(:number, nil)
assert_nil Book.find_by_number(1234)
assert_nil Book.find(object.id).number
end
def test_does_not_allow_nil_sets_default_value_on_existing_nils
Book.default_value_for(:number, :allows_nil => false) { 1234 }
object = Book.create
object.update_attribute(:number, nil)
assert_nil Book.find_by_number(1234)
assert_equal 1234, Book.find(object.id).number
end
def test_overwrites_db_default
Book.default_value_for :count, 1234
assert_equal 1234, Book.new.count
end
def test_doesnt_overwrite_values_provided_by_mass_assignment
Book.default_value_for :number, 1234
assert_equal 1, Book.new(:number => 1, :count => 2).number
end
def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
Book.default_value_for :timestamp, Time.mktime(2000, 1, 1)
timestamp = Time.mktime(2009, 1, 1)
object = Book.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
assert_equal timestamp, object.timestamp
end
def test_doesnt_overwrite_values_provided_by_constructor_block
Book.default_value_for :number, 1234
object = Book.new do |x|
x.number = 1
x.count = 2
end
assert_equal 1, object.number
end
def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
Book.default_value_for :number, 1234
assert_equal nil, Book.new(:number => nil).number
end
def test_overwrites_explicitly_provided_nil_values_in_mass_assignment
Book.default_value_for :number, :value => 1234, :allows_nil => false
assert_equal 1234, Book.new(:number => nil).number
end
def test_default_values_are_inherited
Book.default_value_for :number, 1234
assert_equal 1234, Novel.new.number
end
def test_default_values_in_superclass_are_saved_in_subclass
Book.default_value_for :number, 1234
Novel.default_value_for :flag, true
object = Novel.create!
assert_equal object.id, Novel.find_by_number(1234).id
assert_equal object.id, Novel.find_by_flag(true).id
end
def test_default_values_in_subclass
Novel.default_value_for :number, 5678
assert_equal 5678, Novel.new.number
assert_nil Book.new.number
end
def test_multiple_default_values_in_subclass_with_default_values_in_parent_class
Book.class_eval do
default_value_for :other_number, nil
attr_accessor :other_number
end
Novel.default_value_for :number, 5678
# Ensure second call in this class doesn't reset _default_attribute_values,
# and also doesn't consider the parent class' _default_attribute_values when
# making that check.
Novel.default_value_for :user_id, 9999
object = Novel.new
assert_nil object.other_number
assert_equal 5678, object.number
assert_equal 9999, object.user_id
end
def test_override_default_values_in_subclass
Book.default_value_for :number, 1234
Novel.default_value_for :number, 5678
assert_equal 5678, Novel.new.number
assert_equal 1234, Book.new.number
end
def test_default_values_in_subclass_do_not_affect_parent_class
Book.default_value_for :number, 1234
Novel.class_eval do
default_value_for :hello, "hi"
attr_accessor :hello
end
assert Book.new
assert !Book._default_attribute_values.include?(:hello)
end
def test_doesnt_set_default_on_saved_records
Book.create(:number => 9876)
Book.default_value_for :number, 1234
assert_equal 9876, Book.first.number
end
def test_also_works_on_attributes_that_arent_database_columns
Book.class_eval do
default_value_for :hello, "hi"
attr_accessor :hello
end
assert_equal 'hi', Book.new.hello
end
def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
Book.class_eval do
def initialize(attrs = {})
@initialized = true
super(:count => 5678)
end
default_value_for :number, 1234
end
object = Book.new
assert_equal 1234, object.number
assert_equal 5678, object.count
assert object.instance_variable_get('@initialized')
end
def test_model_instance_is_passed_to_the_given_block
instance = nil
Book.default_value_for :number do |n|
instance = n
end
object = Book.new
assert_same object.object_id, instance.object_id
end
def test_can_specify_default_value_via_association
user = User.create(:username => 'Kanako', :default_number => 123)
Book.default_value_for :number do |n|
n.user.default_number
end
assert_equal 123, user.books.create!.number
end
def test_default_values
Book.default_values({
:type => "normal",
:number => lambda { 10 + 5 },
:timestamp => lambda {|_| Time.now }
})
object = Book.new
assert_equal("normal", object.type)
assert_equal(15, object.number)
end
def test_default_value_order
Book.default_value_for :count, 5
Book.default_value_for :number do |this|
this.count * 2
end
object = Book.new
assert_equal(5, object.count)
assert_equal(10, object.number)
end
def test_attributes_with_default_values_are_not_marked_as_changed
Book.default_value_for :count, 5
Book.default_value_for :number, 2
object = Book.new
assert(!object.changed?)
assert_equal([], object.changed)
object.type = "foo"
assert(object.changed?)
assert_equal(["type"], object.changed)
end
def test_default_values_are_duplicated
User.default_value_for :username, "hello"
user1 = User.new
user1.username << " world"
user2 = User.new
assert_equal("hello", user2.username)
end
def test_default_values_are_shallow_copied
User.class_eval do
attr_accessor :hash
default_value_for :hash, { 1 => [] }
end
user1 = User.new
user1.hash[1] << 1
user2 = User.new
assert_equal([1], user2.hash[1])
end
def test_constructor_does_not_affect_the_hash_passed_to_it
Book.default_value_for :count, 5
options = { :count => 5, :user_id => 1 }
options_dup = options.dup
Book.new(options)
assert_equal(options_dup, options)
end
def test_subclass_find
Book.default_value_for :number, 5678
n = Novel.create
assert Novel.find(n.id)
end
def test_does_not_see_false_as_blank_at_boolean_columns_for_existing_records
Book.default_value_for(:flag, :allows_nil => false) { true }
object = Book.create
# allows nil for existing records
object.update_attribute(:flag, false)
assert_equal false, Book.find(object.id).flag
end
def test_works_with_nested_attributes
User.accepts_nested_attributes_for :books
User.default_value_for :books do
[Book.create!(:number => 0)]
end
user = User.create! :books_attributes => [{:number => 1}]
assert_equal 1, Book.all.first.number
end
if ActiveRecord::VERSION::MAJOR == 3
def test_constructor_ignores_forbidden_mass_assignment_attributes
Book.class_eval do
default_value_for :number, 1234
attr_protected :number
end
object = Book.new(:number => 5678, :count => 987)
assert_equal 1234, object.number
assert_equal 987, object.count
end
def test_constructor_respects_without_protection_option
Book.class_eval do
default_value_for :number, 1234
attr_protected :number
end
object = Book.create!({:number => 5678, :count => 987}, :without_protection => true)
assert_equal 5678, object.number
assert_equal 987, object.count
end
end
end