12/08/2018, 14:45

Tìm hiểu sâu về Ruby Modules

Modules có một cấu trúc ngôn ngữ linh hoạt, nó được ứng dụng một cách rộng rãi trong nhiều trường hợp khác nhau, chẳng hạn như namespacing, inheritance và decorating. Tuy nhiên, một số deverloper vẫn đang còn mơ hồ về cách làm việc của modules và cách chúng tương tác với code riêng của họ. Bài ...

Modules có một cấu trúc ngôn ngữ linh hoạt, nó được ứng dụng một cách rộng rãi trong nhiều trường hợp khác nhau, chẳng hạn như namespacing, inheritance và decorating. Tuy nhiên, một số deverloper vẫn đang còn mơ hồ về cách làm việc của modules và cách chúng tương tác với code riêng của họ. Bài viết này nhằm mục đích tìm hiểu rõ về Modules và cách sử dụng chúng.

Ruby Object Model (ROM)

Đối với hầu hết mọi thứ về Ruby, muốn sử dụng các module một cách dễ dàng thì chúng ta phải hiểu làm như thế nào để chúng phù hợp với Ruby Object Model (ROM). Rom thông dụng là các class (class-objects, a.k.a. Classes) và các object của các class (instance-objects). Và các Module cũng vậy!

Hãy bắt đầu tạo ra một cặp class:

class Car
  def drive
    "driving"
  end
end

class Trabant < Car
end

Nếu chúng ta hình dung ROM trên mặt phẳng 2D, thì hệ thống object sẽ như sau:

Các class-object được dẫn xuất từ class ở trên nó. Các class-object dẫn xuất trực tiếp các class ở dưới nó. Bên phải của class, được gọi là eigenclass (a.k.a singleton class or meta-class). Các Eigenclass là class-object, cũng như các class khác, chúng có các superclass, thường là eigenclass của supperclass, hay, trong trường hợp của các object, class của chính đối tượng. Bây giờ, đừng lo lắng quá nhiều về chúng, chỉ biết rằng chúng ở đây và có mục đích.

Vậy, chuyện gì xảy ra khi chúng ta tạo một object theo class

my_car = Car.new

Ruby sẽ tạo ra eigenclass-object của chúng ta trực tiếp dưới Car-class. Nó sẽ tạo ra một object mới (my_car) tới bên trái của eigenclass và bên ngoài của hệ thống phân cấp object.

Chúng ta có thể xác thực tất cả điều này trong Ruby’s irb:

my_car.class
        => Car 
> my_car.singleton_class
        => #<Class:#<Car:0x0000000165e568>> 
> my_car.singleton_class.class
        => Class 
> my_car.singleton_class.superclass
        => Car

Phương thức tìm kiếm

Hãy gọi một method trong object:

my_car.drive

The object we call a method on (my_car) is called the receiver object. Ruby has a very simple algorithm for looking up methods: Object mà chúng ta gọi một method từ (my_car) được gọi là receiver object. Ruby có thuật toán đơn giản cho phương thức tìm kiếm như sau:

receiver –> look to the right –> look up

Khi chúng ta gọi method drive trong my_car, đầu tiên Ruby sẽ nhìn bên phải eigenclass của my_car‘s. Nó sẽ không tìm method được gọi ở đây, mà nó sẽ tìm kiếm tới object Car, nơi nó sẽ tìm định nghĩa về drive. Biết điều này làm ta hiểu cách để dùng các module dễ dàng.

Modules

Có 3 điều chúng ta có thể làm với một module:

  1. Include nó trong class-objects
  2. Prepend nó trong class-objects
  3. Extend nó trong class objects hoặc tạo objects với nó
resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
    get 'sporters_by_country'
    get 'results_by_country'
  end
end

The Helicopter Rule

Các Module bên trong ROM tuân theo qui tắc tạm gọi là luật Helicopter. Tôi gọi như thế bởi vì trong trí tưởng tượng của tôi, biểu đồ giống như một helicopter(trực thăng), như được thể hiện ở hình trên. Luật Helicopter nghĩa là:

  1. Including một module trong object sẽ đặt trực tiếp nó sau object.
  2. Prepending một module trong object sẽ đặt trực tiếp nó trước object.
  3. Extending một object bằng một module sẽ đặt trực tiếp nó vào eigenclass của object.

Hãy xác thực điều này trong code:

  module A; end
  module B; end
  module C; end

  class MyClass
    include A
    prepend B
    extend C
  end

   MyClass.ancestors
   => [B, MyClass, A, Object, Kernel, BasicObject] 
   MyClass.singleton_class.ancestors
   => [#<Class:MyClass>, C, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

Chúng ta thấy rằng module A được đặt trực tiếp phía sau MyClass (included), module B được đặt trực tiếp trước MyClass (prepended) và module C được đặt trực tiếp phía sau  MyClass của eigen class (extended)

Chú ý: Gọi phương thức supperclasss trong một class object sẽ tham chiếu đến class cao hơn.

Kết luận:

Bài viết này khá sơ lược. Bài viết tiếp theo tôi sẽ tìm hiểu kĩ về các phương thức Including, Prepending và Extending trong ROM.

Thank you!!

Tài liệu dịch: https://www.sitepoint.com/get-the-low-down-on-ruby-modules/

0