클래스가 주어지면 인스턴스에 메소드가 있는지 확인하십시오 (Ruby)


227

Ruby respond_to?에서 객체에 특정 메소드가 있는지 확인하는 데 사용할 수 있다는 것을 알고 있습니다 .

그러나 클래스가 주어지면 인스턴스에 특정 메소드가 있는지 어떻게 확인할 수 있습니까?

즉, 같은

Foo.new.respond_to?(:bar)

그러나 새로운 인스턴스를 인스턴스화하는 것보다 더 좋은 방법이 있어야한다고 생각합니다.

답변:


364

왜 모든 사람들이 당신이 사용해야하는지 instance_methods그리고 include?언제 method_defined?일 을해야하는지 모르겠습니다 .

class Test
  def hello; end
end

Test.method_defined? :hello #=> true

노트

다른 OO 언어에서 Ruby로 온 경우 또는 method_defined명시 적으로 정의한 메소드 만 의미 한다고 생각합니다 .

def my_method
end

그런 다음 이것을 읽으십시오 :

루비에서는 모델의 속성 (속성)이 기본적으로 방법입니다. 따라서 메서드뿐만 아니라method_defined? 속성에 대해서도 true를 반환합니다 .

예를 들면 다음과 같습니다.

String 속성을 가진 클래스의 인스턴스가 주어지면 first_name:

<instance>.first_name.class #=> String

<instance>.class.method_defined?(:first_name) #=> true

왜냐하면 first_name속성과 메소드 (그리고 문자열 유형의 문자열) 이기 때문 입니다.


9
method_defined? instance_methods가 Ruby 1.8과 1.9 사이에서 변경되었으므로 최상의 솔루션입니다. 1.8은 문자열 배열을 반환하고 1.9는 기호 배열을 반환합니다. method_defined? 1.8과 1.9 모두에서 기호를 사용합니다.
Jason

2
: instance_methods는 매번 호출 할 때마다 새로운 배열을 생성하고 : include? 그런 다음 배열을 걸어야합니다. 대조적으로 : method_defined? 내부적으로 메소드 조회 테이블 (C에있는 하나의 해시 조회)을 조회하고 새 오브젝트를 작성하지 않고 알려줍니다.
Asher

4
이처럼 사용할 때 적어도 하나의 장점이 있지만, String.instance_methods(false).include? :freeze잘못된 인수 여부를 정확히 알 수 있습니다 freeze방법은 String 클래스에 정의되지 않았거나. 이 경우 freeze메서드는 String에 의해 커널 모듈에서 상속 되므로 false를 반환 하지만 String.method_defined? :freeze항상 true를 반환하므로 이러한 목적으로 많은 도움이되지 않습니다.
ugoa

1
@Bane 클래스의 메소드와 인스턴스에서 사용 가능한 메소드를 혼동하고 있습니다. method_defined?클래스 (예를 들어 사용해야합니다 Array(예를 들면),하지만 당신은 경우에 그것을 사용하려고 [])
horseyguy

@banister 절대적으로 맞습니다. 설명을 주셔서 감사합니다, 그것을 읽고 완벽하게 이해합니다. :) 혼동하지 않도록 의견을 삭제했습니다.
베인

45

method_defined?다음과 같이 사용할 수 있습니다 .

String.method_defined? :upcase # => true

instance_methods.include?다른 사람들이 제안하는 것 보다 훨씬 쉽고 휴대 가능하며 효율적 입니다.

클래스 method_missing가 (예를 들어 재정의를 통해 respond_to?) 또는 Ruby 1.9.2를 정의하여 정의 하여 일부 호출에 동적으로 응답하는지 알 수 없습니다 respond_to_missing?.


2
만약 당신이 손에 인스턴스를 가지고 있고 당신이 그것의 클래스를 모른다면, 당신은 할 수 있습니다instance.class.method_defined? :upcase
jaydel

25

실제로 이것은 객체와 클래스 모두에서 작동하지 않습니다.

이것은 :

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

3
예를 들어`instance.class.method_defined? '를 사용할 수도 있습니다.
Luksurious

루비 버전에 따라 다릅니다. 위의 방법은 1.8.7을 포함한 모든 버전에서 작동합니다.
Alex V

10

" 클래스가 주어지면 인스턴스에 메소드 (Ruby)가 있는지 확인하십시오 "에 대한 대답 이 더 낫습니다. 분명히 Ruby에는이 기능이 내장되어 있으며, 어떻게 든 놓쳤습니다. 내 대답은 관계없이 참조 용입니다.

루비 클래스는 방법에 반응 instance_methods하고 public_instance_methods. Ruby 1.8에서 첫 번째는 모든 인스턴스 메소드 이름을 문자열 배열로 나열하고 두 번째는이를 공개 메소드로 제한합니다. 두 번째 동작은 respond_to?기본적으로 공개 메소드로 제한 되기 때문에 가장 원하는 것입니다.

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를 모두 지원하려면 문자열과 기호를 모두 검색하는 논리를 추가하기에 편리한 위치입니다.


1
method_defined?더 낫다 :)
horseyguy

@banister-아, 그리고 나는 어떻게 든 그것을 놓쳤다! xD @Marc의 답변 뒤에 +1을
던지고


3

이것이 최선의 방법인지 확실하지 않지만 항상 이렇게 할 수 있습니다.

Foo.instance_methods.include? 'bar'


3

객체가 일련의 메소드에 응답 할 수 있는지 확인하는 경우 다음과 같은 작업을 수행 할 수 있습니다.

methods = [:valid?, :chase, :test]

def has_methods?(something, methods)
  methods & something.methods == methods
end

methods & something.methods공통 / 일치하는 요소에서 두 배열을 결합합니다. 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를 반환하기 때문에 기호를 사용하려고합니다 .


2

klass.instance_methods.include :method_name또는 "method_name"루비 버전에 따라 다릅니다.


2
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] 

이것이 당신에게 도움이되기를 바랍니다!


1

루비 2.5.3으로 작업하는 경우 다음 문장이 완벽하게 작동했습니다.

value = "hello world"

value.methods.include? :upcase

부울 값 true 또는 false를 리턴합니다.


1

respond_to?공용 메소드에 대해서만 true를 리턴 하지만 클래스에서 "메소드 정의"를 확인하면 개인 메소드와 관련 될 수도 있습니다.

Ruby v2.0 +에서는 공개 및 비공개 세트를 모두 확인할 수 있습니다.

Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.