Skip to content
Browse files

Merge pull request #240 from amarshall/freezing-defaults

Don’t override already-defined default values when freezing
  • Loading branch information...
2 parents 79f66db + c16ab82 commit 45ef710dc856901c40c7a989222c5e4070020188 @solnic committed Jan 31, 2014
View
11 lib/virtus/attribute/accessor.rb
@@ -34,6 +34,17 @@ def self.extended(descendant)
descendant.instance_variable_set('@instance_variable_name', "@#{name}")
end
+ # Return if attribute value is defined
+ #
+ # @param [Object] instance
+ #
+ # @return [Boolean]
+ #
+ # @api public
+ def defined?(instance)
+ instance.instance_variable_defined?(instance_variable_name)
+ end
+
# Return value of the attribute
#
# @param [Object] instance
View
2 lib/virtus/attribute_set.rb
@@ -209,7 +209,7 @@ def finalize
# @api private
def skip_default?(object, attribute)
- attribute.lazy? || object.instance_variable_defined?(attribute.instance_variable_name)
+ attribute.lazy? || attribute.defined?(object)
end
# Merge the attributes into the index
View
2 lib/virtus/instance_methods.rb
@@ -191,7 +191,7 @@ def set_default_attributes
#
# @api public
def set_default_attributes!
- attribute_set.set_defaults(self, proc { |_| false })
+ attribute_set.set_defaults(self, proc { |object, attribute| attribute.defined?(object) })
self
end
View
20 spec/unit/virtus/attribute/defined_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Virtus::Attribute, '#defined?' do
+ subject { object.defined?(instance) }
+
+ let(:object) { described_class.build(String, :name => name) }
+
+ let(:model) { Class.new { attr_accessor :test } }
+ let(:name) { :test }
+ let(:instance) { model.new }
+
+ context 'when the attribute value has not been defined' do
+ it { should be(false) }
+ end
+
+ context 'when the attribute value has been defined' do
+ before { instance.test = nil }
+ it { should be(true) }
+ end
+end
View
13 spec/unit/virtus/freeze_spec.rb
@@ -9,6 +9,7 @@
attribute :name, String, :default => 'foo', :lazy => true
attribute :age, Integer, :default => 30
+ attribute :rand, Float, :default => Proc.new { rand }
}
}
@@ -18,4 +19,16 @@
its(:name) { should eql('foo') }
its(:age) { should be(30) }
+
+ it "does not change dynamic default values" do
+ original_value = object.rand
+ object.freeze
+ expect(object.rand).to eq original_value
+ end
+
+ it "does not change default attributes that have been explicitly set" do
+ object.rand = 3.14
+ object.freeze
+ expect(object.rand).to eq 3.14
+ end
end

0 comments on commit 45ef710

Please sign in to comment.
Something went wrong with that request. Please try again.