Ruby에서 클래스 계층 구조를 쉽게 올릴 수 있습니다.
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
계층 구조를 내릴 수있는 방법이 있습니까? 나는 이것을하고 싶다
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
그러나 방법이없는 것 같습니다 descendants
.
(이 질문은 기본 클래스에서 내려온 Rails 응용 프로그램의 모든 모델을 찾아서 나열하려고하기 때문에 발생합니다. 그러한 모델에서 작동 할 수있는 컨트롤러가 있으며 새 모델을 추가하고 싶습니다. 컨트롤러를 수정할 필요가 없습니다.)
답변
예를 들면 다음과 같습니다.
class Parent
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class Child < Parent
end
class GrandChild < Child
end
puts Parent.descendants
puts Child.descendants
Parent.descendants는 다음을 제공합니다.
GrandChild
Child
Child.descendants가 제공하는 내용 :
GrandChild
답변
Rails> = 3을 사용하면 두 가지 옵션이 있습니다. .descendants
하나 이상의 수준의 하위 클래스를 원하거나 .subclasses
첫 번째 하위 클래스에 사용하려는 경우에 사용하십시오 .
예:
class Animal
end
class Mammal < Animal
end
class Dog < Mammal
end
class Fish < Animal
end
Animal.subclasses #=> [Mammal, Fish]
Animal.descendants #=> [Dog, Mammal, Fish]
답변
멋진 체인 반복자가 포함 된 Ruby 1.9 (또는 1.8.7) :
#!/usr/bin/env ruby1.9
class Class
def descendants
ObjectSpace.each_object(::Class).select {|klass| klass < self }
end
end
루비 pre-1.8.7 :
#!/usr/bin/env ruby
class Class
def descendants
result = []
ObjectSpace.each_object(::Class) {|klass| result << klass if klass < self }
result
end
end
다음과 같이 사용하십시오.
#!/usr/bin/env ruby
p Animal.descendants
답변
inherited 라는 클래스 메서드를 재정의하십시오 . 이 메소드는 생성 될 때 추적 할 수있는 서브 클래스로 전달됩니다.
답변
또는 (ruby 1.9+로 업데이트) :
ObjectSpace.each_object(YourRootClass.singleton_class)
루비 1.8 호환 방식 :
ObjectSpace.each_object(class<<YourRootClass;self;end)
모듈에서는 작동하지 않습니다. 또한 YourRootClass가 답변에 포함됩니다. Array #-또는 다른 방법으로 제거 할 수 있습니다.
답변
오브젝트 공간의 작품을 사용하지만, 상속 클래스 메소드는 여기에 더 적합한 것 같다 (서브 클래스) 루비 문서 상속
객체 공간은 본질적으로 현재 할당 된 메모리를 사용하는 모든 것에 액세스 할 수있는 방법이므로 Animal 클래스의 하위 요소인지 여부를 확인하기 위해 모든 요소 중 하나를 반복하는 것이 이상적이지 않습니다.
아래 코드에서 상속 된 Animal 클래스 메서드는 새로 만든 하위 클래스를 하위 배열에 추가하는 콜백을 구현합니다.
class Animal
def self.inherited(subclass)
@descendants = []
@descendants << subclass
end
def self.descendants
puts @descendants
end
end
답변
상속 에서이 작업을 수행하는 방법을 묻고 있지만 루비에서 직접 이름을 지정하여 클래스의 이름을 지정 하여이 작업을 수행 할 수 있습니다 ( Class
또는 Module
)
module DarthVader
module DarkForce
end
BlowUpDeathStar = Class.new(StandardError)
class Luck
end
class Lea
end
end
DarthVader.constants # => [:DarkForce, :BlowUpDeathStar, :Luck, :Lea]
DarthVader
.constants
.map { |class_symbol| DarthVader.const_get(class_symbol) }
.select { |c| !c.ancestors.include?(StandardError) && c.class != Module }
# => [DarthVader::Luck, DarthVader::Lea]
ObjectSpace
다른 솔루션이 제안하는 것처럼 모든 클래스와 비교하는 것보다 훨씬 빠릅니다 .
상속에서 이것을 심각하게 필요로한다면 다음과 같이 할 수 있습니다 :
class DarthVader
def self.descendants
DarthVader
.constants
.map { |class_symbol| DarthVader.const_get(class_symbol) }
end
class Luck < DarthVader
# ...
end
class Lea < DarthVader
# ...
end
def force
'May the Force be with you'
end
end
여기에 벤치 마크 :
http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
최신 정보
결국 당신이해야 할 일은 이것입니다
class DarthVader
def self.inherited(klass)
@descendants ||= []
@descendants << klass
end
def self.descendants
@descendants || []
end
end
class Foo < DarthVader
end
DarthVader.descendants #=> [Foo]
제안 해 주셔서 감사합니다 @ saturnflyer