2012-03-27 20 views
8

Tôi có đoạn mã sau:Không hiểu lớp, Modules, và lớp << tự phương pháp

class MyClass 
    module MyModule 
    class << self 

     attr_accessor :first_name 

     def myfunction 
     MyModule.first_name = "Nathan" 
     end 

    end 
    end 
end 

Khi tôi gọi phương thức myfunction như vậy, nó hoạt động tốt:

> me = MyClass::MyModule.myfunction 
=> "Nathan" 
> me 
=> "Nathan" 

Nhưng nếu tôi đã xóa class << self và thêm tiền tố self. vào myfunction, nó sẽ không hoạt động.

Ví dụ:

class MyClass 
    module MyModule 

    attr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 


> me = MyClass::MyModule.myfunction 
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module 

Tôi đang cố gắng để hiểu được phương pháp class << self. Tôi nghĩ rằng đó là một cách thêm tiền tố self. cho tất cả các phương pháp bên trong của nó, nhưng nếu đó là sự thật, tại sao nó không hoạt động nếu tôi loại bỏ nó và tiền tố mỗi phương pháp với self. bằng tay?

Cảm ơn trước sự giúp đỡ của bạn.

+2

Nếu bạn thực sự muốn tìm hiểu chi tiết của Ruby Lập trình meta, tôi khuyên các [Metaprogramming của Ruby cuốn sách của Paolo Perrotta] (http://pragprog.com/book/ppmetr/metaprogramming-ruby) . – sarnold

Trả lời

7

Điều này là do attr_accessor :first_name của bạn cũng được bao bọc bởi class << self.

Để làm điều đó theo cách bạn gợi ý, bạn có thể sử dụng mattr_accessor như vậy:

require 'active_support' 

class MyClass 
    module MyModule 

    mattr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 
+0

Vì vậy, đây là một điều cụ thể đường ray dựa trên active_support? Tôi giả sử mattr_accessor là một phương pháp setter/getter cụ thể mô-đun? – Nathan

+0

Đúng vậy. Để tốt hơn hoặc tệ hơn, 'mattr_accessor' chỉ có thể truy cập thông qua Rails. – jnevelson

+0

Có một loạt các thứ mà đôi khi tôi muốn cũng có sẵn trong Ruby thông thường, không chỉ là Rails hoặc ActiveRecord. –

4

Để hiểu rõ hơn làm thế nào bạn có thể đạt được những gì bạn muốn, hãy nhìn vào ví dụ sau:

module PrintingModule 

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

    module ClassMethods 

    def class_method_of_class 
     puts "I am class #{self.name}" 
    end 

    end 

    def instance_method_of_class 
    puts "My name is: #{@name}" 
    end 

    class << self 
    def static_module_method 
     puts "Printer version 1.0" 
    end 
    end 
end 

class SomeObject 
    include PrintingModule 
    def initialize(name) 
    @name = name 
    end 
end 

object = SomeObject.new("Something") 
object.instance_method_of_class 
SomeObject.class_method_of_class 
PrintingModule.static_module_method 

Tôi hy vọng nó rõ ràng hơn bây giờ, lưu ý rằng đây chỉ là một trong những cách có thể (có những cách khác)

CẬP NHẬT: Tôi sẽ cố gắng cụ thể hơn. Khi bạn định nghĩa các phương thức instance/singleton trên module, những gì bạn đang thực sự làm là bạn định nghĩa các phương thức instance của lớp sẽ bao gồm module đó và mặt khác, các phương thức lớp được định nghĩa trên module sẽ trở thành các phương thức lớp của module đó. Điều thứ hai cần biết là attr_accessor tạo ra phương thức instance cho getter và setter của tham số đã cho.

Trả lời một phần câu hỏi của bạn, trong ví dụ đầu tiên bạn đang tạo 3 phương thức lớp trên lớp của mô-đun. Trong phương thức thứ hai, bạn đang tạo phương thức 1 lớp nơi bạn đang cố gắng truy cập một phương thức lớp khác (setter), nhưng getters và setters của bạn được định nghĩa là instance method = chúng sẽ trở thành instance của method class sẽ bao gồm module của bạn không thể nhận được cho họ theo cách này = bạn không có quyền truy cập vào getters và setters của bạn. Để giải thích về bản thân, tôi không giỏi lắm, nhưng theo như tôi biết, khi bạn sử dụng "class < < self" bạn đang mở eigenclass (mỗi đối tượng có riêng nó) của đối tượng (lưu ý rằng Lớp, mô-đun hoặc các thể hiện của các lớp cũng là các đối tượng của khóa học), nơi bạn đang định nghĩa các phương thức thể hiện. Class method của object trong Ruby = instance method của eigenclass của đối tượng. Vì vậy, bạn có thể làm điều này cho ví dụ:

text = "something" 
class << text 
    def say_hi 
    puts "Hi!" 
    end 
end 

text.say_hi 

Khi bạn tạo thể hiện của lớp (String trong ví dụ này), ví dụ mà được nó độc đáo của riêng lớp vô danh đó là lớp con của lớp đó. Trong ví dụ này, bạn đã định nghĩa phương thức cá thể trên eigenclass của lớp con ẩn danh của lớp String. Vì vậy, bạn có thể sử dụng phương thức "say_hi" trên đối tượng văn bản nhưng không sử dụng lớp String. Vì vậy, "class < < self" là mở những eigenclasses.

Mặt khác, "tự" một mình đại diện cho một đối tượng trong ngữ cảnh hiện tại, có nghĩa là giống nhau trong một số trường hợp (ví dụ: của bạn). Đối với phương thức self.included, nó chỉ là một phương thức gọi lại được gọi khi module được đưa vào lớp với tham số biểu diễn đối tượng (ở đây là SomeObject).

Tôi hy vọng rằng tôi đã trả lời ít nhất một phần câu hỏi của bạn. biết thêm thông tin ở đây: Difference between 'self.method_name' and 'class << self' in Ruby

+0

Tôi thấy bạn đang sử dụng mixin như thế nào, và hầu hết tất cả đều có ý nghĩa ngoại trừ 'def self.included (object) ...' lên hàng đầu. Vấn đề là mặc dù tôi không muốn tìm kiếm bất cứ thứ gì nhiều như tôi đang cố gắng hiểu hành vi. Tôi không chắc ví dụ của bạn đã giải thích tại sao 'class << self' làm việc với một mô-đun hỗn hợp nhưng tiền tố' .self' không khi cố gắng truy cập phương thức lớp. Trên thực tế, tôi đang bối rối trong ví dụ của tôi như thế nào phương pháp dụ: first_name có sẵn với một cuộc gọi lớp. – Nathan

+0

Tôi đã cập nhật câu trả lời của mình, tôi hy vọng câu trả lời đó sẽ trả lời ít nhất một phần câu hỏi của bạn. Chúc một ngày tốt lành. – Giron

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