ruby method_alias в унаследованном классе
Я углубляюсь в метапрограммирование 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 раза, это вызывает ошибку. Каков наилучший способ исправить такие вещи? Как определить, что смешивание существует, и удалить его до нового смешивания
1 ответ
Следуйте определению методов, чтобы понять, почему это происходит.
Вы сначала определяете Example1::example
в определении класса Example1
, Он записывает строку в консоль.
Тогда вы расширяете ExampleAliaser
, Когда вы звоните Example1::do_example_alias
, ты тогда псевдоним метод example
в origin_example
и переопределить метод example
записать в консоль другую строку и вызвать origin_example
,
Затем вы определяете класс Example2
наследовать от Example1
, который теперь имеет два метода, определенных на нем: 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
в подклассах, чтобы удалить методы, которые вы больше не хотите определять.