web-dev-qa-db-fra.com

Comment redéfinir une constante Ruby sans avertissement?

J'exécute un code Ruby qui évoque un fichier Ruby chaque fois que sa date change. Dans le fichier, j'ai des définitions constantes, comme

Tau = 2 * Pi

et, bien sûr, ils font que l'interprète affiche à chaque fois l'avertissement indésirable "constante déjà initialisée", donc, j'aimerais avoir les fonctions suivantes:

def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)

Je pourrais éviter l'avertissement en écrivant toutes mes définitions constantes comme ceci:

Tau = 2 * Pi unless defined?(Tau)

mais il est inélégant et un peu mouillé (pas SEC ).

Y a-t-il une meilleure façon de def_if_not_defined? Et comment redef_without_warning?

-

Solution grâce à Steve:

class Object
  def def_if_not_defined(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.const_set(const, value) unless mod.const_defined?(const)
  end

  def redef_without_warning(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.send(:remove_const, const) if mod.const_defined?(const)
    mod.const_set(const, value)
  end
end

A = 1
redef_without_warning :A, 2
fail 'unit test' unless A == 2
module M
  B = 10
  redef_without_warning :B, 20
end
fail 'unit test' unless M::B == 20

-

Cette question est ancienne. Le code ci-dessus n'est nécessaire que pour Ruby 1.8. Dans Ruby 1.9, la réponse de P3t3rU5 ne produit aucun avertissement et est simplement meilleure.

55
Eldritch Conundrum

Le module suivant peut faire ce que vous voulez. Si ce n'est pas le cas, cela peut fournir des conseils sur votre solution

module RemovableConstants

  def def_if_not_defined(const, value)
    self.class.const_set(const, value) unless self.class.const_defined?(const)
  end

  def redef_without_warning(const, value)
    self.class.send(:remove_const, const) if self.class.const_defined?(const)
    self.class.const_set(const, value)
  end
end

Et comme exemple d'utilisation

class A
  include RemovableConstants

  def initialize
    def_if_not_defined("Foo", "ABC")
    def_if_not_defined("Bar", "DEF")
  end

  def show_constants
    puts "Foo is #{Foo}"
    puts "Bar is #{Bar}"
  end

  def reload
    redef_without_warning("Foo", "GHI")
    redef_without_warning("Bar", "JKL")
  end

end

a = A.new
a.show_constants
a.reload
a.show_constants

Donne la sortie suivante

Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL

Pardonnez-moi si j'ai brisé des tabous Ruby ici car je suis toujours en train de me renseigner sur une partie de la structure Module: Class: Eigenclass dans Ruby

60
Steve Weet

Si vous souhaitez redéfinir une valeur, n'utilisez pas de constantes, utilisez plutôt une variable globale ($ tau = 2 * Pi), mais ce n'est pas non plus une bonne pratique. Vous devez en faire une variable d'instance d'une classe appropriée.

Pour l'autre cas, Tau = 2 * Pi unless defined?(Tau) est parfaitement correct et le plus lisible, donc la solution la plus élégante.

4
Leventix

Une autre approche, utilisant $ VERBOSE, pour supprimer les avertissements, est discutée ici: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_Ruby/

3
Paul Lynch

À moins que les valeurs des constantes soient assez étranges (c'est-à-dire que vous avez des constantes définies sur nil ou false), le meilleur choix serait d'utiliser l'opérateur d'affectation conditionnelle: Tau ||= 2*Pi

Cela mettra Tau à 2π s'il est nil, false ou non défini, et le laissera tranquille sinon.

2
Chuck