ruby method_alias в унаследованном классе - PullRequest
2 голосов
/ 24 февраля 2012

Я углубляюсь в метапрограммирование 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 Ответ

1 голос
/ 24 февраля 2012

Следуйте определению методов, чтобы понять, почему это происходит.

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

...