2013-07-05 19 views
8

Tôi đã cố gắng tìm hiểu cách mở rộng hành vi của initialize từ mô-đun. Tôi muốn làm điều đó mà không cần gọi siêu trong số initialize của lớp đang được trộn vào. Tôi muốn hỗ trợ kiểu gọi thông thường include Tôi không thể hiểu được. Tôi đã đọc tất cả mọi thứ tôi có thể tìm thấy về vấn đề này và, trong khi mọi người có đề xuất, không ai trong số họ thực sự có vẻ làm việc (trong tay tôi ít nhất).Có thể ghi đè #initialize trong mô-đun Ruby không?

Dưới đây là những gì tôi (nghĩ) Tôi biết:

  • Nếu nó có thể được thực hiện ở tất cả, nó phải được thực hiện bằng cách sử dụng móc trên include (ví dụ: Module.included(base)).
  • Móc include sẽ thực thi trước khi lớp bao gồm xác định initialize do đó không có điểm để chỉ đơn giản là cố gắng xác định initialize với base.instance_eval vì nó sẽ bị ghi đè.
  • Một đề xuất đã được thực hiện để sử dụng móc method_added và xử lý nó trong đó. Đó là những gì tôi đang thử bây giờ nhưng có vẻ như móc thực hiện ở đầu định nghĩa phương thức để bạn kết thúc với những gì bạn thấy bên dưới.

    module Mo 
        def self.included(klass) 
        klass.instance_eval do 
         def method_added(method) 
         puts "Starting creation of #{method} for #{self.name}" 
         case method 
         when :initialize 
          alias_method :original_initialize, :initialize 
          puts "About to define initialize in Mo" 
          def initialize 
          original_initialize 
          puts "Hello from Mo#initialize" 
          end 
          puts "Finished defining initialize in Mo" 
         end 
         puts "Finishing creation of #{method} for #{self.name}" 
         end 
        end 
        end 
    end 
    
    class Foo 
        include Mo 
        def initialize 
        puts "Hello from Foo#initialize" 
        end 
    end 
    
    foo = Foo.new 
    

Điều này dẫn đến kết quả như sau:

Starting creation of initialize for Foo 
    Starting creation of original_initialize for Foo 
    Finishing creation of original_initialize for Foo 
    About to define initialize in Mo 
    Finished defining initialize in Mo 
    Finishing creation of initialize for Foo 
    Hello from Foo#initialize 

Có vẻ với tôi như initialize từ lớp Foo vẫn ghi đè lên các định nghĩa từ các mô-đun. Tôi đoán rằng điều này là bởi vì định nghĩa vẫn còn mở, cho thấy rằng nó không phải là vấn đề mà khối được bắt đầu cuối cùng được hoàn thành cuối cùng mà "thắng".

Nếu có ai đó thực sự biết cách làm điều này và làm việc đó, hãy làm sáng tỏ tôi.

FWIW, vâng, tôi nghĩ tôi có lý do chính đáng để làm điều này.

Trả lời

24

Nếu bạn sử dụng phiên bản Ruby 2.0 trở lên, bạn chỉ có thể sử dụng prepend. Hoặc yêu cầu người dùng prepend hơn include, hoặc làm:

module Mo 
    module Initializer 
    def initialize 
     puts "Hello from Mo#initialize" 
     super 
    end 
    end 

    def self.included(klass) 
    klass.send :prepend, Initializer 
    end 
end 
+0

Tôi phát hiện ra 'prepend' ngay sau khi đặt câu hỏi. Tôi thích nó! Vẫn còn tò mò nếu có một cách để làm điều đó trong 1.9. * – Huliax

+0

Có điều gì hiển nhiên tôi thiếu trong việc sử dụng 'klass.send: prepend' thay vì đơn giản' klass.prepend'? – NobodysNightmare

0

Bạn có thỏa mãn khi có cuộc gọi có điều kiện trong khởi tạo của Foo mà chỉ gọi một phương thức được bao gồm nếu nó có mặt không?

module Mo 
    def initialize_extra 
    puts "Hello from Mo" 
    end 
end 

class Foo 
    include Mo 
    def initialize 
    if defined? initialize_extra 
     initialize_extra 
    else 
     puts "Hello from Foo" 
    end 
    end 
end 

x = Foo.new 
+1

Mục tiêu của tôi là không đặt bất kỳ gánh nặng nào lên lớp ngoài nhu cầu bao gồm mô-đun. – Huliax

6

Ok, cũng trong Ruby 1.9 bạn có thể thêm chức năng cho các phương pháp new lớp ...

module Mo 
    def new(*var) 
    additional_initialize(*var) 
    super(*var) 
    end 
    def additional_initialize(*var) 
    puts "Hello from Mo" 
    end 
end 

class Foo 
    extend Mo 
    def initialize 
    puts "Hello from Foo" 
    end 
end 

foo = Foo.new 

Đó trả ...

Hello from Mo 
Hello from Foo 
Các vấn đề liên quan