方法super
调用基于__method__
的父方法。
如何基于__callee__
调用父方法?
class SomeLogic
DICTIONARY = {
new_method_1: 'dictionary value 1',
new_method_2: 'dictionary value 2'
}
def initialize(method_name)
@method_name = method_name
end
def call
DICTIONARY[@method_name]
end
end
module M
extend ActiveSupport::Concern
def base_method
logic = SomeLogic.new(__callee__).call
if logic
logic
elsif defined?(__callee__)
super # here analogue of super needed
else
{}
end
end
alias_method :new_method_1, :base_method
alias_method :new_method_2, :base_method
alias_method :new_method_3, :base_method
end
class A
prepend M
def new_method_3
'foo'
end
end
预期结果:
A.new.new_method_1 # dictionary value 1
A.new.new_method_2 # dictionary value 2
A.new.new_method_3 # foo
当前结果:
A.new.new_method_1 # dictionary value 1
A.new.new_method_2 # dictionary value 2
A.new.new_method_3 # no superclass method `base_method' for A
答案 0 :(得分:1)
如果您更改
class A
prepend M
到
class A
include M
您将获得所需的输出
答案 1 :(得分:0)
好的,这非常麻烦,但是可以按要求工作
class SomeLogic
DICTIONARY = {
new_method_1: 'dictionary value 1',
new_method_2: 'dictionary value 2'
}
def initialize(method_name)
@method_name = method_name
end
def call
DICTIONARY[@method_name]
end
end
module M
def self.prepended(base)
base.extend(ClassMethods)
end
def base_method(&block)
SomeLogic.new(__callee__).call ||
block&.call || # ruby < 2.3 block && block.call
{}
end
module ClassMethods
def method_added(method_name)
if M.instance_methods.include?(method_name)
orig = M.instance_method(method_name)
M.remove_method(method_name)
new = self.instance_method(method_name)
self.prepend(Module.new do
define_method(method_name) do
result = orig.bind(self).call(&new.bind(self))
end
end)
M.define_method(method_name, &orig.bind(M))
end
end
end
alias_method :new_method_1, :base_method
alias_method :new_method_2, :base_method
alias_method :new_method_3, :base_method
alias_method :new_method_4, :base_method
end
class A
prepend M
def new_method_3
'foo'
end
end
class B
prepend M
end
因此,当您定义一个新方法时,我们将检查该方法是否已由M
定义。如果是这样,那么我们捕获到UnboundMethod
从M
中删除方法,然后捕获新定义为UnboundMethod
,然后在匿名Module
中将新方法定义为{{ 1}}实现将新方法实现作为proc传递给M
实现,并将该模块放在定义的M
之前,然后我们将Class
的实现放回到{{1} },因此其他类别仍然有效。
结果:
M
如果您更喜欢M
而不是p A.new.new_method_1
#=> 'dictionary value 1'
p A.new.new_method_2
#=> 'dictionary value 2'
p A.new.new_method_3
#=> 'foo'
p A.new.new_method_4
#=> {}
p B.new.new_method_3
#=> {}
,那么include
可能看起来像
prepend