method_missing
Rubyでメソッドを定義する際の注意点はありますか? 継承、例外のスロー、パフォーマンス、またはその他からのそれほど明白ではない相互作用があるかどうか疑問に思っています。
6 に答える
やや明白なもの: を再定義respond_to?
する場合は常に再定義しますmethod_missing
。機能する場合method_missing(:sym)
は、respond_to?(:sym)
常に true を返す必要があります。これに依存する多くのライブラリがあります。
後で:
例:
# Wrap a Foo; don't expose the internal guts.
# Pass any method that starts with 'a' on to the
# Foo.
class FooWrapper
def initialize(foo)
@foo = foo
end
def some_method_that_doesnt_start_with_a
'bar'
end
def a_method_that_does_start_with_a
'baz'
end
def respond_to?(sym, include_private = false)
pass_sym_to_foo?(sym) || super(sym, include_private)
end
def method_missing(sym, *args, &block)
return foo.call(sym, *args, &block) if pass_sym_to_foo?(sym)
super(sym, *args, &block)
end
private
def pass_sym_to_foo?(sym)
sym.to_s =~ /^a/ && @foo.respond_to?(sym)
end
end
class Foo
def argh
'argh'
end
def blech
'blech'
end
end
w = FooWrapper.new(Foo.new)
w.respond_to?(:some_method_that_doesnt_start_with_a)
# => true
w.some_method_that_doesnt_start_with_a
# => 'bar'
w.respond_to?(:a_method_that_does_start_with_a)
# => true
w.a_method_that_does_start_with_a
# => 'baz'
w.respond_to?(:argh)
# => true
w.argh
# => 'argh'
w.respond_to?(:blech)
# => false
w.blech
# NoMethodError
w.respond_to?(:glem!)
# => false
w.glem!
# NoMethodError
w.respond_to?(:apples?)
w.apples?
# NoMethodError
欠落しているメソッドが特定のメソッド名のみを探している場合、探しているものが見つからない場合は super を呼び出すことを忘れないでください。そうすれば、欠落している他のメソッドが目的を果たすことができます。
メソッド名を予測できる場合は、method_missing に依存するよりも動的に宣言する方が適切です。method_missing はパフォーマンスの低下を招くからです。たとえば、次の構文でデータベース ビューにアクセスできるようにデータベース ハンドルを拡張するとします。
selected_view_rows = @dbh.viewname( :column => value, ... )
データベース ハンドルの method_missing に依存し、メソッド名をビューの名前としてデータベースにディスパッチするのではなく、事前にデータベース内のすべてのビューを決定し、それらを反復処理して @dbh に "viewname" メソッドを作成することができます。 .
Pistos のポイントに基づいて構築するmethod_missing
と、私が試したすべての Ruby 実装で通常のメソッド呼び出しよりも少なくとも 1 桁遅くなります。への呼び出しを回避するために、可能であれば予測するのは正しいことmethod_missing
です。
冒険好きなら、あまり知られていない Ruby のDelegatorクラスをチェックしてみてください。
別の落とし穴:
method_missing
obj.call_method
と の間で動作が異なりobj.send(:call_method)
ます。基本的に、前者はすべてのプライベート メソッドと未定義のメソッドを見逃しますが、後者はプライベート メソッドを見逃すことはありません。
したがってmethod_missing
、誰かが を介してプライベート メソッドを呼び出したときに、呼び出しがトラップされることはありませんsend
。