Ruby Metaprogramming - Creating Methods
This post hasn't been updated for 7 years
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
All Rights Reserved