Ruby Metaprogramming - The Basics
Bài đăng này đã không được cập nhật trong 8 năm
Qua 3 bài trong loạt bài về metaprogramming
trong ruby, tôi đã nói về eval
, send
, define_method
, hẳn bạn đã thấy sự kì diệu mà metaprogramming
mang lại cho chúng ta. Nhưng đi sâu thêm một chút nữa, có lẽ chúng ta nên tìm hiểu và nên biết tại sao metaprogramming
có thể hoạt động được và nó đã hoạt động như thế nào. Trong bài này, bài cuối cùng trong loạt bài về metaprogramming
trong ruby, tôi sẽ cùng các bạn đi sâu vào mô hình đối tượng của Ruby để tìm hiểu cách vận hành của chúng.
Dưới đây là mô hình đối tượng của Ruby, chúng ta hãy cùng nhau phân tích nó.
h1. 1. Từ khóa @self@
Như bạn đã biết, mọi thứ trong Ruby đều là đối tượng, bao gồm cả class. Như ở đây, Developer
là một class, nó sẽ được hiểu là một instance của class Class
. Chẳng hạn như thế này:
Developer = Class.new do
def self.meth1; "Hello"; end
def meth2; "Bye"; end
end
a = Developer.new #=> #<#<Class:0x100381890>:0x100376b98>
Developer.meth1 #=> "Hello"
a.meth2 #=> "Bye"
Ta có một cấu trúc các class được kế thừa lẫn nhau:
p Developer.class # Class
p Class.superclass # Module
p Module.superclass # Object
p Object.superclass # BasicObject
Một điều quan trọng cần hiểu ở đây là ý nghĩa của từ khóa self
. Tất cả những mã thực thi trong Ruby đều chứa một biểu hiện cụ thể, nó chính là self
. self
luôn đề cập đến một đối tượng cụ thể nhưng nó có thể thay đổi theo đoạn mã được thực thi. Ví dụ, bên trong một khai báo class, self
thể hiện cho chính instance của Class:
class Developer
p self
end
# Developer
Trong một instance method, self
thể hiện một instance của class đó:
class Developer
def frontend
self
end
end
p Developer.new.frontend
# #<Developer:0x2c8a148>
Trong một class method, self
thể hiện cho class của chính nó
class Developer
def self.backend
self
end
end
p Developer.backend
# Developer
Có khi nào bạn tự hỏi, tại sao lại có khai báo class method như trên, và class method là gì? Trước khi trả lời câu hỏi đó, tôi muốn nhắc đến một khái niệm là metaclass, hay còn được gọi với cái tên singleton class và eigenclass. Phương thức backend ở trên chính là một instance được khai báo trong metaclass của class Developer.
h1. 2. Metaclass
Tất cả mọi đối tượng trong Ruby đều chứa một metaclass
, nó có thể là vô hình đối với bạn, nhưng nó vẫn tồn tại và bạn có thể sử dụng nó. Class Developer ở trên cơ bản là một đối tượng, và tất nhiên nó cũng có một metaclass
. Một metaclas
s về cơ bản là một class được Ruby tạo ra và chèn vào các hệ thống phân cấp thừa kế để giữ các phương thức class, do đó không can thiệp với các instance được tạo ra từ các class. Hãy cùng làm một ví dụ nho nhỏ với metaclass
:
example = "I'm a string object"
def example.something
self.upcase
end
p example.something
# I'M A STRING OBJECT
Trong ví dụ này, ta đã tạo ra một singleton method là something
cho một đối tượng example
. Sự khác biệt giữa class methods và singleton methods: trong khi class methods có thể sử dụng với tất cả instance của một class thì singleton methods chỉ có thể sử dụng cho duy nhất một instance. Các class methods được sử dụng nhiều nhưng singleton methods được sử dụng ít hơn, tuy nhiên chúng đều được thêm vào metaclass
của một đối tượng.
Ví dụ bên trên có thể được viết bằng cách khác:
example = "I'm a string object"
class << example
def example.something
self.upcase
end
end
Bây giờ hãy quay lại với ví dụ khai báo class Developer ở bên trên và cùng thử một số cú pháp để khai báo một class method:
class Developer
def self.backend
"I am backend developer"
end
end
Một cách tường minh hơn:
def Developer.backend
"I am backend developer"
end
Hoặc như chúng ta vẫn thường viết:
class << self
def backend
"I am backend developer"
end
end
Đầu tiên chúng ta khai báo class << self
để ám chỉ đến metaclass
của class Developer, và sau đó khao báo phương thức backend
ở trong metaclass
của class Developer. Bằng cách khai báo như thế này, chúng ta đang thêm phương thức backend
vào trong metaclass
của clas Developer, thay vì thêm vào chính class đó. Nói cách khác, phương thức backend
là một instance của metaclass
, của class Developer.
Và như vậy, chỉ cần hiểu rõ về object, class, method cũng như cấu trúc của nó là chúng ta đã có thể sử dụng các phương thức eval
, send
,... để lập trình metaprogramming một cách thuần thục hơn.
All rights reserved