2012-04-11 26 views
5

Sau đây là một Ruby đoạn mã từ Why's Poignant Guide to Ruby Chapter 6, nơi ông cố gắng để chứng minh lập trình meta trong Ruby:Mã Ruby này làm gì ?: def self.metaclass; lớp << tự; tự; kết thúc; cuối

# Get a metaclass for this class 
def self.metaclass; class << self; self; end; end 

Tôi không phải là rất quen thuộc với Ruby, nhưng là này những gì nó sẽ như thế nào ở dạng mở rộng?

def self.metaclass 
    def self.self 
    end 
end 

Ít nhất đó là cách tôi hiểu điều đó. Tuy nhiên, nó vẫn không hiểu chính xác mã này là gì. Mục đích của nó là gì?

Tiếp tục trên trong các mã, Tại sao bổ sung này:

arr.each do |a| 
    metaclass.instance_eval do 
    define_method(a) do |val| 
     @traits ||= {} 
     @traits[a] = val 
    end 
    end 
end 

Nếu tôi hiểu nó một cách chính xác, đoạn mã này cho biết thêm một giá trị mới cho @traits với tên và giá trị nhất định. Điều đó có đúng không?

Nhờ sự giúp đỡ của bạn, đây là toàn bộ mã nguồn đó khiến tôi gặp khó khăn, cho bất cứ ai muốn nhìn thấy nó:

# The guts of life force within Dwemthy's Array 
class Creature 

# Get a metaclass for this class 
def self.metaclass; class << self; self; end; end 

# Advanced metaprogramming code for nice, clean traits 
def self.traits(*arr) 
return @traits if arr.empty? 

# 1. Set up accessors for each variable 
attr_accessor *arr 

# 2. Add a new class method to for each trait. 
arr.each do |a| 
    metaclass.instance_eval do 
    define_method(a) do |val| 
     @traits ||= {} 
     @traits[a] = val 
    end 
    end 
end 

# 3. For each monster, the `initialize' method 
# should use the default number for each trait. 
class_eval do 
    define_method(:initialize) do 
    self.class.traits.each do |k,v| 
     instance_variable_set("@#{k}", v) 
    end 
    end 
end 

end 

# Creature attributes are read-only 
traits :life, :strength, :charisma, :weapon 
end 

Và trong sử dụng:

class Dragon < Creature 
    life(1340)  # tough scales 
    strength(451) # bristling veins 
    charisma(1020) # toothy smile 
    weapon(939) # fire breath 
end 
+3

Đọc: http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ – Phrogz

+0

Cảm ơn, điều này có vẻ hữu ích. Nhưng tôi thực sự muốn hiểu ý nghĩa của def self.metaclass; lớp << tự; tự; kết thúc; kết thúc. – LonelyWebCrawler

Trả lời

5
class Foo 
    def self.bar # Create a method invoked by Foo.bar instead of Foo.new.bar 
    42   # the return value of this method (value of last expression) 
    end 
end 


class Foo 
    def self.jim # Another method on the class itself 
    class << self # Change the 'self' to be the metaclass of the current object 
     self  # Evaluate the current 'self' as the 'return value' of 
    end   # class<<self…end; and since this is the last expression in 
    end    # the method, its value is the return value for the method 
end 

Tóm lại: những gì bạn đang thấy định nghĩa một phương thức có tên là metaclass trên chính lớp Creature (không phải cho các phiên bản). Khi bạn chạy phương pháp này, nó tìm thấy metaclass của Creature và trả về điều đó.

Read around the 'net để biết "metaclass" của đối tượng là gì.

+0

Cảm ơn bạn. Tôi có đúng là điều này không cần thiết nữa với #define_singleton_method không? – LonelyWebCrawler

+2

Nếu bạn chỉ muốn sử dụng metaclass để xác định một phương pháp, không, nó không cần thiết. Nhưng nếu bạn muốn truy cập vào metaclass vì các lý do khác (ví dụ: liệt kê tất cả các phương thức) thì phương pháp đó không cắt nó. Tuy nhiên, những gì nó cắt được giới thiệu trong 1.9.2 ['singleton_class'] (http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class) phương thức thực hiện cùng chức năng này. – Phrogz

2

Ở dạng mở rộng nó trông giống hệt nhau:

def self.metaclass 
    class << self 
    self 
    end 
end 

Thông báo nó chỉ trở self, mà bởi vì nó được đánh giá trong bối cảnh của metaclass, mà trên thực tế những gì class << self làm, self là metaclass.

Với việc giới thiệu những thứ như define_singleton_method, số lượng trường hợp bạn cần có quyền truy cập vào metaclass trực tiếp đang trở nên rất nhỏ.

Đó là tất cả very complicated và dường như là hậu quả của nguyên tắc thiết kế "mọi thứ là đối tượng".

+0

Whoa, bạn có thể làm rõ đoạn đó bắt đầu với "Thông báo nó chỉ ..."? – LonelyWebCrawler

+1

Vâng, nội dung của khối bên trong đơn giản là 'self' có tác dụng trả về từ khối đó bởi vì không có câu lệnh nào khác được thực thi. – tadman

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