Class Definitions trong ruby

Trước khi đi vào nội dung chính có một chú ý nhỏ với bạn đó là mọi thứ bạn học về class cũng có thể áp dụng cho modules.

Một số các khái niệm liên quan như self, accesstor_chain, reserver các bạn có thể tham khảo ở đây Method và blog trong ruby

I. Khái quát về class

Một ví dụ về class

2.1.5 :004 > class Viblo
2.1.5 :005?>   "Hi"
2.1.5 :006?>   "Welcome to Viblo"
2.1.5 :007?> end
 => "Welcome to Viblo"
  • Nhìn vào ví dụ trên ta cũng có thể thấy được class nó cũng giống như block hay method sẽ return ở câu lệnh cuối cùng.

  • Bản thân class cũng tuân theo quy tắc của current object self.

  • Class chỉ đơn giản object, và tên của class là hằng số(constant)

1. current class

  • Bất cứ khi nào bạn mở một class với từ khóa class (hay module với từ khóa module) thì class này sẽ trở thành current class.

ví dụ:

    class Viblo
        #current clas là Viblo

        def topics
        end
    end
  • current class giống với self - class definition
  • Tất cả các method thông thường được định nghĩa bên trong sẽ trở thành instance method của current class (như trên thì ta có instance method topics)

2. class_eval()

  • Nó được sử dụng để add method vào class, nó là một method trong Module và nó khá giống với instance_eval(). Ngoài ra thì class_eval() nó còn có một tên khác nữa là module_eval().

  • Sự khác biệt giữa instance_eval()class_eval() ở đây là gì? Câu trả lời là instance_eval() chỉ thay đổiselfcòn class_eval() thay đổi cả self và current class. DO thay đổi class nên nó rất hữu ích trong việc mở class và làm một số việc trong đó thay vì bạn phát viết mở class + class name.

  • Nếu bạn muốn thay đổi object mà nó không phải là class thì sử dụng instance_eval() nhưng nếu bạn muốn mở một class và định nghĩa một phương thức bên trong đó thì class_eval() là sự lựa chọn đúng đắn.

    ví dụ:

        def add_method_to(class_name)
            class_name.class_eval do
                def topics
                    "many topics here"
                end
            end
        end
Từ ví dụ trên bạn có thể thấy class_eval() cho phép ta add method vào trong bất kỳ một class nào mà không biết tên trước.

3. Class instance variables

  • Trong class tất cả các instance variable đều thuộc về curent object self (self lúc này là class). Instance variable ucar class thì khác với instance variable object của class.
    class Viblo
        @language = "Vietnamese"
        def self.show
            @language
        end

        def change
            @language = "Japanese"
        end

        def show
            @language
        end
    end
2.1.5 :040 > Viblo.show
 => "Vietnamese"
2.1.5 :041 > Viblo.new.show
 => nil
2.1.5 :042 >

Từ ví dụ trên bạn thấy dường như @language ở đây nằm trong scope khác nhau và nó là hai biến không bị ảnh hưởng lẫn nhau.

2.1.5 :045 > vib = Viblo.new
 => #<Viblo:0x00000001abfc88>
2.1.5 :046 > vib.show
 => nil
2.1.5 :047 > vib.change
 => "Japanese"
2.1.5 :048 > vib.show
 => "Japanese"
2.1.5 :049 > Viblo.show
 => "Vietnamese"
Có nói như sau: `@language` được định nghĩa với object `vib` và nó là một instance variable của object `vib`. Còn biến `@language` định nghĩa ngay bên dưới từ khóa *class Viblo* là một instance variable của class `Viblo` (Class instance variable).

Tóm lại: Class instance variable chỉ có thể truy cập bởi chính bản thân class, các instance của class hoặc subclass không thể truy cập được.

Vậy để thay đổi được biến language đó ở mọi nơi trong class thì làm thế nào. ta sẽ đi đến phần tiếp theo

