Skip to content

Commit 42c27a5

Browse files
committed
Re-memoize methods in subclasses (fix #70)
This should fix some corner cases when inheritance is in play.
1 parent 92ba7de commit 42c27a5

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

lib/dry/core/memoizable.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ module Base
1313
def memoize(*names)
1414
prepend(Memoizer.new(self, names))
1515
end
16+
17+
def inherited(base)
18+
super
19+
20+
memoizer = base.ancestors.find { _1.is_a?(Memoizer) }
21+
base.prepend(memoizer.dup)
22+
end
1623
end
1724

1825
module BasicObject
@@ -79,7 +86,7 @@ def define_memoizable(method:)
7986
kernel = KERNEL
8087

8188
if parameters.empty?
82-
key = method.name.hash.abs
89+
key = "#{object_id}:#{method.name}".hash.abs
8390

8491
define_method(method.name) do
8592
value = super()

spec/dry/core/memoizable_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,29 @@ def initialize(*args, **kwargs, &block)
206206
expect(counter.value).to eql(3)
207207
end
208208
end
209+
210+
context "inheritance" do
211+
let(:subclass) { Class.new(klass) }
212+
213+
before do
214+
klass.define_method(:nodes) { [:root] }
215+
klass.define_method(:path) { [*nodes, :leaf] }
216+
klass.memoize(:nodes, :path)
217+
218+
subclass.define_method(:nodes) { [*super(), :node] }
219+
end
220+
221+
let(:subclass_instance) do
222+
subclass.new
223+
end
224+
225+
it "memoizes results separately" do
226+
expect(instance.nodes).to eql([:root])
227+
expect(instance.path).to eql([:root, :leaf])
228+
229+
expect(subclass_instance.nodes).to eql([:root, :node])
230+
expect(subclass_instance.path).to eql([:root, :node, :leaf])
231+
end
232+
end
209233
end
210234
end

0 commit comments

Comments
 (0)