2012-02-24 3 views
1

Я углубляюсь в метапрограммирование ruby ​​и задаю следующий вопрос. Пример:ruby ​​method_alias в унаследованном классе

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 раза это вызывает ошибку. Каков наилучший способ исправить такие вещи? Как определить, что перемешивание существует и удалить его перед новым смешиванием

+0

исправить то, что именно? – psyho

+0

уровень стека слишком глубокий, прокрутите вниз блок источника – Fivell

+0

doh, не заметили полосу прокрутки: | – psyho

ответ

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 в подклассах, чтобы удалить методы, которые вы больше не хотите определены.

+0

Да, я понимаю это, мой вопрос о том, как изменить модуль, чтобы он мог узнать, что он был расширен ранее, и переопределить псевдонимы снова – Fivell

+0

Я имею в виду, как резонировать такие конфликты, если модуль был расширен ранее. Также, если Example2 вызовет do_example_alias (: other_prefix), как удалить ранее определенные псевдонимы? – Fivell

+0

Извините, я даже не видел ваш последний абзац после блока кода. Я уточню свой ответ. – Brandan

Смежные вопросы