Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read/write attribute directly from @attributes to match ActiveModel #122

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions lib/active_attr/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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
Expand Down
69 changes: 56 additions & 13 deletions spec/unit/active_attr/attributes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -211,20 +211,61 @@ 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 == %{#<Foo amount: nil, first_name: "Ben", last_name: "#{last_name}">}
model.inspect.should == %{#<Foo amount: nil, first_name: "Ben", last_name: nil>}
end

it "doesn't format the inspection string for attributes if the model does not have any" do
attributeless.new.inspect.should == %{#<Foo>}
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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down