diff --git a/lib/active_attr/attributes.rb b/lib/active_attr/attributes.rb index 0c13c9e..65df7c0 100644 --- a/lib/active_attr/attributes.rb +++ b/lib/active_attr/attributes.rb @@ -57,7 +57,7 @@ def ==(other) # # @since 0.2.0 def attributes - attributes_map { |name| send name } + attributes_map { |name| attribute name } end # Returns the class name plus its attributes @@ -90,11 +90,8 @@ def inspect # # @since 0.2.0 def read_attribute(name) - if respond_to? name - send name.to_s - else - raise UnknownAttributeError, "unknown attribute: #{name}" - end + @attributes ||= {} + @attributes[name.to_s] end alias_method :[], :read_attribute @@ -112,11 +109,8 @@ def read_attribute(name) # # @since 0.2.0 def write_attribute(name, value) - if respond_to? "#{name}=" - send "#{name}=", value - else - raise UnknownAttributeError, "unknown attribute: #{name}" - end + @attributes ||= {} + @attributes[name.to_s] = value end alias_method :[]=, :write_attribute @@ -126,16 +120,22 @@ def write_attribute(name, value) # # @since 0.2.1 def attribute(name) - @attributes ||= {} - @attributes[name] + if self.class.attribute_names.include? name.to_s + read_attribute(name) + else + raise UnknownAttributeError, "unknown attribute: #{name}" + end end # Write an attribute to the attributes hash # # @since 0.2.1 def attribute=(name, value) - @attributes ||= {} - @attributes[name] = value + if self.class.attribute_names.include? name.to_s + write_attribute(name, value) + else + raise UnknownAttributeError, "unknown attribute: #{name}" + end end # Maps all attributes using the given block diff --git a/spec/unit/active_attr/attributes_spec.rb b/spec/unit/active_attr/attributes_spec.rb index 1c322a1..99565f7 100644 --- a/spec/unit/active_attr/attributes_spec.rb +++ b/spec/unit/active_attr/attributes_spec.rb @@ -201,8 +201,8 @@ def self.name end context "when a getter is overridden" do - it "uses the overridden implementation" do - model.attributes.should include("last_name" => last_name) + it "uses the original value" do + model.attributes.should include("last_name" => nil) end end end @@ -211,7 +211,7 @@ def self.name before { model.first_name = "Ben" } it "includes the class name and all attribute values in alphabetical order by attribute name" do - model.inspect.should == %{#} + model.inspect.should == %{#} end it "doesn't format the inspection string for attributes if the model does not have any" do @@ -219,12 +219,53 @@ def self.name end context "when a getter is overridden" do - it "uses the overridden implementation" do - model.inspect.should include %{last_name: "#{last_name}"} + it "uses the original value" do + model.inspect.should include %{last_name: nil} end end end + describe "#attribute" do + context "when an attribute is not set" do + it "raises when getting an undefined attribute" do + expect do + model.send(:attribute, :initials) + end.to raise_error UnknownAttributeError, "unknown attribute: initials" + end + end + + context "when an attribute is set" do + let(:first_name) { "Bob" } + + before { model.write_attribute(:first_name, first_name) } + + it "delegates to read_attribute" do + model.should_receive(:read_attribute).with(:first_name).and_return first_name + model.send(:attribute, :first_name).should == first_name + end + end + end + + describe "#attribute=" do + context "when an attribute is not set" do + it "raises when getting an undefined attribute" do + expect do + model.send(:attribute=, :initials, nil) + end.to raise_error UnknownAttributeError, "unknown attribute: initials" + end + end + + context "when an attribute is set" do + let(:first_name) { "Bob" } + + it "delegates to write_attribute" do + model.should_receive(:write_attribute).with(:first_name, first_name) + model.send(:attribute=, :first_name, first_name) + end + end + end + + [:[], :read_attribute].each do |method| describe "##{method}" do context "when an attribute is not set" do @@ -248,15 +289,15 @@ def self.name end context "when the getter is overridden" do - it "uses the overridden implementation" do - model.send(method, :last_name).should == last_name + it "uses the original value" do + model.send(method, :last_name).should be_nil end end - it "raises when getting an undefined attribute" do + it "doesn't raise when getting an undefined attribute" do expect do model.send(method, :initials) - end.to raise_error UnknownAttributeError, "unknown attribute: initials" + end.to_not raise_error end end end @@ -284,14 +325,16 @@ def self.name expect { model.send(method, :first_name, nil) }.to change { model.attributes["first_name"] }.from("Ben").to(nil) end - it "uses the overridden implementation when the setter is overridden" do - model.send(method, :last_name, "poweski").should == "POWESKI" + context "when the setter is overridden" do + it "uses the original value" do + model.send(method, :last_name, "poweski").should == "poweski" + end end - it "raises when setting an undefined attribute" do + it "doesn't raise when getting an undefined attribute" do expect do model.send(method, :initials, "BP") - end.to raise_error UnknownAttributeError, "unknown attribute: initials" + end.to_not raise_error end end end