0

Understanding method missing

Mở đầu

Trong bài viết này chúng là sẽ đi tìm hiểu về method_misingrespond_to_mising? để cùng xem họ đã tạo ra và sử dụng nó như thế nào. Chúng ta sẽ tại tạo lại class StringInquirer trong Ruby on Rails như là một cách để chứng minh cái gì đang diễn ra và làm thế nào để có thể sử dụng nó trong các ứng dụng thực tế.

StringInquirer là gì

Với tất cả những ai đã làm việc với Rails application, thì có lẽ chúng ta đã từng kiểm tra tại một thời điểm, ứng dụng đang chạy trên môi trường nào. Để kiểm tra điều này chúng ta có thể gọi Rails.env.staging?. Những gì tôi biết tại sao rails làm được việc này là gì env là một instance của class StringInquirer

StringInquirer cho phép chúng ta so sánh String với một cái gì đó bằng cách hỏi staging? hoặc env == "staging"

NoMethodError

Có thể chúng ta đã nhìn thấy các ngoại lệ NoMethodError nhiều lần trong khi lập trình Ruby. Đoạn code dưới đây sẽ tạo ra ngoại lên NoMethodError vì method happy? không tồn tại.

class StringInquirer < String
end

mood = StringInquirer.new("happy")
mood.happy?

Khi chúng ta gọi happy? Ruby sẽ kiểm tra xe đối tượng trả về là method... hay nói một cách khác, nếu method happy? tồn tại với tên đó trong đối tượng hiện tại hoặc bất kỳ class khác trong hệ thống chuỗi phân cấp.

Trong trường hợp không thể tìm thấy method happy? nó sẽ bắn ra exception. Nhưng Ruby cho phép chúng ta implement một method là method_missing.

method_missing nhận tên của method và các đối số được truyền cho method được gọi. Nếu chúng ta thêm method_missing vào class của chúng ta và in ra các giá trị. Đấy là ý tưởng về việc chúng ta đang làm.

class StringInquirer < String

  private
    def method_missing(method_name, *arguments)
      puts method_name.inspect
      puts arguments.inspect
    end
end
mood = StringInquirer.new("happy")
mood.happy?

:happy?
[]

Bây giờ chúng ta muốn kiểm tra một method_name với ký tự ? ở cuối . Đầu tiên, hãy kiểm tra xem nếu đầu vào, method_name kết thúc bằng một dấu ?, nếu đúng, thì kiểm tra xem phần bắt đầu của method_name tương đương với día trị chuỗi chúng ta đã khai báo (ex: "happy"). Nếu method truyên vào không kết thúc bằng ? thì chúng ta khai báo super để gọi đến các method ở class String

class StringInquirer < String

  private
    def method_missing(method_name, *arguments)
      if method_name[-1] == '?'
        self == method_name[0..-2]
      else
        super
      end
    end
end

Với việc cập nhật lại như này, đoạn code sẽ trả về true khi chúng ta gọi happy?false nếu chúng ta gọi một thứ bất kỳ (ex: sad?)

Does my object respond to?

Thỉnh thoảng trước khi gọi một method nào đó chúng ta thường kiểm tra xem object có đáp ứng được method mình đang gọi hay không. Để làm được điều đó chúng ta có thể sử dụng method respond_to?

"Happy".respond_to?(:length) # => true

Vấn đề ở đây, các method happy? hay sad? không thực sự tồn tại. Có một method khác mà chúng ta có thể implement để giúp chúng ta xử lý các trường hợp không thể tìm thấy method cụ thể được gọi. Đó gọi là respond_to_missing?. respond_to_missing? nhận method name và các giá trị khác được gọi là include_private (chúng ta không cần quan tâm về nó bây giờ). Trong trường hợp này, chúng ta muốn kiểm tra các method được gọi có kết thúc bằng ? hay không.

Để làm được việc này chúng ta lại về với class StringInquirer nơi chúng ta sẽ implement 2 method method_missing and respond_to_missing?

class StringInquirer < String
  private

    def respond_to_missing?(method_name, include_private = false)
      method_name[-1] == '?'
    end

    def method_missing(method_name, *arguments)
      if method_name[-1] == '?'
        self == method_name[0..-2]
      else
        super
      end
    end
end

Chúng ta có thể sử dụng class như sau.

mood = StringInquirer.new("happy")
p mood.happy? # => true
p mood.sad? # => false
p mood.respond_to?(:happy?) # => true

Concluding thoughts

Mình đã đề cập và sử dụng đến 2 method là method_missingrespond_to_missing để thực hiện và hiểu một chút về "Meta programing". Cho phép code của chúng ta đặt các câu hỏi cho chính nó và tạo ra chức năng mới một cách nhanh chóng.

Lần sau, khi sử chúng ta sử dụng Rails.env.development? chúng ta sẽ biết được chuyện gì đã xảy ra để làm được điều này.

Tham khảo

Bài viết được dịch từ:

https://www.leighhalliday.com/understanding-method-missing


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí