Rubyにクラスが既に存在するかどうかを確認するにはどうすればよいですか?
私のコードは:
puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval (" #{nameofclass}...... Not sure what to write here")
私は使用することを考えていました:
eval "#{nameofclass}ancestors. ....."
Module.const_get
を使用して、文字列が参照する定数を取得できます。定数を返します(通常、クラスは定数によって参照されます)。その後、定数がクラスであるかどうかを確認できます。
私はこれらの線に沿って何かをするでしょう:
def class_exists?(class_name)
klass = Module.const_get(class_name)
return klass.is_a?(Class)
rescue NameError
return false
end
また、可能であれば、ユーザー入力を受け入れるときにeval
の使用を常に避けます。私はこれがどんな深刻なアプリケーションにも使用されるとは思いませんが、セキュリティ上のリスクに注意する価値があります。
おそらくあなたは定義された状態でそれを行うことができますか?
例えば:
if defined?(MyClassName) == 'constant' && MyClassName.class == Class
puts "its a class"
end
注:次のようなクラスチェックが必要です。
Hello = 1
puts defined?(Hello) == 'constant' # returns true
元の質問に答えるには:
puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval("defined?(#{nameofclass}) == 'constant' and #{nameofclass}.class == Class")
Module#const_defined?("SomeClass")
を呼び出すことにより、特定のスコープ内で定数を探している場合、_Module.const_get
_からNameErrorを救出する必要がなくなります。
これを呼び出す一般的なスコープはObjectです。例:Object.const_defined?("User")
。
「 Module 」を参照してください。
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
クラス名は定数です。 defined?
メソッドを使用して、定数が定義されているかどうかを確認できます。
defined?(String) # => "constant"
defined?(Undefined) # => nil
興味があるなら defined?
がどのように機能するかについてもっと読むことができます。
より簡潔なバージョンは次のとおりです。
def class_exists?(class_name)
eval("defined?(#{class_name}) && #{class_name}.is_a?(Class)") == true
end
class_name = "Blorp"
class_exists?(class_name)
=> false
class_name = "String"
class_exists?(class_name)
=> true
Kernel.const_defined?("Fixnum") # => true
この問題に取り組むために私が時々することがあります。次のメソッドをStringクラスに次のように追加できます。
class String
def to_class
my_const = Kernel.const_get(self)
my_const.is_a?(Class) ? my_const : nil
rescue NameError
nil
end
def is_a_defined_class?
true if self.to_class
rescue NameError
false
end
end
次に:
'String'.to_class
=> String
'Unicorn'.to_class
=> nil
'puppy'.is_a_defined_class?
=> false
'Fixnum'.is_a_defined_class?
=> true
1行だけで、次のように記述します。
!!Module.const_get(nameofclass) rescue false
指定されたtrue
が定義されたクラスに属する場合にのみnameofclass
を返します。
これを使用して、実行時にクラスがロードされたかどうかを確認しました。
def class_exists?(class_name)
ObjectSpace.each_object(Class) {|c| return true if c.to_s == class_name }
false
end
パッケージ化する場合は、 finishing_moves
gemは class_exists?
メソッド。
class_exists? :Symbol
# => true
class_exists? :Rails
# => true in a Rails app
class_exists? :NonexistentClass
# => false
クラスがロードされていない場合は、何らかのアクションを起こすと思います。
ファイルが必要な場合は、単にrequire
の出力を確認してみませんか?
require 'already/loaded'
=> false
おそらく私のコードがサブモジュールのスコープ内にあるため、上記の答えはどれもうまくいきませんでした。
私はclass_exists?
メソッドは、 「クラスが定義されているかどうかを確認するにはどうすればいいですか?」 に対する(= /// =)Fred Wilmoreの応答にあるコードを使用します。
def class_exists?(name)
name.constantize.is_a?(Class) rescue false # rubocop:disable Style/RescueModifier
end
好奇心のための完全なコード:
module Some
module Thing
def self.build(object)
name = "Some::Thing::#{object.class.name}"
class_exists?(name) ? name.constantize.new(object) : Base.new(object)
end
def self.class_exists?(name)
name.constantize.is_a?(Class) rescue false # rubocop:disable Style/RescueModifier
end
private_class_method :class_exists?
end
end
引数として渡されたオブジェクトのクラスに応じてオブジェクトを構築するファクトリーとして使用します。
Some::Thing.build(something)
=> # A Some::Thing::Base object
Some::Thing.build(something_else)
=> # Another object, which inherits from Some::Thing::Base