刚才跟NS老兄聊的时候他给我看了段代码:
night_stalker 写道
看到一个方法简写 trick
irb(main):004:0> "Hello World".spl
=> ["Hello", "World"]
irb(main):005:0> "Hi there Daniel".sp
=> ["Hi", "there", "Daniel"]
irb(main):006:0> "Hi there Daniel".s
=> "Ambigous abbreviation s -> select, slice, sub!, squeeze, send, split,
size, strip, succ!, squeeze!, sub, slice!, scan, sort, swapcase, swapcase!,
sum, singleton_methods, succ, sort_by, strip!"
我正无聊,回答说这实现起来不难,就模仿那段代码的行为估摸了一个出来。不过这么简单的东西我一开始居然写错了,郁闷 T T
class Object
def method_missing(name, *args, &block)
candidates = methods.grep /^#{name}/
raise "undefined method `#{name}' for #{self}:#{self.class}" if candidates.empty?
raise "Ambigous abbreviation #{name} -> #{candidates.join ', '}" unless candidates.one?
method(candidates.first).call *args
end
end
一开始忘写method,直接拿candidates.first[*args]就调用了……找起错来还挺麻烦的 T T
另外,还可以尝试匹配下划线分隔的名字中的缩写,像是把end_with?缩写成ew。在Ruby 1.9上可以这样写:
class Object
def method_missing(name, *args, &block)
candidates = methods.grep /^#{name}/
if candidates.empty?
downcase_name = name.to_s.downcase
candidates = methods.map{|m| m.downcase}.reject{|m| m[0] != name[0]}.select do |m|
downcase_name == m.to_s.sub(/[?!=]$/, '').split(/_/).map{|p| p[0]}.join
end
end
raise "undefined method `#{name}' for #{self}:#{self.class}" if candidates.empty?
raise "Ambigous abbreviation #{name} -> #{candidates.join ', '}" unless candidates.one?
method(candidates.first).call *args
end
end
主要是Ruby 1.9之前String#[]返回的是字节的值,是个Fixnum,要转成字符还得用Fixnum#chr,比较烦……要在Ruby 1.8上运行这代码的话,要在[0]后面都加上.chr。
E:\build_area\ruby191\bin>irb
irb(main):001:0> class Object
irb(main):002:1> def method_missing(name, *args, &block)
irb(main):003:2> candidates = methods.grep /^#{name}/
irb(main):004:2> if candidates.empty?
irb(main):005:3> candidates = methods.select do |m|
irb(main):006:4* name.to_s.downcase == m.to_s.sub(/[?!=]$/, '').split(/_/).map {|p| p[0]}.join.downcase
irb(main):007:4> end
irb(main):008:3> end
irb(main):009:2> raise "undefined method `#{name}' for #{self}:#{self.class}" if candidates.empty?
irb(main):010:2> raise "Ambigous abbreviation #{name} -> #{candidates.join ', '}" unless candidates.one?
irb(main):011:2> method(candidates.first).call *args
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> 'alpha'.ew 'a'
=> true
irb(main):015:0> 'alpha'.end_with? 'a'
=> true
结束语:人不能太无聊了 XDD