49

method_missingRubyでメソッドを定義する際の注意点はありますか? 継承、例外のスロー、パフォーマンス、またはその他からのそれほど明白ではない相互作用があるかどうか疑問に思っています。

4

6 に答える 6

60

やや明白なもの: を再定義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
于 2008-11-14T22:57:31.353 に答える
13

欠落しているメソッドが特定のメソッド名のみを探している場合、探しているものが見つからない場合は super を呼び出すことを忘れないでください。そうすれば、欠落している他のメソッドが目的を果たすことができます。

于 2011-04-23T00:30:51.787 に答える
11

メソッド名を予測できる場合は、method_missing に依存するよりも動的に宣言する方が適切です。method_missing はパフォーマンスの低下を招くからです。たとえば、次の構文でデータベース ビューにアクセスできるようにデータベース ハンドルを拡張するとします。

selected_view_rows = @dbh.viewname( :column => value, ... )

データベース ハンドルの method_missing に依存し、メソッド名をビューの名前としてデータベースにディスパッチするのではなく、事前にデータベース内のすべてのビューを決定し、それらを反復処理して @dbh に "viewname" メソッドを作成することができます。 .

于 2008-11-15T18:00:38.830 に答える
6

Pistos のポイントに基づいて構築するmethod_missingと、私が試したすべての Ruby 実装で通常のメソッド呼び出しよりも少なくとも 1 桁遅くなります。への呼び出しを回避するために、可能であれば予測するのは正しいことmethod_missingです。

冒険好きなら、あまり知られていない Ruby のDelegatorクラスをチェックしてみてください。

于 2008-11-17T23:49:26.007 に答える
1

別の落とし穴:

method_missingobj.call_methodと の間で動作が異なりobj.send(:call_method)ます。基本的に、前者はすべてのプライベート メソッドと未定義のメソッドを見逃しますが、後者はプライベート メソッドを見逃すことはありません。

したがってmethod_missing、誰かが を介してプライベート メソッドを呼び出したときに、呼び出しがトラップされることはありませんsend

于 2017-03-13T06:22:13.920 に答える