Rubyクラスが別のクラスのサブクラスであるかどうかをテストする


187

クラスが別のクラスから継承するかどうかをテストしたいのですが、そのためのメソッドが存在しないようです。

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

私が欲しいものの簡単な実装は次のようになります:

class Class
  def is_subclass_of?(clazz)
    return true if superclass == clazz
    return false if self == Object
    superclass.is_subclass_of?(clazz)
  end
end

しかし、私はこれがすでに存在することを期待します。


2
A.class #=> Class。これがB.is_a? Afalseを返す理由です。
ウェン

どうkind_of?
ですか

1
kind_of?オブジェクトがクラスのインスタンスであるかどうかをテストします。オブジェクトがクラスから継承するかどうかではありません。
混乱

5
kind_of?の別名ですis_a?
coreyward 2017

回答:


355

<演算子を使用するだけ

B < A # => true
A < A # => false

または<=演算子を使用

B <= A # => true
A <= A # => true

13
@Brian はにis_a?変換されるため、のインスタンスですBインスタンスではないAB.newしかしされます(B.new.is_a? A # => true)。
Marcel Jackwerth、2012年

4
うーん、奇妙な構文(私の最初の推測ではなかっただろう)が、説明をありがとう!
ブライアンアームストロング

2
ドキュメントについては、コアAPI /モジュール/#<を参照してください。
webwurst 2013

2
Rubyとの私の愛/憎しみの関係は続いています…なぜクラスの関係を宣言するために使用される演算子に異なる関数を提供し、それを行う2つの異なる方法を提供するのですか?
Ben Gotow 2013

4
@BenGotow-1. <は演算子ではないので、メソッドです。2. <はサブクラスのみをチェックするため、<=にはselfも含まれます。
超照明

59

また利用できる:

B.ancestors.include? A

に含まれているB < Aため、これは(短い)回答とは少し異なります。BB.ancestors

B.ancestors
#=> [B, A, Object, Kernel, BasicObject]

B < B
#=> false

B.ancestors.include? B
#=> true

これが望ましいかどうかは、ユースケースによって異なります。


24
より読みやすい:(B <= Bと同じ結果B.ancestors.include? B)。
Marcel Jackwerth、

更新:直前のソリューションは1.9以降で動作しますが、「祖先」はありませんか?1.9で。

8
これは、 '<'構文に慣れていない人を混乱させないでしょう。そのため、私はそれを好みます。
Asfand Qazi 2013

2
@SimonLepkinおそらくマイクロ秒がカチカチ音をたてるのを経験できない限り、「しばらく」ではないでしょう。;)はい、舞台裏でinclude?and <メソッドは祖先チェーンをループします。Cでこれを行うので、Ruby配列をループするよりも確実に高速ですが、実際には2つは区別できません。
Phrogz、2015

1
@JunanChakma英語の「祖先」という単語の定義に基づいて、戻り値にを含めないことに同意しますB。しかし、そうです。メソッドのドキュメントは、言います「(MODで先頭に追加モジュールのリストが含ま返品/ MOD自体を含むが)。」(強調鉱山)。を使用するときに便利な独自のクラスが含まれていると思いますが、これは私の推測に.include?すぎません。
Phrogz 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.