Ruby Method_alias nella classe ereditata
-
12-11-2019 - |
Domanda
Sto profondendo nel metaprogrammazione di Ruby e ho la prossima domanda. Esempio:
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!!
Quindi, quando la mixin usata 2 volte causa l'errore. Qual è il modo migliore per sistemare tali cose? Come determinare che esiste la miscelazione e rimuoverlo prima di una nuova miscelazione
Soluzione
Segui la definizione di metodi per capire perché questo sta accadendo.
Per prima cosa definisci Example1::example
Nella definizione di classe di Example1
. Scrive una stringa alla console.
Quindi estendi ExampleAliaser
. Quando chiami Example1::do_example_alias
, quindi alias il metodo example
a origin_example
e ridefinire il metodo example
Per scrivere una stringa diversa alla console e chiama origin_example
.
Quindi definisci la classe Example2
ereditare da Example1
, che ora ha due metodi definiti su di esso: origin_example
e example
. Quando chiami Example2::do_example_alias
, alias il metodo example
a origin_example
. Ma ricordalo example
era già ridefinito per chiamare origin_example
. Così efficacemente, Example2::example
Si chiamerà finché non esaurirai lo spazio sullo stack.
Se vuoi evitare il doppio aliasing, potresti includere una sorta di guardia do_example_alias
:
def do_example_alias(prefix = :origin)
unless methods.include?("#{prefix}_example")
# do the aliasing
end
end
Puoi anche undef :method_name
Nelle sottoclassi per rimuovere i metodi che non si desidera più definire.