Hook methods trong Ruby (phần 2)
Bài đăng này đã không được cập nhật trong 8 năm
Trong bài viết trước, chúng ta đã đề cập tới 2 cách thức sử dụng hook method trong ruby là:
- included
- extended
Các bạn có thể xem lại ở link sau: https://viblo.asia/dieunb/posts/mrDkMOglGzL
Tiếp theo, chúng ta sẽ cùng nhau xem xét 3 cách thức khác để sử dụng hook trong ruby là:
- prepended
- inherited
- method_missing
Prepended
Phần trước chúng ta nhận thấy, có thể sự dụng include
và extend
để sử dụng những hàm được định nghĩa trong module. Tuy nhiên, bên cạnh đó còn có một cách khác, đó là sử dụng prepend
. Prepend
được giới thiệu trong Ruby 2.0
và bản thân nó khác hoàn toàn so với include
và extend
. Những hàm được định nghĩa trong module nhưng khi sử dụng thông qua include
hoặc extend
đều có thể bị overide lại tại module/class. Nhưng với prepend
thì hoàn toàn ngược lại. Chúng ta sử dụng để overide lại những hàm được định nghĩa trong module/class mà prepend
module đó. Ví dụ:
Khi chưa prepend
module Person
def name
"My name belongs to Person"
end
end
class User
def name
"My name belongs to User"
end
end
puts User.new.name
=> My name belongs to User
Sau khi prepend
module Person
def name
"My name belongs to Person"
end
end
class User
prepend Person
def name
"My name belongs to User"
end
end
puts User.new.name
=> My name belongs to Person
Prepend có một hàm callback tên là prepended
. Hàm này sẽ được thực thi khi mà module được preprend vào một module/class khác. Ví dụ:
module Person
def self.prepended(base)
puts "#{self} prepended to #{base}"
end
def name
"My name belongs to Person"
end
end
Ngay sau khi thực hiện chúng ta có ngay kết quả:
Person prepended to User
My name belongs to Person
prepend
được giới thiệu cũng là nhằm tránh việc sử dụng alias_method_chain
trong Rails, vì thực sự sử dụng alias_method_chain
không được đẹp.
Inherited
Inherit là một khái niệm quan trọng trong OOP. Ruby là một OOP vậy nên việc cung cấp inherit
cũng không phải là một ngoại lệ. Cùng xem ví dụ:
class Person
def name
"My name is Person"
end
end
class User < Person
end
puts User.new.name # => My name is Person
Chúng ta cũng có một hook method để nhận biết là class nào kế thừa class nào.
class Person
def self.inherited(child_class)
puts "#{child_class} inherits #{self}"
end
def name
"My name is Person"
end
end
class User < Person
end
puts User.new.name
Kết quả chúng ta nhận được
User inherits Person
My name is Person
Inherit trong Rails
Có một class quan trọng trong các Rails app có tên là Application
, class này được định nghĩa trong config/application.rb
. Class này thực hiện rất nhiều tác vụ như thực hiện tất cả Railties, engines, và plugin.
method_missing
Dường như method_missing
là hook method được sử dụng rộng rãi nhất vì khi tìm kiếm trong những Ruby frameworks/gems/libraries, chúng ta thấy tần xuất xuất hiện của nó rất nhiều. Hàm này sẽ được gọi khi mà chúng ta đang cố gắng thực hiện một hàm mà hàm đó không có sẵn. Cùng xem ví dụ:
class Person
def name
"My name is Person"
end
end
p = Person.new
puts p.name # => My name is Person
puts p.address # => undefined method `address' for #<Person:0x007fb730a2b450> (NoMethodError)
Chúng ta có thể sự dụng method_missing
để tránh được exception và ghi lại điều đó một cách vui vẻ.
class Person
def method_missing(sym, *args)
"#{sym} not defined on #{self}"
end
def name
"My name is Person"
end
end
p = Person.new
puts p.name # => My name is Person
puts p.address # => address not defined on #<Person:0x007fb2bb022fe0>
Như vậy, bên trên chúng ta đã đề cập xong những hàm hook quan trọng trong Ruby. Việc sử dụng linh hoạt những hook method này sẽ làm cho ứng dụng của bạn sạch sẽ và chuyên nghiệp hơn.
Nguồn + tham khảo:
All rights reserved