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:
- Include nó trong class-objects
- Prepend nó trong class-objects
- 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à:
- Including một module trong object sẽ đặt trực tiếp nó sau object.
- Prepending một module trong object sẽ đặt trực tiếp nó trước object.
- 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/