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.
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
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.
Une autre approche, utilisant $ VERBOSE, pour supprimer les avertissements, est discutée ici: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_Ruby/
À 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.