78

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

Amber が既にクラスである場合、次の方法で文字列からクラスに取得できます。

Object.const_get("Amber")

または(Railsで)

"Amber".constantize

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

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

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

では、クラスを変換する前に、文字列がクラスに名前を付けているかどうかをテストするにはどうすればよいでしょうか? (さて、NameError エラーをキャッチするためにbegin/ブロックはどうですか? あまりにも醜いですか? 私は同意します...)rescue

4

6 に答える 6

134

どう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
于 2011-04-22T18:07:56.813 に答える
22

レールでは、それは本当に簡単です:

amber = "Amber".constantize rescue nil
if amber # nil result in false
    # your code here
end
于 2015-09-30T15:23:09.190 に答える
15

上記の@ctcherryの応答に触発されて、ここに「安全なクラスメソッドsend」があります。ここ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

応答したmethod場合にのみ呼び出す、さらに安全なバージョン:class_name

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
于 2011-04-22T18:54:10.317 に答える
6

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
于 2016-03-21T11:33:44.837 に答える
2

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

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
于 2014-08-22T18:14:28.950 に答える