我正在深入研究 ruby 元编程并有下一个问题。 示例:
module ExampleAliaser
def do_example_alias(prefix=:origin)
class_eval <<-EOS
class << self
alias_method :#{prefix}_example, :example
def example
puts "in aliase will call :#{prefix}_example"
#{prefix}_example
end
end
EOS
end
end
class Example1
def self.example
puts "Example"
end
end
Example1.extend(ExampleAliaser)
class Example1
do_example_alias(:origin)
end
class Example2 < Example1
do_example_alias(:origin)
end
Example1.example
in aliase will call :origin_example
Example
=> nil
Example2.example
in aliase will call :origin_example
in aliase will call :origin_example
in aliase will call :origin_example
SystemStackError: stack level too deep
from /Users/igorfedoronchuk/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/irb/workspace.rb:80
Maybe IRB bug!!
所以当 mixin 使用 2 次时会导致错误。 解决此类问题的最佳方法是什么?如何确定混合存在并在新的混合之前将其去除
最佳答案
遵循方法的定义,看看为什么会这样。
您首先在 Example1
的类定义中定义 Example1::example
。它向控制台写入一个字符串。
然后扩展 ExampleAliaser
。当您调用 Example1::do_example_alias
时,您将方法 example
别名为 origin_example
并将方法 example
重新定义为将不同的字符串写入控制台并调用 origin_example
。
然后定义继承自 Example1
的类 Example2
,它现在定义了两个方法:origin_example
和 example
。当您调用 Example2::do_example_alias
时,您将方法 example
别名为 origin_example
。但请记住,example
已被重新定义为调用 origin_example
。如此有效,Example2::example
将调用自身,直到堆栈空间用完。
如果你想避免双重别名,你可以在 do_example_alias
中包含某种守卫:
def do_example_alias(prefix = :origin)
unless methods.include?("#{prefix}_example")
# do the aliasing
end
end
您还可以在子类中undef :method_name
来删除您不再希望定义的方法。
关于继承类中的ruby method_alias,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9430755/