2012-04-06 30 views
15
module Test 
    def self.model_method 
    puts "this is a module method" 
    end 
end 

class A 
    include Test 
end 

A.model_method 

này sẽ lỗi với:Tại sao phương pháp 'tự' của mô-đun không thể trở thành một phương thức đơn lớp?

phương pháp xác định 'model_method' cho A: Class (NoMethodError)

Nhưng khi tôi sử dụng metaclass của A. hoạt động:

module Test 
    def model_method 
    puts "this is a module method" 
    end 
end 

class A 
    class << self 
    include Test 
    end 
end 

A.model_method 

Ai đó có thể giải thích điều này?

+1

thể trùng lặp của [? Là có thể để xác định một phương pháp lớp học trong một module] (http://stackoverflow.com/questions/4699355/is-that-possible-to-define -a-class-method-in-a-module) –

Trả lời

32

Nếu bạn muốn có cả hai phương pháp lớp học và phương pháp dụ trộn vào một lớp khi bao gồm một mô-đun, bạn có thể làm theo các mô hình:

module YourModule 
    module ClassMethods 
    def a_class_method 
     puts "I'm a class method" 
    end 
    end 

    def an_instance_method 
    puts "I'm an instance method" 
    end 

    def self.included(base) 
    base.extend ClassMethods 
    end 
end 

class Whatever 
    include YourModule 
end 

Whatever.a_class_method 
# => I'm a class method 

Whatever.new.an_instance_method 
# => I'm an instance method 

Về cơ bản để quá đơn giản hóa nó, bạn extend để thêm các phương pháp lớp và bạn include để thêm các phương thức thể hiện. Khi một mô-đun được bao gồm, phương thức #included được gọi, với lớp thực tế mà nó được bao gồm. Từ đây bạn có thể extend lớp đó với một số phương thức lớp từ một mô-đun khác. Đây là một mô hình khá phổ biến.

Xem thêm: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

11

Bao gồm một mô-đun tương tự như sao chép các phương thức thể hiện của nó.

Trong ví dụ của bạn, không có phương pháp thể hiện nào để sao chép sang A. model_method thực sự là một phương pháp thể hiện của lớp singleton của Test.


Given:

module A 
    def method 
    end 
end 

này:

module B 
    include A 
end 

là tương tự như này:

module B 
    def method 
    end 
end 

Khi bạn nghĩ về nó theo cách này, điều này làm cho cảm giác hoàn hảo:

module B 
    class << self 
    include A 
    end 
end 

B.method 

Ở đây, các phương pháp đang được sao chép vào lớp đơn của mô-đun B, làm cho chúng trở thành "phương pháp lớp" của B.

Lưu ý rằng đây là chính xác những điều tương tự như:

module B 
    extend A 
end 

Trên thực tế, phương pháp này không được sao chép; không có sự trùng lặp nào. Mô-đun này chỉ được bao gồm trong danh sách tra cứu phương pháp.

+1

Đối với người mới bắt đầu như tôi, cuộc thảo luận này về sự khác biệt giữa mở rộng và bao gồm tại http: //www.railstips.org/blog/lưu trữ/2009/05/15/include-vs-extend-in-ruby/rất hữu ích khi đọc cùng với bài đăng này. –

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