當 ruby 找不到 method 就會 call 這個 method
1
2
3
4
5
6
7
8
class Post
#自己建立 method_missing 呼叫
def method_missing ( method_name , * args )
puts "You tried to call #{ method_name } with these arguments: #{ args } "
super #default method_missing handling raises a NoMethodError
end
end
Post . new . submit ( 1 , "Here's a post." )
1
2
3
4
5
6
7
8
9
10
11
12
class Something
def method_missing ( method , * args , & block )
puts "You called: #{ method } "
p args
block . call 7
end
end
s = Something . new
s . call_method "boo" , 5 do | x |
x . times { puts "in block" }
end
用找不到 method 會 call method_missing
的特性,直接自己定義 method_missing 去定義呼叫其他的 method
它的執行效率並不好,所以只適合用在沒辦法預先知道方法名稱的情況下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Post
DELEGATED_METHODS = [ :username , :avatar ]
def initialize ( user )
@user = user
end
def method_missing ( method_name , * args )
if DELEGATED_METHODS . include? ( method_name )
@user . send ( method_name , * args )
else
super #沒有在設定的 DELEGATED_METHODS 裡面,就呼叫 default method_missing handling raises a NoMethodError
end
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Post
def initialize ( text )
@text = text
end
def to_s
@text
end
def method_missing ( method_name , * args )
match = method_name . to_s . match ( /^hash_(\w+)/ ) #找前面是 hash_
if match
@text << " #" + match [ 1 ]
else
super
end
end
 end
post = Post . new ( "HI" )
post . hash_ruby
post . hash_metaprogramming
puts post
#=> HI #ruby #metaprogramming
respond_to?
1
2
3
4
post = Post . new
post . respond_to? ( :to_s ) # => true
post . hash_ruby #再 method_missing 有定義所以呼叫得到
post . respond_to? ( :hash_ruby ) # => false #但在 respond_to 卻回傳 false
因此必須自己定義 respond_to?
1
2
3
4
5
class Post
def respond_to? ( method_name )
method_name =~ /^hash_\w+/ || super
end
end
但是 post.method(:hash_ruby)
還是會出現 NameError: undefined method
所以要改成另一個 respond_to_missing?
1
2
3
4
5
class Post
def respond_to_missing? ( method_name )
method_name =~ /^hash_\w+/ || super
end
end
DEFINE_METHOD REVISITED
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Post
def initialize ( text )
@text = text
end
def to_s
@text
end
def method_missing ( method_name , * args )
match = method_name . to_s . match ( /^hash_(\w+)/ )
if match #有 match 到 hash_ 就建立出新的 method
self . class . class_eval do
define_method ( method_name ) do
@text << " #" + match [ 1 ]
end
end
send ( method_name ) #並且呼叫 method
else
super #沒有就 raises a NoMethodError
end
end
end
#當 call post.hash_codeschool 就會定義出下面的 method
def hash_codeschool
@text << " #" + "codeschool"
end
const_missing
另一個跟 method_missing 一樣的,主要是常數找不到時會 call
const_missing
官方文件:
method_missing
MatchData
Regexp
參考文件:
如何設計出漂亮的 Ruby APIs
method_missing,一個Ruby 程序員的夢中情人
respond_to? vs. respond_to_missing?