web-dev-qa-db-fra.com

Comment vérifier si une classe existe déjà en Ruby

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.     ....."
59
Jimmy

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é.

71
Olly

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")
45
Sam Saffron

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 ".

25
stcorbett
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
11
Rob

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é.

7
Tate Johnson

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
6
Mike Bethany
Kernel.const_defined?("Fixnum") # => true
6
lfender6445

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

En une seule ligne, j'écrirais:

!!Module.const_get(nameofclass) rescue false

qui retournera trueonly si la nameofclass donnée appartient à une classe définie.

2
Andrea Salicetti

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
1
Hugh

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
0
Frank Koehl

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
0
stackdump

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
0
Goulven