2013-02-17 19 views
5

Làm thế nào để xác định các biến lớp bên trong một khối class_eval? Tôi có những điều sau đây:Xác định các biến lớp bên trong class_eval bên trong Module # include

module Persist 
    def self.included(base) 
     # base is the class including this module 
     base.class_eval do 
      # class context begin 
      @@collection = Connection.new.db('nameofdb').collection(self.to_s.downcase) 
      def self.get id # Class method 
       #... 
      end 
     end 
    end 
    # Instance methods follow 
    def find 
     @@collection.find().first 
     #... 
    end 
end 

class User 
    include Persist 
end 

class Post 
    include Persist 
end 

Các lớp tài khoản và Bưu cả hiển thị :get khi introspecting sử dụng User.methods hoặc Post.methods. Điều này có ý nghĩa, vì chúng được định nghĩa trong ngữ cảnh của class_eval và chính xác là những gì tôi cần. Tương tự, phương thức :find được hiển thị dưới dạng instance_method của các lớp riêng lẻ.

Tuy nhiên, điều tôi nghĩ là biến lớp tức là @@collection, hóa ra là một cấp Mô-đun class_variable. Khi tôi quan sát User.class_variables hoặc Post.class_variables, chúng sẽ trống. Tuy nhiên Persist.class_variables hiển thị :@@collection.

Làm cách nào có thể? Không phải là bối cảnh bên trong khối class_eval của lớp học. Vì vậy, không nên biến @@collection được xác định trên lớp và không phải là mô-đun?

Ngoài ra, giá trị của @@collection luôn là tên của lớp cuối cùng bao gồm nó. Vì vậy, trong trường hợp này, nó luôn là 'bài viết' và không bao giờ là 'người dùng'. Tôi nghĩ rằng điều này là bởi vì nó là một biến cấp mô-đun, nó sẽ thay đổi trên mỗi bao gồm. Điều này có đúng không?

Cuối cùng, làm cách nào để xác định biến lớp trong ngữ cảnh này để mỗi lớp có định nghĩa riêng là @@collection.

Trả lời

5

Một phương pháp sẽ là tạo phương thức truy cập cho biến lớp.

module Persist 
    def self.included(base) 
     # Adds class methods from 'ClassMethods' to including class. 
     base.extend(ClassMethods) 
     base.class_eval do 
      self.collection = Connection.new.db('nameofdb').collection(self.to_s.downcase) 
      # ... 
     end 
    end 
    module ClassMethods 
     def collection=(value) 
      @@collection = value 
     end 
     def collection 
      @@collection 
     end 
    end 
    # Instance methods follow 
    def find 
     self.class.collection.find().first 
     #... 
    end 
end 

class User 
    include Persist 
end 

class Post 
    include Persist 
end 

phương pháp khác sẽ được tiếp cận các biến lớp của bao gồm lớp trong mô-đun thông qua accessors class_variable_set vv

def self.included(base) 
    base.class_eval do 
     class_variable_set('@@collection', Connection.new.db('nameofdb').collection(self.to_s.downcase)) 
     # … 
    end 
end 

tôi sẽ mất một đâm vào trả lời câu hỏi của bạn " Làm thế nào là điều này có thể? Không phải là bối cảnh bên trong khối class_eval của lớp. "

Phương thức class_eval tự làm tự tham chiếu đến lớp mà nó đang được gọi vào bên trong khối nhất định. Điều này cho phép bạn gọi các phương thức lớp, vv Tuy nhiên, các biến lớp sẽ được đánh giá trong ngữ cảnh mà khối được ràng buộc - ở đây, mô-đun.

Ví dụ, hãy thử làm điều này:

class Foo 
    @@bar = 1 
end 

Foo.class_eval { puts @@bar } 

Điều này sẽ dẫn đến việc ngoại lệ "NameError: uninitialized lớp biến @@ thanh trong Object". Ở đây khối đã cho được gắn với ngữ cảnh của "Đối tượng", không gian tên cấp cao nhất.

+0

Cảm ơn! Một lời giải thích rất rõ ràng. Tôi đã kết thúc bằng cách sử dụng class_variable_set. –

+1

sử dụng ClassMethods cũng tạo các biến tĩnh liên quan đến mô-đun ... – Geoffroy

+0

Câu trả lời này cần được sửa. Phương pháp đầu tiên được trình bày bằng mô-đun ClassMethods không hoạt động để khắc phục sự cố của câu hỏi. Các biến lớp được khai báo cũng có phạm vi mô đun và do đó được chia sẻ trên tất cả các lớp. Phương thức 'class_variable_set' không hoạt động, và phải là thông tin duy nhất trong câu trả lời này –

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