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

Другие вопросы по тегам