源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Ruby元编程之梦中情人method_missing方法详解

  • 时间:2022-12-23 21:26 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Ruby元编程之梦中情人method_missing方法详解
我最近读了些文章(比如[url=http://rubylearning.com/blog/2010/10/07/do-you-know-rubys-chainsaw-method/]这篇[/url]),宣传在 Ruby 里使用 method_missing 的。 很多人都与 method_missing 干柴烈火,但在并没有小心处理彼此之间的关系。所以,我想来探讨一下这个问题: [b]** 我该怎么用 method_missing **[/b] 什么时候该抵挡 method_missing 的诱惑 首先,永远不要在还没花时间考虑你用得够不够好之前,就向 method_missing 的魅力屈服。你知道,在日常生活中,很少会让你以为的那样亟需 method_missing: [b]日常:方法代理[/b] 案例:我需要让这个类能够使用另一个类的方法 这是我所见过最普遍的使用 method_missing 的情况。这在 gems 与 Rails 插件里头尤其流行。它的模型类似这样:
[url=http://railsmagazine.com/articles/4]ruby delegation library[/url] 和 [url=http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate/]Rails ActiveRecord delegation[/url]。 好,我们总结一下,看看 define_method 的真正威力。 修改自 ruby-doc.org 上的 [url=http://ruby-doc.org/core/classes/Module.html#M001654]例子[/url]
[u]复制代码[/u] 代码如下:
class A   def fred     puts "In Fred"   end   def create_method(name, &block)     self.class.send(:define_method, name, &block)   end   define_method(:wilma) { puts "Charge it!" } end class B < A   define_method(:barney, instance_method(:fred)) end a = B.new a.barney                                #=> In Fred a.wilma                                 #=> Charge it! a.create_method(:betty) { p self.to_s } a.betty                                 #=> B
[b]什么时候用 method_missing?[/b] 现在你估计在想,总有该用它的时候吧,不然还要它干嘛?没错。 [b]动态命名的方法(又名,元方法)[/b] 案例:我要依据某种模式提供一组方法。这些方法做的事情顾名思义。我可能从来没有调用过这些可能的方法,但是等我要用的时候,它们必须可用。 现在才是人话!这其实正是 ActiveRecord 所采用的方式,为你提供那些基于属性的动态构建的查找方法,比如 find_by_login_and_email(user_login, user_email)。
[u]复制代码[/u] 代码如下:
def method_missing(method_id, *arguments, &block)   if match = DynamicFinderMatch.match(method_id)     attribute_names = match.attribute_names     super unless all_attributes_exists?(attribute_names)     if match.finder?       # ...you get the point     end # my OCD makes me unable to omit this     # ...   else     super # this is important, I'll tell you why in a second   end end
[b]权衡利弊[/b] 当你有一大堆元方法要定义,又不一定用得到的时候,method_missing 是个完美的折衷。 想想 ActiveRecord 中基于属性的查找方法。要用 define_method 从头到脚定义这些方法,ActiveRecord 需要检查每个模型的表中所有的字段,并为每个可能的字段组合方式都定义方法。
[u]复制代码[/u] 代码如下:
find_by_email find_by_login find_by_name find_by_id find_by_email_and_login find_by_email_and_login_and_name find_by_email_and_name # ...
假如你的模型有 10 个字段,那就是 10! (362880)个查找方法需要定义。想象一下,在你的 Rails 项目跑起来的时候,有这么多个方法需要一次定义掉,而 ruby 环境还得把它们都放在内存里头。 老虎·伍兹都做不来的事情。 [b]** 正确的 method_missing 使用方式[/b] (译者猥琐地注:要回家了,以下简要摘译) [b]1、先检查[/b] 并不是每次调用都要处理的,你应该先检查一下这次调用是否符合你需要添加的元方法的模式:
[u]复制代码[/u] 代码如下:
def method_missing(method_id, *arguments, &block)   if method_id.to_s =~ /^what_is_[w]+/     # do your thing   end end
[b]2、包起来[/b] 检查好了,确实要处理的,请记得把函数体包在你的好基友,define_method 里面。如此,下次就不用找情妇了:
[u]复制代码[/u] 代码如下:
def method_missing(method_id, *arguments, &block)   if method_id.to_s =~ /^what_is_[w]+/     self.class.send :define_method, method_id do       # do your thing     end     self.send(method_id)   end end
[b]3、擦屁股[/b] 自己处理不来的方法,可能父类有办法,所以 super 一下:
[u]复制代码[/u] 代码如下:
def method_missing(method_id, *arguments, &block)   if method_id.to_s =~ /^what_is_[w]+/     self.class.send :define_method, method_id do       # do your thing     end     self.send(method_id)   else     super   end end
[b]4、昭告天下[/b]
[u]复制代码[/u] 代码如下:
def respond_to?(method_id, include_private = false)   if method_id.to_s =~ /^what_is_[w]+/     true   else     super   end end
要告诉别人,你的类虽然暂时还没有这个方法,但是其实是能够响应这方法的。 [b]** 总结 **[/b] 在每个 Ruby 程序员的生活中,这仨方法扮演了重要的角色。define_method 是你的好基友,method_missing 是个如胶似漆但也需相敬如宾的情妇,而 respond_to? 则是你的爱子,如此无虞。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部