Rubyでは、respond_to?
を使用してオブジェクトに特定のメソッドがあるかどうかを確認できることを知っています。
しかし、クラスが与えられた場合、インスタンスに特定のメソッドがあるかどうかを確認するにはどうすればよいですか?
すなわち、何かのような
Foo.new.respond_to?(:bar)
しかし、新しいインスタンスをインスタンス化するよりも良い方法があるはずです。
instance_methods
が仕事をするときにinclude?
とmethod_defined?
を使用すべきだとみんなが提案している理由がわかりません。
class Test
def hello; end
end
Test.method_defined? :hello #=> true
NOTE
別のRuby言語OOからORにアクセスする場合、method_defined
は明示的に定義したメソッドのみを意味すると思います:
def my_method
end
次にこれを読んでください:
Rubyでは、モデルのプロパティ(属性)も基本的にメソッドです。したがって、method_defined?
はメソッドに対してもtrueを返しますメソッドだけではありません。
例えば:
String属性first_name
を持つクラスのインスタンスを指定します:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
first_name
は属性とメソッド(およびString型の文字列)の両方であるためです。
次のようにmethod_defined?
を使用できます。
String.method_defined? :upcase # => true
instance_methods.include?
よりもはるかに簡単で、移植性があり、効率的です。
クラスがmethod_missing
を使用していくつかの呼び出しに動的に応答するかどうかは、たとえばrespond_to?
を再定義することによって、または respond_to_missing?
を定義することによってRuby 1.9.2以降 。
実際、これはオブジェクトとクラスの両方で機能しません。
これは:
class TestClass
def methodName
end
end
したがって、与えられた答えで、これは機能します:
TestClass.method_defined? :methodName # => TRUE
しかし、これは機能しません:
t = TestClass.new
t.method_defined? : methodName # => ERROR!
したがって、クラスとオブジェクトの両方にこれを使用します。
クラス:
TestClass.methods.include? 'methodName' # => TRUE
オブジェクト:
t = TestClass.new
t.methods.include? 'methodName' # => TRUE
「 クラスを指定して、インスタンスにメソッド(Ruby)があるかどうかを確認する 」の答えの方が優れています。どうやらRubyにこのビルトインがあり、どういうわけか見逃しました。とにかく、私の答えは参照用に残されています。
Rubyクラスは、メソッド instance_methods
および public_instance_methods
に応答します。 Ruby 1.8では、最初のメソッドは文字列の配列内のすべてのインスタンスメソッド名をリストし、2番目のメソッドはそれをパブリックメソッドに制限します。 respond_to?
もデフォルトでパブリックメソッドに制限しているため、2番目の動作が最も望ましいと思われます。
Foo.public_instance_methods.include?('bar')
ただし、Ruby 1.9では、これらのメソッドはシンボルの配列を返します。
Foo.public_instance_methods.include?(:bar)
これを頻繁に行う予定がある場合は、Module
を拡張してショートカットメソッドを含めることをお勧めします。 (これをModule
の代わりにClass
に割り当てるのは奇妙に思えるかもしれませんが、それがinstance_methods
メソッドが存在する場所であるため、そのパターンに沿っておくことが最善です。)
class Module
def instance_respond_to?(method_name)
public_instance_methods.include?(method_name)
end
end
Ruby 1.8とRuby 1.9の両方をサポートする場合は、文字列と記号の両方を検索するロジックを追加するのに便利な場所です。
Foo.instance_methods.include? :bar
を試してください
これが最善の方法であるかどうかはわかりませんが、常にこれを行うことができます。
Foo.instance_methods.include? 'bar'
オブジェクトが一連のメソッドに応答できるかどうかを確認している場合、次のようなことができます。
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
methods & something.methods
は、共通/一致する要素で2つの配列を結合します。 something.methodsには、チェック対象のすべてのメソッドが含まれており、メソッドと同等です。例えば:
[1,2] & [1,2,3,4,5]
==> [1,2]
そう
[1,2] & [1,2,3,4,5] == [1,2]
==> true
この場合、.methodsを呼び出すとシンボルの配列が返され、["my", "methods"]
を使用するとfalseが返されるため、シンボルを使用する必要があります。
Railsのmethod_defined?
に何か問題があると思います。一貫性がないか何かである可能性があるため、Railsを使用する場合は、 attribute_method?(attribute)
の何かを使用することをお勧めします。
" ActiveRecordクラスのmethod_definedのテストは、インスタンス化まで動作しません "は不整合に関する質問です。
Ruby 2.5.3を扱う私の場合、次の文は完全に機能しました。
value = "hello world"
value.methods.include? :upcase
ブール値trueまたはfalseを返します。
class Foo
def self.fclass_method
end
def finstance_method
end
end
foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method]
foo_obj.class.instance_methods(false)
=> [:fclass_method]
これがあなたを助けることを願っています!
Rubyバージョンに応じて、klass.instance_methods.include :method_name
または"method_name"
。