Ruby Metaprogramming - Creating Methods
Creating Methods Trong bài viết này tôi sẽ nói về một khía cạnh của lập trình meta programming trong Ruby. Khả năng về tạo ra methods dynamically, trong suốt thời gian chạy. Có khá nhiều lý do để giải thích tại sao chúng ta nên làm điều này, một trong số đó là cho phép chúng ta viết ra generator ...
Creating Methods
Trong bài viết này tôi sẽ nói về một khía cạnh của lập trình meta programming trong Ruby. Khả năng về tạo ra methods dynamically, trong suốt thời gian chạy. Có khá nhiều lý do để giải thích tại sao chúng ta nên làm điều này, một trong số đó là cho phép chúng ta viết ra generator methods để giúp chúng ta tránh được việc viết code lặp đi lặp lại.
The Long Way
Nếu không có gì đặc biệt xảy ra, các method dưới đây không thực sự làm được gì nhiều ngoài việc get và set 1 biến instance.
class Alpaca def initialize @name end def name @name end def name=(value) @name = value end end buddy = Alpaca.new("Buddy") buddy.name # Buddy
Điều này thực sự gây phiền nhiều, tốn thời gian để viết ... Và trong ruby có một cách dễ dàng để có được chức năng tương tự với chỉ tốn 1 dòng code. attr_accessor Ruby cho chúng ta 3 methods để giúp tạo ra getter, setter cho biến instance. attr_reader tạo getter, attr_writer tạo setter, attr_accessor tạo cả 2. Để sử dụng, chúng ta chỉ cần định nghĩa phía trên đầu của class và ruby sẽ tạo ra getter, setter cho chúng ta.
class Alpaca attr_accessor :name def initialize(name) self.name = name end end buddy = Alpaca.new("Buddy") puts buddy.name # "Buddy"
Let's do this ourselves
Bởi vì Ruby là dynamic laguage, nó cho phép chúng ta thêm mới hoặc xóa đi các method trong lúc chạy chương trình. Chúng ta hãy cùng tái hiện lại những gì Ruby đã làm gì khi chúng ta sử dụng attr_accessor. Tôi sẽ gọi nó là getset, getter, setter. Chúng ta có thể sử dụng define_method để tự động tạo ra 1 method mới. Để hoàn hành method, tôi sẽ sử dụng tiếp các method instance_variable_get và instance_variable_set để thiết lập các biến instance trong hàm được định nghĩa.
# Let's create a base class to extend from. # This class contains the code generator methods that we'll be using. class Base def self.getset(*args) args.each do |field| getter(field) setter(field) end end def self.getter(*args) args.each do |field| define_method(field) do instance_variable_get("@#{field}") end end end def self.setter(*args) args.each do |field| define_method("#{field}=") do |value| instance_variable_set("@#{field}", value) end end end end # Now let's create a class and utilize our getset generator class Alpaca < Base # We'll create accessors for :name and :age getset :name, :age def initialize(name, age) self.name = name self.age = age end end buddy = Alpaca.new("Buddy", 24) # Let's call our methods and make sure they return what we expect puts buddy.name # Buddy puts buddy.age # 24 # Let's see if our object responds to the new methods we created puts buddy.respond_to?(:name) # true puts buddy.respond_to?(:name=) # true
Concluding thoughts
Nếu bạn là Rails developer, có lẽ bạn đã từng sử dụng một method được tự động sinh ra trước khi bạn biết hoặc là chưa biết về nó.Trong model của rails có khá nhiều methods được tạo ra tự động cho mỗi thuộc tính của model đó. Đây là lý do tại sao bạn có thể gọi @user.name mà không cần phải tạo ra phương thức getter cho thuộc tính trên.
Bài viết được dịch tại nguồn https://www.leighhalliday.com/ruby-metaprogramming-creating-methods