クラスが定義されているかどうかを確認するにはどうすればいいですか?


58

文字列をクラス名に変換するにはどうしたらよいですか?そのクラスが既に存在する場合のみですか?

Object.const_get("Amber") 

または

"Amber".constantize 

(Railsの中に)しかし、これらのいずれかがで失敗します:オレンジすでにクラスであれば、私は経由して、クラスに文字列から

得ることができますNameError: uninitialized constant Amberアンバーがクラスでない場合。

私が最初に考えたのはdefined?メソッドを使用することですが、それはまだ存在し、クラスとそうでないものを区別しません:

>> defined?("Object".constantize) 
=> "method" 
>> defined?("AClassNameThatCouldNotPossiblyExist".constantize) 
=> "method" 

文字列名クラスならば、どのように、私はテストしません私はそれを変換しようとする前に? (さて、begin/rescueブロックでNameErrorエラーを捕まえるのはどうですか?あまりにも醜いですか?私は同意します...)

  0

'定義された'の例では、正確にそれを行うことになっているものやっている:Stringオブジェクトの 'constantize'メソッドが定義されている場合はチェックします。文字列に "Object"または "AClassNameThatCouldNotPossiblyExist"が含まれているかどうかは気にしません。 08 5月. 172017-05-08 15:34:40

105

どうすればconst_defined?

開発モードでのオートローディングがあり、Railsのに覚えているので、あなたはそれをテストしているとき、それは難しいことができます:

>> Object.const_defined?('Account') 
=> false 
>> Account 
=> Account(id: integer, username: string, google_api_key: string, created_at: datetime, updated_at: datetime, is_active: boolean, randomize_search_results: boolean, contact_url: string, hide_featured_results: boolean, paginate_search_results: boolean) 
>> Object.const_defined?('Account') 
=> true 
+2

完璧 - ありがとう。自動ローダーの場合、IIRCにはオートローダーリストにあるものを見つける方法があります。それが問題になると、私はそれを掘り下げます。 22 4月. 112011-04-22 18:36:46

  0

ありがとう、ちょうど私が必要な= D 17 4月. 152015-04-17 04:55:35

+3

これはまた、クラスではないものにもマッチします。 03 9月. 152015-09-03 17:47:26


10

は上記@ ctcherryの応答に触発され、ここでは「安全クラスメソッドセンドです'、class_nameは文字列です。 class_nameがクラスに名前を付けていない場合は、nilを返します。

def class_send(class_name, method, *args) 
    Object.const_defined?(class_name) ? Object.const_get(class_name).send(method, *args) : nil 
end 

それにclass_name応答した場合にのみmethod呼び出すアンより安全なバージョン:文字列が有効なクラス名(またはカンマで区切ったリストである場合

def class_send(class_name, method, *args) 
    return nil unless Object.const_defined?(class_name) 
    c = Object.const_get(class_name) 
    c.respond_to?(method) ? c.send(method, *args) : nil 
end 
+2

p.s.あなたがこの回答を気に入っているなら、正しい方向に私を指摘してくれたので、ctcherryの回答をアップしてください。 22 4月. 112011-04-22 18:54:49


0

私がテストするためにバリデータを作成しましたが有効なクラス名の):


1

別の方法では、クラスを取得する場合もあります。クラスが定義されていない場合はnilを返しますので、例外をキャッチする必要はありません。レールで

class String 
    def to_class(class_name) 
    begin 
     class_name = class_name.classify (optional bonus feature if using Rails) 
     Object.const_get(class_name) 
    rescue 
     # swallow as we want to return nil 
    end 
    end 
end 

> 'Article'.to_class 
class Article 

> 'NoSuchThing'.to_class 
nil 

# use it to check if defined 
> puts 'Hello yes this is class' if 'Article'.to_class 
Hello yes this is class 

11

それは本当に簡単です:

amber = "Amber".constantize rescue nil 
if amber # nil result in false 
    # your code here 
end 
  0

'rescue'は、定数がアンロードされ、' const_defined? 'でチェックが偽になることがあるので役に立ちました。 17 6月. 162016-06-17 18:52:29

  0

ありがとうございました! 11 2月. 172017-02-11 12:16:40

  0

例外を抑止することはお勧めできません。https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions 11 9月. 172017-09-11 19:23:25

  0

@AndrewK:Rubyのレスキューは本当に頻繁に使用されます - ofc私はそれが良くない;エリクシルの世界では、これを行う必要がなければ私たちはこれをやろうとしませんが、多くの人がRubyでレスキューを使うことがわかりました 12 9月. 172017-09-12 19:43:44

  0

@Eiji、Agreed。 Rubyを初めて使う人には、それが反パターンであることは知られておらず、避けるべきであるという点で言及したかっただけです。 12 9月. 172017-09-12 20:56:38


2

Object.const_defined?メソッドを使用して、すべての答えが欠陥であると思われます。問題のクラスが遅延ロードのためにまだロードされていない場合、アサーションは失敗します。決定的にこれを達成する唯一の方法はとても似ている?

validate :adapter_exists 

    def adapter_exists 
    # cannot use const_defined because of lazy loading it seems 
    Object.const_get("Irs::#{adapter_name}") 
    rescue NameError => e 
    errors.add(:adapter_name, 'does not have an IrsAdapter') 
    end