web-dev-qa-db-ja.com

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

文字列をクラス名に変換する方法はありますが、そのクラスが既に存在する場合のみですか?

Amberがalreadyクラスの場合、文字列からクラスへは次の方法で取得できます。

Object.const_get("Amber")

または(Railsで)

"Amber".constantize

ただし、Amberがまだクラスでない場合、これらのいずれかはNameError: uninitialized constant Amberで失敗します。

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

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

それで、変換を試みる前に、文字列がクラスに名前を付けるかどうかをどのようにテストしますか? (さて、NameErrorエラーをキャッチするbegin/rescueブロックはどうですか?ugすぎる?同意します...)

69
fearless_fool

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
122
ctcherry

Railsでは本当に簡単です:

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

上記の@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
13
fearless_fool

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
4
TomDunning

文字列が有効なクラス名(または有効なクラス名のコンマ区切りリスト)かどうかをテストするためのバリデーターを作成しました:

class ClassValidator < ActiveModel::EachValidator
  def validate_each(record,attribute,value)
    unless value.split(',').map { |s| s.strip.constantize.is_a?(Class) rescue false }.all?
      record.errors.add attribute, 'must be a valid Ruby class name (comma-separated list allowed)'
    end
  end
end
2
Fred Willmore

クラスを取得したい場合の別のアプローチ。クラスが定義されていない場合は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
1
mahemoff