文字列をクラス名に変換する方法はありますが、そのクラスが既に存在する場合のみですか?
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すぎる?同意します...)
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
Railsでは本当に簡単です:
amber = "Amber".constantize rescue nil
if amber # nil result in false
# your code here
end
上記の@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
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
文字列が有効なクラス名(または有効なクラス名のコンマ区切りリスト)かどうかをテストするためのバリデーターを作成しました:
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
クラスを取得したい場合の別のアプローチ。クラスが定義されていない場合は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