2011-08-25 33 views
5

Có thể thực hiện công việc này mà không cần phải bao gồm mô-đun ở cuối lớp và chỉ bao gồm mô-đun ở trên cùng không?Mô-đun để bọc một phương pháp lớp học?

module VerboseJob 
    def self.included(job_class) 
    class << job_class 
     alias_method :original_perform, :perform 
     def perform(*args) 
     JobLogger.verbose { original_perform(*args) } 
     end 
    end 
    end 
end 

class HelloJob 
    include VerboseJob 

    def self.perform(arg1, arg2) 
    puts "Job invoked with #{arg1} and #{arg2}" 
    end 
end 

Những gì tôi muốn xảy ra, là cho HelloJob.perform để thực sự gọi VerboseJob.perform (mà sau đó gọi phương thức ban đầu bên trong một khối). Vì mô-đun ở đây được bao gồm ở đầu lớp, điều này không có tác dụng, vì perform chưa được xác định. Di chuyển các include đến cùng không làm việc, nhưng có một cách đó là một chút tha thứ hơn? Tôi muốn giữ tất cả các mô-đun đi kèm ở đầu các định nghĩa lớp của tôi.

Tôi sắp tìm một số phương thức được gọi là Module hoặc Class khi được tải đầy đủ, thay vì được giải thích bởi thời gian chạy.

Trả lời

2

Đây là một chiều/hackish thay vòng xoay để làm việc đó mà tôi đã đưa ra bằng cách trì hoãn việc xác định các phương pháp wrapper cho đến khi phương pháp ban đầu đã được xác định:

module A 
    def self.included(base) 
    base.class_eval do 
     def self.singleton_method_added(name) 
     @@ran||=false 
     if name==:perform && [email protected]@ran 
      @@ran=true 
      class<<self 
      alias_method :original_perform, :perform 
      def perform(*args) 
       puts "Hello" 
       original_perform(*args) 
      end 
      end 
     end 
     end 
    end 
    end 
end 

class B 
    include A 

    def self.perform 
    puts "Foobar" 
    end 
end 

B.perform 

Edit:

d11wtq đã đơn giản hóa tính năng này thành nhiều hơn:

module VerboseJob 
    module ClassMethods 
    def wrap_perform! 
     class << self 
     def perform_with_verbose(*args) 
      JobLogger.verbose { perform_without_verbose(*args) } 
     end 

     alias_method_chain :perform, :verbose \ 
      unless instance_method(:perform) == instance_method(:perform_with_verbose) 
     end 
    end 

    def singleton_method_added(name) 
     wrap_perform! if name == :perform 
    end 
    end 

    def self.included(job_class) 
    job_class.extend ClassMethods 
    job_class.wrap_perform! if job_class.respond_to?(:perform) 
    end 
end 
+0

Tại sao không chỉ sử dụng 'method_added' để bọc' hoạt động' khi nó được .. er .. thêm? :) –

+2

Tôi không chắc chắn tôi có ý nghĩa của bạn, tôi không làm điều đó? –

+2

Tôi lấy câu trả lời của bạn (kết hợp với http://pivotallabs.com/users/rolson/blog/articles/1162-redefine-a-method-from-a-module-like-a-gentleman này) và đã đưa ra ngắn gọn hơn https://gist.github.com/1170661 (nó hoạt động không có vấn đề nơi 'bao gồm' được thực hiện). Vui lòng chỉnh sửa câu trả lời của bạn. Tôi vẫn chấp nhận nó :) – d11wtq

-1

Giả sử bạn muốn tất cả các lớp học của bạn được xác định trước đó bạn muốn perform chạy, bạn có thể muốn sử dụng Kernel#at_exit:

Chuyển đổi khối đến một đối tượng Proc (và do đó liên kết với nó tại điểm của cuộc gọi) và đăng ký nó để thực hiện khi thoát khỏi chương trình. Nếu nhiều trình xử lý được đăng ký, chúng được thực hiện theo thứ tự ngược lại đăng ký.

def do_at_exit(str1) 
    at_exit { print str1 } 
    end 
    at_exit { puts "cruel world" } 
    do_at_exit("goodbye ") 
    exit 

sản xuất:

tạm biệt thế giới độc ác

Bạn cũng có thể muốn xem xét cách kiểm tra đơn vị khuôn khổ, chẳng hạn như Test :: Đơn vị hoặc MiniTest, xử lý kéo dài thời gian chạy các nhiệm vụ.

+0

Tôi không chắc tôi hiểu cách điều này liên quan đến câu hỏi của tôi, đó là về "gói" một phương thức lớp/thể hiện từ bên trong một Mô-đun đi kèm? – d11wtq

+0

@ d11wtq: Tôi đang cố gắng giải quyết vấn đề mà bạn có một cách phù hợp nhất. Xem [Mô tả mục tiêu, không phải là bước] (http://catb.org/~esr/faqs/smart-questions.html#goal) –

Các vấn đề liên quan