루비에서 클래스의 모든 자손을 찾으십시오.
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 클래스의 하위 요소인지 여부를 확인하기 위해 모든 요소 중 하나를 반복하는 것이 이상적이지 않습니다.
In the code below, the inherited Animal class method implements a callback that will add any newly created subclass to its descendants array.
class Animal
def self.inherited(subclass)
@descendants = []
@descendants << subclass
end
def self.descendants
puts @descendants
end
end
I know you are asking how to do this in inheritance but you can achieve this with directly in Ruby by name-spacing the class (Class
or 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]
It's much faster this way than comparing to every class in ObjectSpace
like other solutions propose.
If you seriously need this in a inheritance you can do something like this:
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
benchmarks here: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
update
in the end all you have to do is this
class DarthVader
def self.inherited(klass)
@descendants ||= []
@descendants << klass
end
def self.descendants
@descendants || []
end
end
class Foo < DarthVader
end
DarthVader.descendants #=> [Foo]
thank you @saturnflyer for suggestion
(Rails <= 3.0 ) Alternatively you could use ActiveSupport::DescendantsTracker to do the deed. From source:
This module provides an internal implementation to track descendants which is faster than iterating through ObjectSpace.
Since it is modularize nicely, you could just 'cherry-pick' that particular module for your Ruby app.
Ruby Facets has Class#descendants,
require 'facets/class/descendants'
It also supports a generational distance parameter.
A simple version that give an array of all the descendants of a class:
def descendants(klass)
all_classes = klass.subclasses
(all_classes + all_classes.map { |c| descendants(c) }.reject(&:empty?)).flatten
end
You can require 'active_support/core_ext'
and use the descendants
method. Check out the doc, and give it a shot in IRB or pry. Can be used without Rails.
Rails provides a subclasses method for every object, but it's not well documented, and I don't know where it's defined. It returns an array of class names as strings.
Using descendants_tracker gem may help. The following example is copied from the gem's doc:
class Foo
extend DescendantsTracker
end
class Bar < Foo
end
Foo.descendants # => [Bar]
This gem is used by the popular virtus gem, so I think it's pretty solid.
This method will return a multidimensional hash of all of an Object's descendants.
def descendants_mapper(klass)
klass.subclasses.reduce({}){ |memo, subclass|
memo[subclass] = descendants_mapper(subclass); memo
}
end
{ MasterClass => descendants_mapper(MasterClass) }
If you have access to code before any subclass is loaded then you can use inherited method.
If you don't (which is not a case but it might be useful for anyone who found this post) you can just write:
x = {}
ObjectSpace.each_object(Class) do |klass|
x[klass.superclass] ||= []
x[klass.superclass].push klass
end
x[String]
Sorry if I missed the syntax but idea should be clear (I don't have access to ruby at this moment).
참고URL : https://stackoverflow.com/questions/2393697/look-up-all-descendants-of-a-class-in-ruby
'Programing' 카테고리의 다른 글
모든 프로그래머가 메모리에 대해 알아야 할 사항 (0) | 2020.06.22 |
---|---|
Java 8에서 스트림을 캐스트 할 수 있습니까? (0) | 2020.06.22 |
setTimeout 재설정 (0) | 2020.06.22 |
Vim으로 Git 커밋 메시지를 입력 할 때 발생하는 문제 (0) | 2020.06.21 |
CoffeeScript에서 댓글을 어떻게 작성합니까? (0) | 2020.06.21 |