Comment vérifier si un cours existe déjà dans Ruby?
Mon code est:
puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval (" #{nameofclass}...... Not sure what to write here")
Je pensais utiliser:
eval "#{nameofclass}ancestors. ....."
Vous pouvez utiliser Module.const_get
pour obtenir la constante référencée par la chaîne. Il retournera la constante (généralement les classes sont référencées par des constantes). Vous pouvez ensuite vérifier si la constante est une classe.
Je voudrais faire quelque chose dans ce sens:
def class_exists?(class_name)
klass = Module.const_get(class_name)
return klass.is_a?(Class)
rescue NameError
return false
end
De plus, si possible, j'éviterais toujours d'utiliser eval
lors de l'acceptation d'une entrée d'utilisateur; Je doute que cela puisse être utilisé pour des applications sérieuses, mais cela vaut la peine d'être conscient des risques pour la sécurité.
peut-être que vous pouvez le faire avec défini?
par exemple:
if defined?(MyClassName) == 'constant' && MyClassName.class == Class
puts "its a class"
end
Remarque: la vérification de classe est requise, par exemple:
Hello = 1
puts defined?(Hello) == 'constant' # returns true
Pour répondre à la question initiale:
puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval("defined?(#{nameofclass}) == 'constant' and #{nameofclass}.class == Class")
Vous pouvez éviter d'avoir à extraire NameError de Module.const_get
si vous recherchez la constante dans une certaine étendue en appelant Module#const_defined?("SomeClass")
.
Un objet commun pour appeler cela serait Object, par exemple: Object.const_defined?("User")
.
Voir: " Module ".
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
Les noms de classe sont des constantes. Vous pouvez utiliser la méthode defined?
pour voir si une constante a été définie.
defined?(String) # => "constant"
defined?(Undefined) # => nil
Vous pouvez en savoir plus sur le fonctionnement de defined?
si vous êtes intéressé.
Voici une version plus succincte:
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
Voici quelque chose que je fais parfois pour m'attaquer à ce problème. Vous pouvez ajouter les méthodes suivantes à la classe String de la manière suivante:
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
Ensuite:
'String'.to_class
=> String
'Unicorn'.to_class
=> nil
'puppy'.is_a_defined_class?
=> false
'Fixnum'.is_a_defined_class?
=> true
En une seule ligne, j'écrirais:
!!Module.const_get(nameofclass) rescue false
qui retournera true
only si la nameofclass
donnée appartient à une classe définie.
J'ai utilisé ceci pour voir si une classe était chargée à l'exécution:
def class_exists?(class_name)
ObjectSpace.each_object(Class) {|c| return true if c.to_s == class_name }
false
end
Si vous voulez quelque chose dans le paquet, le finishing_moves
gem ajoute une méthode class_exists?
.
class_exists? :Symbol
# => true
class_exists? :Rails
# => true in a Rails app
class_exists? :NonexistentClass
# => false
Je suppose que vous agirez si la classe n'est pas chargée.
Si vous voulez demander un fichier, pourquoi ne pas simplement vérifier la sortie de require
?
require 'already/loaded'
=> false
Aucune des réponses ci-dessus n'a fonctionné pour moi, peut-être parce que mon code est intégré à un sous-module.
J'ai décidé de créer une méthode class_exists?
dans mon module, en utilisant le code trouvé dans Réponse de Fred Wilmore à "Comment vérifier si une classe est définie?" et enfin arrêté de maudire.
def class_exists?(name)
name.constantize.is_a?(Class) rescue false # rubocop:disable Style/RescueModifier
end
Code complet, pour les curieux:
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
Je l'utilise comme une fabrique qui construit des objets en fonction de la classe de l'objet passé en argument:
Some::Thing.build(something)
=> # A Some::Thing::Base object
Some::Thing.build(something_else)
=> # Another object, which inherits from Some::Thing::Base