4. Class variables

  • Class variable khác với class instance variable bởi chúng cho thể được truy cập bởi bản thân class, subclass, hay các instance method thông thường. Chúng được định nghĩa bắt đầu với tiền tố @@(@@language chẳng hạn)
        class Viblo
            @@language = "Vietnamese"
            def self.show
                @@language
            end

            def change
                @@language = "Japanese"
            end

            def show
                @@language
            end
        end
        2.1.5 :080 > obj = Viblo.new
         => #<Viblo:0x00000001ca7de8>
        2.1.5 :081 > obj.show
         => "Vietnamese"
        2.1.5 :082 > Viblo.show
         => "Vietnamese"
        2.1.5 :083 > obj.change
         => "Japanese"
        2.1.5 :084 > Viblo.show
         => "Japanese"
        2.1.5 :085 >

II. Singleton Methods

1. Singleton Methods là gì?

  • Là việc add một method vào trong một object.
2.1.5 :085 > str = "welcome to viblo"
 => "welcome to viblo"
2.1.5 :086 > def str.up_case
2.1.5 :087?>   self.upcase
2.1.5 :088?> end
 => :up_case
2.1.5 :089 > str
 => "welcome to viblo"
2.1.5 :090 > str.up_case
 => "WELCOME TO VIBLO"

Như ví dụ trên thì ta không quan tâm đến str là object str là của class nào mà vẫn có thể định nghĩa cho nó một phương thức, nhưng chỉ với object str có phương thức đó còn các object khác thì không.

    2.1.5 :091 > str_new = "Ruby on Rails"
    => "Ruby on Rails"
    2.1.5 :092 > str_new.up_case
    NoMethodError: undefined method `up_case' for "Ruby on Rails":String

2. Class methods

  • Có một vài cách để định nghĩa một class method
        class Viblo
            def self.class_method_1
            end

            def Viblo.class_method_2
            end

            class << self
                def class_method_3
                end
            end
        end
  • Cách thứ 3 là cách mà mọi người thường hay sử dụng nhất. giờ hay xem cách khai báo của class_method_1class_method_2 và so sánh với ví dụng trước str.up_case. Cách khai báo là hoàn toàn giống nhau, và cách gọi cũng vậy
    str.up_case
    Viblo.class_method_1
  • Thực ra thì class method chính là Signeleton method của class.

Và đề tìm hiểu sâu hơn nữa về singleton method ta sẽ đi đến phần tiếp theo

**4. Eigenclasses **

  • Singleton method của class không sống trong object cũng không sống trong class vậy nó sống ở đâu? Có một class mà bạn không thể thấy nó được, nó là một class đặt biệt, một class ẩn và nó có tên là Eigenclass của object. Và đó là nơi mà Singleton method cư trú 😃.
  • Eigenclass chỉ có duy nhất một instance .
    class Object
        def eigenclass
            class << self
                self
            end
        end
    end
2.1.5 :110 > "viblo".eigenclass
 => #<Class:#<String:0x00000001cf6600>>
  • Nếu trong một object có eigenclass ruby sẽ tìm kiếm phương thức bên trong eigenclass trước thay vì tìm các method thông thường. Nếu như ruby không tìm thấy phương thức trong eigenclass thì nó sẽ tìm theo ancestors chain

** Eigenclasses và kế thừa**

Dấu # sẽ được đánh dấu là eigenclass (#D là eigenclass của class D) super_eigen.jpg

Nhìn vào hình vẽ trên cho ta thấy: superclass của Eigenclass #obj là class D, superclass của eigenclass #D là eigenclass #C (eigenclass của class C).

  • Ta có kết luận sau: superclass của eigenclass của một object là class của object đó. superclass của eigenclass của một class là eigenclass của superclass của class.

5. Module và các vấn đề

  • Khi một class include một module nó sẽ lấy tất các instance_method của module, không lấy class method của module
    module MyModule
        def self.my_method
            'hello'
        end
    end
    class MyClass
        include MyModule
    end
2.1.5 :125 > MyClass.my_method
NoMethodError: undefined method `my_method' for MyClass:Class

Để include được ta phải dùng đến Eigenclass

    module MyModule
        def my_method
            'hello'
        end
    end
    class MyClass
        class << self
            include MyModule
        end
    end
2.1.5 :136 >  MyClass.my_method
 => "hello"
  • my_method lúc này trở thành instance method của eigenclass của MyClass. lúc này nó cũng là một class method của Myclass. công nghệ này gọi là Class Extension