Comment utiliser des énumérations de style C # dans Ruby?
-
03-07-2019 - |
Question
Je veux juste connaître le meilleur moyen d'émuler une énumération de style C # en Ruby.
La solution
Plus précisément, j'aimerais pouvoir effectuer des tests logiques par rapport à l'ensemble de valeurs donné à une variable. Exemple: l’état d’une fenêtre: "minimisé, maximisé, fermé, ouvert"
Si vous avez besoin que les énumérations correspondent aux valeurs (par exemple, vous devez minimisé pour égaler 0, maximisé pour être égal à 100, etc.) J'utiliserais un hachage de symboles en valeurs, comme ceci:
WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze
Le gel (comme le dit nate) vous empêche de tout casser à l'avenir par accident. Vous pouvez vérifier si quelque chose est valide en faisant ceci
WINDOW_STATES.keys.include?(window_state)
Sinon, si vous n'avez besoin d'aucune valeur et que vous devez simplement cocher 'appartenance', alors un tableau est bien
WINDOW_STATES = [:minimized, :maximized].freeze
Utilisez-le comme ceci
WINDOW_STATES.include?(window_state)
Si vos clés doivent être des chaînes (comme par exemple un champ "Etat" dans une application RoR), vous pouvez utiliser un tableau de chaînes. Je le fais TOUT LE TEMPS dans beaucoup de nos applications de rails.
WINDOW_STATES = %w(minimized maximized open closed).freeze
C’est à peu près ce pour quoi le validateur rails validates_inclusion_of
est conçu à cet effet: -)
Note personnelle:
Je n'aime pas taper include? tout le temps, donc j'ai ce (c'est compliqué seulement à cause du cas .in? (1, 2, 3):
class Object
# Lets us write array.include?(x) the other way round
# Also accepts multiple args, so we can do 2.in?( 1,2,3 ) without bothering with arrays
def in?( *args )
# if we have 1 arg, and it is a collection, act as if it were passed as a single value, UNLESS we are an array ourselves.
# The mismatch between checking for respond_to on the args vs checking for self.kind_of?Array is deliberate, otherwise
# arrays of strings break and ranges don't work right
args.length == 1 && args.first.respond_to?(:include?) && !self.kind_of?(Array) ?
args.first.include?( self ) :
args.include?( self )
end
end
end
Ceci vous permet de taper
window_state.in? WINDOW_STATES
Autres conseils
Ce n'est pas tout à fait pareil, mais je construis souvent un hash pour ce genre de chose:
STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()
Le fait de geler le hachage m'empêche d'en modifier accidentellement le contenu.
De plus, si vous souhaitez générer une erreur lorsque vous accédez à quelque chose qui n'existe pas, vous pouvez utiliser un Proc par défaut pour le faire:
STATES = Hash.new { |hash, key| raise NameError, "#{key} is not allowed" }
STATES.merge!({:open => 1, :closed => 2, :max => 3, :min => 4}).freeze()
STATES[:other] # raises NameError
Je ne pense pas que Ruby supporte les vrais enums - bien qu'il existe encore des solutions.
La méthode la plus simple pour définir un Enum dans ruby ??consiste à utiliser une classe avec des variables constantes.
class WindowState
Open = 1
Closed = 2
Max = 3
Min = 4
end
Faire un cours ou un hachage, comme d’autres l’ont dit, fonctionnera. Cependant, Ruby doit utiliser symboles . Les symboles en Ruby commencent par deux points et ressemblent à ceci:
greetingtype = :hello
Ils sont un peu comme des objets qui consistent uniquement en un nom.