Skip to content

Commit 21040dc

Browse files
Prepend ivar setup in included modules
Fixes #302 Co-authored-by: alpaca-tc <alpaca-tc@alpaca.tc>
1 parent 7cf8ed2 commit 21040dc

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

lib/memo_wise.rb

+19-4
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ module MemoWise
5454
# [this article](https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/)
5555
# for more information.
5656
#
57+
5758
# :nocov:
58-
all_args = RUBY_VERSION < "2.7" ? "*" : "..."
59-
# :nocov:
60-
class_eval <<~HEREDOC, __FILE__, __LINE__ + 1
59+
INITIALIZE_LITERAL = <<~HEREDOC
6160
# On Ruby 2.7 or greater:
6261
#
6362
# def initialize(...)
@@ -72,11 +71,14 @@ module MemoWise
7271
# super
7372
# end
7473
75-
def initialize(#{all_args})
74+
def initialize(#{RUBY_VERSION < "2.7" ? "*" : "..."})
7675
MemoWise::InternalAPI.create_memo_wise_state!(self)
7776
super
7877
end
7978
HEREDOC
79+
# :nocov:
80+
81+
class_eval(INITIALIZE_LITERAL, __FILE__, __LINE__ + 1)
8082

8183
module CreateMemoWiseStateOnExtended
8284
def extended(base)
@@ -94,6 +96,15 @@ def inherited(subclass)
9496
end
9597
private_constant(:CreateMemoWiseStateOnInherited)
9698

99+
module CreateMemoWiseStateOnIncluded
100+
def included(base)
101+
base.prepend(Module.new do
102+
class_eval(INITIALIZE_LITERAL, __FILE__, __LINE__ + 1)
103+
end)
104+
end
105+
end
106+
private_constant(:CreateMemoWiseStateOnIncluded)
107+
97108
# @private
98109
#
99110
# Private setup method, called automatically by `prepend MemoWise` in a class.
@@ -176,6 +187,10 @@ def memo_wise(method_name_or_hash)
176187
if klass.is_a?(Class) && !klass.singleton_class?
177188
klass.singleton_class.prepend(CreateMemoWiseStateOnInherited)
178189
else
190+
if klass.is_a?(Module) && !klass.singleton_class?
191+
klass.singleton_class.prepend(CreateMemoWiseStateOnIncluded)
192+
end
193+
179194
klass.prepend(CreateMemoWiseStateOnInherited)
180195
end
181196

spec/memo_wise_spec.rb

+42
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,32 @@ def module2_method
351351
end
352352
end
353353

354+
let(:klass_with_initializer) do
355+
Class.new do
356+
include Module1
357+
def initialize(*); end
358+
end
359+
end
360+
361+
let(:module_with_initializer) do
362+
Module.new do
363+
include Module1
364+
def initialize(*); end
365+
end
366+
end
367+
368+
let(:klass_with_module_with_initializer) do
369+
Class.new do
370+
include Module3
371+
end
372+
end
373+
354374
let(:instance) { klass.new }
355375

356376
before(:each) do
357377
stub_const("Module1", module1)
358378
stub_const("Module2", module2)
379+
stub_const("Module3", module_with_initializer)
359380
end
360381

361382
it "memoizes inherited methods separately" do
@@ -364,6 +385,27 @@ def module2_method
364385
expect(Array.new(4) { instance.module2_method }).to all eq("module2_method")
365386
expect(instance.module2_method_counter).to eq(1)
366387
end
388+
389+
it "can memoize klass with initializer" do
390+
instance = klass_with_initializer.new(true)
391+
expect { instance.module1_method }.not_to raise_error
392+
393+
expect(Array.new(4) { instance.module1_method }).to all eq("module1_method")
394+
expect(instance.module1_method_counter).to eq(1)
395+
end
396+
397+
it "can memoize klass with initializer" do
398+
instance = klass_with_module_with_initializer.new(true)
399+
expect { instance.module1_method }.not_to raise_error
400+
401+
expect(Array.new(4) { instance.module1_method }).to all eq("module1_method")
402+
expect(instance.module1_method_counter).to eq(1)
403+
end
404+
405+
it "can reset klass with initializer" do
406+
instance = klass_with_initializer.new(true)
407+
expect { instance.reset_memo_wise }.not_to raise_error
408+
end
367409
end
368410

369411
context "when the class, its superclass, and its module all memoize methods" do

0 commit comments

Comments
 (0)