define_method
可以帮助我们动态的,快速的定义多个方法;比如有这样一个类:
class Post
attr_accessor :title, :content, :state
def initialize(title, content, state = :draft)
@title, @content, @state = title, content, state
end
def draft
@state = :draft
end
def posted
@state = :posted
end
def deleted
@state = :deleted
end
end
draft
posted
deleted
分别用来把文章的状态设置为: 草稿 发表 和 删除 ,但是这三个方法看起来太类似了,而 define_method
就可以帮助我们优化这部分代码:
class Post
attr_accessor :title, :content, :state
def initialize(title, content, state = :draft)
@title, @content, @state = title, content, state
end
states = [:draft, :posted, :deleted]
states.each do |state|
define_method state do
@state = state
end
end
这下就轻松多了吧!再来一个稍微复杂一点的例子,可以体现其灵活性:
class Game
attr_accessor :name, :year, :system
SYSTEMS = ['SNES', 'PS1', 'Genesis']
SYSTEMS.each do |system|
define_method "runs_on_#{system.downcase}?" do
self.system = system.downcase
end
end
end
那么,如何在目标方法之后传递参数呢?比如说代理一个 block?
class Book
# 省略不相关代码
[:each, :map, :select].each do |method|
define_method method do |&block|
books.send(method, &block)
end
end
end
方法体中之所以使用 send
方法,是因为在我们要重新定义的 each
方法里,books 需要委托数组方法 each
来处理 &block,而不是由 books 直接处理 █当然,其它两个方法也是这样的道理。最终 Ruby 帮我们生成的方法就是类似这样的:
def each # 这是我们为 Book 类定义的 each 方法
books.each(&block) # 这是委托数组的 each 方法来帮 books 处理传入的 &block
end