之前你可能读到 Ruby 元编程,也许你的一些项目中使用它,但一些最流行的开源项目是如何利用这个特性?
答案在这篇文章中!
Rails 大量使用元编程,这是一个开始的好地方。
例如,当您想要检查当前环境,在你的 Rails 应用程序,你做些什么:
Rails.env.production?
但什么是 env 并且这是如何工作的呢?答案是 StringInquirer 类,String 这个类的一个子类。这个类使用 method_missing,让你可以调用 env.production?而不是 env == production.
代码是这样的:
def method_missing(method_name, *arguments)
if method_name[-1] == '?'
self == method_name[0..-2]
else
super
end
end
这就是说:“如果是以问号结尾的方法名称就做比较,否则继续祖先链”。
原始代码可在这里找到。
如果您以前使用过 Sinatra 你可能知道有两种方法来定义你的路由:通过使用 get / post 这种独立于任何类以外的直接方法,或通过定义一个类继承自 Sinatra::Application.
Sinatra 的 DSL(领域特定语言) 方法定义在 Sinatra::Application 内,所以你如何在这个类以外使用呢?
嗯,这里有两个事情:元编程和模块的扩展。
Sinatra 定义了一个 Sinatra::Delegator 模块,在 base.rb,用于将方法调用委托给一个 target。默认情况下目标设置为 Sinatra::Application。
这是一个简化版的定义于 Sinatra::Delegator 的 delegate 类方法:
def self.delegate(*methods)
methods.each do |method_name|
define_method(method_name) do |*args, &block|
Delegator.target.send(method_name, *args, &block)
end
end
end
delegate :get, :patch, :put, :post, :delete
这段代码创建了一组方法 ( define_method),将传递方法调用到 Sinatra::Application(Delegator.target 的默认值).
然后 main 对象被扩展,使用 Sinatra::Delegator 定义的方法,这使得 Sinatra 的 DSL 可用 Sinatra::Application 类。
值得注意的是,Ruby 有两个用于方法委托的内置类,如果你需要他们:Delegator & Forwardable.
Paperclip 是 gem,帮助您的应用程序来处理文件上传。文件加在 ActiveRecord 模型。has_attached_file 方法定义附加文件。
例如:
class User
has_attached_file :avatar, :styles => { :normal => "100x100#" }
end
该方法定义在 paperclip.rb,它使用元编程在模型定义方法。该方法可用于访问文件附件 (Paperclip::Attachment 类的一个实例)。例如,如果附加文件 :avatar, Paperclip 将定义一个 avatar 方法在模型上。
这是 define_instance_getter 方法负责:
# @name => The name of the attachment
# @klass => The ActiveRecord model where this method is being defined
def define_instance_getter
name = @name
options = @options
@klass.send :define_method, @name do |*args|
ivar = "@attachment_#{name}"
attachment = instance_variable_get(ivar)
if attachment.nil?
attachment = Attachment.new(name, self, options)
instance_variable_set(ivar, attachment)
end
end
end
从这段代码中我们可以看到,对象存储在附件 @attachment_#{name}实例变量。在我们的例子中 @attachment_avatar.
然后检查这个附件已经存在,如果它不存在,它创建一个新的 Attachment 对象和设置实例变量。
这是原始源代码.
如您所见,元编程是一个非常强大和灵活的技术,但当你想要使用的时候请记得这句话:“强大意味着更大的责任”。
如果你喜欢这篇文章,不要忘了订阅我的新闻:)