Skip to content

Commit a848bff

Browse files
committed
Add attr_evaluated to StaticAssociation objects
`attr_evaluated` can be used to define an attribute who's return value is evaluated/computed at runtime. It defines a normal writer method using `attr_writer` which can take either a static value or a proc/lambda. If the latter, the reader method will evaluate the proc/lambda when called and return its value. This allows for defining dynamic runtime behaviour for specific record attributes. A static value can still be assigned like other non-evaluated attributes, and that value will always be returned. E.g. ```ruby class MyClass include StaticAssociation attr_accessor :toggle attr_evaluated :status record(id: 1) do self.toggle = true self.status = -> { toggle ? "on" : "off" } end record(id: 2) do self.toggle = true self.status = "static value" end end record1 = MyClass.find(1) record1.status # => "on" record2 = MyClass.find(2) record2.status # => "static value" ``` As with `attr_accessor` you can pass multiple attribute names to a single `attr_evaluated` call. ```ruby attr_evaluated :my_attr_1, :my_attr_2 ```
1 parent 07a9b5b commit a848bff

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

lib/static_association.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ def record(settings, &block)
8282
index[id] = record
8383
end
8484

85+
def attr_evaluated(*names)
86+
attr_writer(*names)
87+
88+
names.each do |name|
89+
define_method(name) do
90+
attr_evaluated = instance_variable_get("@#{name}")
91+
92+
if attr_evaluated.respond_to?(:call)
93+
instance_exec(&attr_evaluated)
94+
else
95+
attr_evaluated
96+
end
97+
end
98+
end
99+
end
100+
85101
private
86102

87103
def matches_attributes?(record:, attributes:)

spec/static_association_spec.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33

44
class DummyClass
55
include StaticAssociation
6+
67
attr_accessor :name
8+
attr_evaluated :gender
79
end
810

911
class AssociationClass
1012
attr_accessor :dummy_class_id
1113
attr_accessor :dodo_class_id
1214

1315
extend StaticAssociation::AssociationHelpers
16+
1417
belongs_to_static :dummy_class
1518
belongs_to_static :dodo_class, class_name: "DummyClass"
1619
end
@@ -75,6 +78,49 @@ class AssociationClass
7578
expect { DummyClass.record(id: 1) }.to change(DummyClass, :count).by(1)
7679
end
7780
end
81+
82+
context "when attr_evaluated defined attribute is assigned a lambda" do
83+
it "evaluates the lambda when the attribute is read" do
84+
record = DummyClass.record(id: 1) do
85+
self.gender = -> do
86+
if name == "Jane"
87+
:female
88+
else
89+
:male
90+
end
91+
end
92+
end
93+
94+
expect(record.gender).to eq(:male)
95+
end
96+
end
97+
98+
context "when attr_evaluated defined attribute is assigned a proc" do
99+
it "evaluates the proc when the attribute is read" do
100+
record = DummyClass.record(id: 1) do
101+
self.name = "Jane"
102+
self.gender = proc do
103+
if @name == "Jane"
104+
:female
105+
else
106+
:male
107+
end
108+
end
109+
end
110+
111+
expect(record.gender).to eq(:female)
112+
end
113+
end
114+
115+
context "when attr_evaluated defined attribute is assigned a static value" do
116+
it "returns the assigned value when the attribute is read" do
117+
record = DummyClass.record(id: 1) do
118+
self.gender = "Not disclosed"
119+
end
120+
121+
expect(record.gender).to eq("Not disclosed")
122+
end
123+
end
78124
end
79125

80126
describe ".all" do

0 commit comments

Comments
 (0)