论坛首页 编程语言技术论坛

ruby处理未定义的方法

浏览 5671 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-10-09  
关于未定义的方法,《ruby编程语言》上面说得比较詳細了,所以先引用一下:
引用

  当方法名解析算法无法找到一个方法时,它会转而去寻找一个名为method_missing的方法。当此方法被调用时,它的第一个参数是一个符号,表示无法找到的方法的名字,后面的参数都是传给本来该找到的方法的。如果在进行方法调用时附带了一个代码块,则这个代码块也会被 传递给找到的方法或method_missing。
  在kernel模块中,method_missing的默认实现不过是简单的抛出一个NoMethodError异常。如果不对这个异常进行捕获,程序将在给出一个错误消息后退出。这也是通常在调用一个不存在的方法后所期望的結果。
  为一个类定制自己的method_missing方法使你有机会处理该类实例上的任何方法调用。method_missing钩子是Ruby动态机制中最强大的工具之一,它常常被用于元编程技术。
为Hash类增加一个method_missing方法,使我们可以像方法一样对某个主键的值进行查询或设置
class Hash
  # Allow hash values to be queried and set as if they were attributes.
  # We simulate attribute getters and setters for any key.
  def method_missing(key, *args)
    text = key.to_s

    if text[-1,1] == "="               # If key ends with = set a value
      self[text.chop.to_sym] = args[0] # Strip = from key
    else                               # Otherwise...
      self[key]                        # ...just return the key value
    end
  end
end

h = {}         # Create an empty hash object
h.one = 1      # Same as h[:one] = 1
puts h.one     # Prints 1. Same as puts h[:one]



上面这段引用讲得比较清楚了,而上面这段代码的作用就是粗体部分所说的那样,针对上面代码,参数key的值为"one=",而args则是代表等号后的内容。
  之所以想关注一下这个,是因为最近看了下camping的源代码,下面的代码与上面的例子的作用相似,不过更精简:
class H < Hash
    def method_missing(m,*a)
        m.to_s=~/=$/?self[$`]=a[0]:self[m.to_s]
    end
  end

其中=~是模式匹配符,$'表示匹配以前的字符,在此文中就是等号前的内容。当然这段代码是自己改了一下,原文直接是下面这样的:
class H < Hash
    def method_missing(m,*a)
        m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super
    end
    undef id, type if ?? == 63
end

暂时没看懂那个super有什么特别的用处,因为既然是继承关系,当然可以访问父类中的方法,除非是private方法,当然下面那句代码中有??这个东西,俺也不明白到底有什么深意,但单独执行却是合法的,望牛人指点。
   发表时间:2010-10-09  
method_missing 是 ruby的神器之一啊。。。。so 伟大
0 请登录后投票
   发表时间:2010-10-09  
那个super就是说
这个method_missing方法处理不了这个状况
让 上一个method_missing来处理吧
0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
??看起来像是返回第二个?的ASCII码, 同理可以试`?a`, `?A`或其他

用"a"[0]的方法也可以得到ASCII码

参见
http://stackoverflow.com/questions/1345843/ruby-question-mark
0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
gokure 写道
??看起来像是返回第二个?的ASCII码, 同理可以试`?a`, `?A`或其他

用"a"[0]的方法也可以得到ASCII码

参见
http://stackoverflow.com/questions/1345843/ruby-question-mark


多谢提醒,在网上找了一下,果然是这个意思:
引用

You can also determine the ASCII code of a character by using the ? operator in Ruby.

参考链接:
http://en.wikibooks.org/wiki/Ruby_Programming/ASCII

不过如果是这样,那个undef id, type if ?? == 63 中的if不是一直为true吗?,‘?’的ascii码本身是63,这个应该是固定的吧。
0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
这个是要与1.9兼容的写法,ruby1.9里??这种方法返回已经不是数字了,而是返回字符串"?"

还有那个type也是一个和ruby1.9不兼容的方法,1.9已经取消掉了这个方法。1.8调用这个方法会有warning...

很多人喜欢用自己熟悉的方式去区分不同版本和平台,比如:
http://www.iteye.com/topic/774779#1692896
其实个人觉得用这样的写法去兼容平台或版本会给阅读者带来很大麻烦。。
ruby已经提供了两个常量RUBY_PLANTFORM和RUBY_VERSION,这些常量让人读起来一目了然~


还有那个super用的确实很奇怪。

按照他的写法,如果方法找不到(调用到了kernel的私有方法?)就会调用Hash的method_missing方法,不如直接raise




0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
class OrderedOptions < Array
  def []=(key, value)
    key = key.to_sym

    if pair = find_pair(key)
      pair.pop
      pair << value
    else
      self << [key, value]
    end
  end

  def [](key)
    pair = find_pair(key.to_sym)
    pair ? pair.last : nil
  end

  def method_missing(name, *args)
    if name.to_s =~ /(.*)=$/
      self[$1.to_sym] = args.first
    else
      self[name]
    end
  end

  private
  def find_pair(key)
    self.each { |i| return i if i.first == key }
    return false
  end
end

  def method_missing(name, *args)
    if name.to_s =~ /(.*)=$/
      self[$1.to_sym] = args.first
    else
      self[name]
    end
  end
干么写那么难懂..
0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
引用
暂时没看懂那个super有什么特别的用处,因为既然是继承关系,当然可以访问父类中的方法,除非是private方法,当然下面那句代码中有??这个东西,俺也不明白到底有什么深意,但单独执行却是合法的,望牛人指点。

这个是惯用方法.
参考这个链接:http://www.alfajango.com/blog/a-rubyists-beautiful-mistress-method_missing/
引用
The right way to use method_missing

If you’re feeling confused and vulnerable now, it’s OK; I’ll help you through this. It’s normal at this point in your life to feel attracted to method_missing. Even though you’re committed to define_method, there are times when you just need to be with method_missing. If you’re going to do it, please just be safe.

As long as you practice safe-programming, you can use method_missing tonight, worry-free. I’ll leave you with three safe-programming guidelines to follow:

引用
3. Clean up after yourself

If anything goes wrong, you need to grab your stuff and get out of there. And ideally, you don’t want to leave a trace. If the called method fails your criteria, at any point, call super. This will allow the method call to continue on it’s merry way up the class chain, so that it can raise the appropriate exception and leave you an exception stack trace you can work with.

你总得要处理异常吧.
0 请登录后投票
   发表时间:2010-10-09  
本来要做的事情就是抛异常,raise是最直观的方法~
而用super是在绕弯弯。。把简单的问题复杂化,举个例子,如果Hash又自己定义了method_missing会怎样?

至于是不是习惯用法,至少matz没这么用(见ruby标准库中ostruct.rb实现)
0 请登录后投票
   发表时间:2010-10-09   最后修改:2010-10-09
嗯,用RUBY_VERSION与RUBY_PLATFORM来判断的话,可读性是好要一些,就拿上面的代码来说:
undef id, type if ?? == 63

大概等价于
undef id, type unless RUBY_VERSION =~/1.9/

当然这个也不太准确,毕竟以后肯定会有2.0的。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics