ruby method_alias en classe héritée
-
12-11-2019 - |
Question
Je suis deeping en ruby métaprogrammation et ont question suivante.Exemple:
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!!
Alors, quand mixin utilisé 2 fois, il provoque une erreur.Quelle est la meilleure façon de corriger de telles choses?Comment faire pour déterminer que le mélange existe et de le retirer avant que la nouvelle de mélange
La solution
Suivre la définition de méthodes pour voir pourquoi ce qui se passe.
Vous devez d'abord définir Example1::example
dans la définition de la classe de Example1
.Il écrit une chaîne de caractères dans la console.
Ensuite, vous étendre ExampleAliaser
.Lorsque vous appelez Example1::do_example_alias
, vous alias la méthode example
pour origin_example
et de redéfinir la méthode example
pour écrire une chaîne de caractère à la console et appel origin_example
.
Ensuite, vous définissez la classe Example2
pour hériter de Example1
, qui a désormais deux méthodes définies sur elle: origin_example
et example
.Lorsque vous appelez Example2::do_example_alias
, vous alias la méthode example
pour origin_example
.Mais rappelez-vous que example
a déjà été redéfini à l'appel origin_example
.Donc, effectivement, Example2::example
va s'appeler lui-même jusqu'à ce que vous manquez de place sur la pile.
Si vous voulez éviter les double-aliasing, vous pourriez inclure une sorte de garde do_example_alias
:
def do_example_alias(prefix = :origin)
unless methods.include?("#{prefix}_example")
# do the aliasing
end
end
Vous pouvez également undef :method_name
dans les sous-classes de méthodes de suppression que vous ne voulez plus défini.