Ruby元编程在野外(翻译,简学互动)

629 查看

之前你可能读到Ruby元编程,也许你的一些项目中使用它,但一些最流行的开源项目是如何利用这个特性?

答案在这篇文章中!

Rails示例

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委托

如果您以前使用过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

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对象和设置实例变量。

这是原始源代码.

结论

如您所见,元编程是一个非常强大和灵活的技术,但当你想要使用的时候请记得这句话:“强大意味着更大的责任”。

如果你喜欢这篇文章,不要忘了订阅我的时事通讯:)

原英文链接


广告时间:

Ruby是知识海洋的贝壳,一起来捡吧。

高性价比培训:

  • 一个月短期培训,自由学习无压力

  • Rails网站开发入门,费用499

  • Ruby和Rails课程,可以为进入编程领域做准备

欢迎了解和交流

链接:简学互动Ruby、Rails基础培训