Ruby의 인스턴스에서 비공개 클래스 메서드를 호출하는 방법이 있나요?
-
09-06-2019 - |
문제
이것 말고도 self.class.send :method, args...
, 물론.코드를 복제하지 않고 클래스와 인스턴스 수준 모두에서 사용할 수 있는 다소 복잡한 메서드를 만들고 싶습니다.
업데이트:
@조나단 브래넘:그것은 내 가정이었지만, 다른 누구도 방법을 찾지 못했음을 확인하고 싶었습니다.Ruby의 가시성은 Java의 가시성과 매우 다릅니다.당신 말이 정말 맞아요 private
클래스 메소드에서는 작동하지 않지만 비공개 클래스 메소드를 선언합니다.
class Foo
class <<self
private
def bar
puts 'bar'
end
end
end
Foo.bar
# => NoMethodError: private method 'bar' called for Foo:Class
해결책
다음은 질문과 관련된 코드 조각입니다.클래스 정의에서 "private"을 사용하는 것은 클래스 메서드에 적용되지 않습니다.다음 예시와 같이 "private_class_method"를 사용해야 합니다.
class Foo
def self.private_bar
# Complex logic goes here
puts "hi"
end
private_class_method :private_bar
class <<self
private
def another_private_bar
puts "bar"
end
end
public
def instance_bar
self.class.private_bar
end
def instance_bar2
self.class.another_private_bar
end
end
f=Foo.new
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class
이 문제를 해결할 방법이 없습니다.설명서에는 개인 메서드의 수신을 지정할 수 없다고 나와 있습니다.또한 동일한 인스턴스에서만 비공개 메서드에 액세스할 수 있습니다.Foo 클래스는 Foo의 특정 인스턴스와 다른 개체입니다.
내 대답을 최종적인 것으로 받아들이지 마십시오.저는 확실히 전문가는 아니지만 답변을 시도하는 다른 사람들이 적절한 비공개 클래스 메소드를 가질 수 있도록 코드 조각을 제공하고 싶었습니다.
다른 팁
다소 이상한 솔루션과 비 솔루션 목록에 기여하겠습니다.
puts RUBY_VERSION # => 2.1.2
class C
class << self
private def foo
'Je suis foo'
end
end
private define_method :foo, &method(:foo)
def bar
foo
end
end
puts C.new.bar # => Je suis foo
puts C.new.foo # => NoMethodError
귀하의 방법이 단지 유틸리티 기능 (즉, 인스턴스 변수에 의존하지 않습니다.) 메소드를 모듈에 넣고 include
그리고 extend
프라이빗 클래스 메서드와 프라이빗 인스턴스 메서드 모두로 사용할 수 있도록 클래스를 생성합니다.
요즘에는 더 이상 도우미 메서드가 필요하지 않습니다.메소드 정의를 사용하여 간단히 인라인할 수 있습니다.이는 Java 사용자에게 매우 친숙하게 느껴질 것입니다.
class MyClass
private_class_method def self.my_private_method
puts "private class method"
end
private def my_private_method
puts "private instance method"
end
end
그리고 아니요, 인스턴스 메서드에서 개인 클래스 메서드를 호출할 수 없습니다.그러나 대신 다음을 구현할 수 있습니다. 사적인 클래스 메소드 공공의 클래스 메소드 사적인 대신 중첩 클래스를 사용하여 private_constant
도우미 방법.보다 이 블로그 게시물 자세한 내용은.
이것이 "실제" 비공개 클래스 메서드를 사용하는 방법입니다.
class Foo
def self.private_bar
# Complex logic goes here
puts "hi"
end
private_class_method :private_bar
class <<self
private
def another_private_bar
puts "bar"
end
end
public
def instance_bar
self.class.private_bar
end
def instance_bar2
self.class.another_private_bar
end
def calling_private_method
Foo.send :another_private_bar
self.class.send :private_bar
end
end
f=Foo.new
f.send :calling_private_method
# "bar"
# "hi"
Foo.send :another_private_bar
# "bar"
건배
이것은 아마도 가장 "네이티브 바닐라 Ruby" 방식일 것입니다:
class Foo
module PrivateStatic # like Java
private def foo
'foo'
end
end
extend PrivateStatic
include PrivateStatic
def self.static_public_call
"static public #{foo}"
end
def public_call
"instance public #{foo}"
end
end
Foo.static_public_call # 'static public foo'
Foo.new.public_call # 'instance public foo'
Foo.foo # NoMethodError: private method `foo' called for Foo:Class
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x00007fa154d13f10>
일부 Ruby 메타프로그래밍을 사용하면 다음과 같이 만들 수도 있습니다.
class Foo
def self.foo
'foo'
end
extend PrivateStatic
private_static :foo
end
Ruby의 메타프로그래밍은 매우 강력하므로 원하는 범위 지정 규칙을 기술적으로 구현할 수 있습니다.그럼에도 불구하고 나는 여전히 명확성과 최소한의 놀라움 첫 번째 변종 중.
내가 오해하지 않는 한 다음과 같은 것이 필요하지 않습니까?
class Foo
private
def Foo.bar
# Complex logic goes here
puts "hi"
end
public
def bar
Foo.bar
end
end
물론 클래스 이름을 하드코딩하지 않으려면 self.class.send 접근 방식을 사용하도록 두 번째 정의를 변경할 수 있습니다.