¿Cómo puedo usar las enumeraciones de estilo C # en Ruby?
-
03-07-2019 - |
Pregunta
Solo quiero saber la mejor manera de emular una enumeración de estilo C # en Ruby.
Solución
Específicamente, me gustaría poder realizar pruebas lógicas contra el conjunto de valores dado alguna variable. Ejemplo sería el estado de una ventana: " minimizado, maximizado, cerrado, abierto "
Si necesita que las enumeraciones se asignen a valores (por ejemplo, necesita minimizarse para que sea igual a 0, maximizado a igual a 100, etc.) usaría un hash de símbolos a valores, como este:
WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze
La congelación (como dice Nate) evita que rompas cosas en el futuro por accidente. Puedes verificar si algo es válido haciendo esto
WINDOW_STATES.keys.include?(window_state)
Alternativamente, si no necesita ningún valor, y solo necesita marcar 'membresía', entonces una matriz está bien
WINDOW_STATES = [:minimized, :maximized].freeze
Úsalo así
WINDOW_STATES.include?(window_state)
Si sus claves serán cadenas (como, por ejemplo, un campo 'estado' en una aplicación RoR), puede usar una serie de cadenas. Hago esto TODO EL TIEMPO en muchas de nuestras aplicaciones de rieles.
WINDOW_STATES = %w(minimized maximized open closed).freeze
Esto es más o menos lo que los códigos validates_inclusion_of
validador está diseñado para :-)
Nota personal:
No me gusta escribir incluir? todo el tiempo, así que tengo esto (solo es complicado debido al caso .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
Esto te permite escribir
window_state.in? WINDOW_STATES
Otros consejos
No es exactamente lo mismo, pero a menudo construiré un hash para este tipo de cosas:
STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()
La congelación del hash me impide modificar accidentalmente su contenido.
Además, si desea generar un error al acceder a algo que no existe, puede usar un Proc defualt para hacer esto:
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
No creo que Ruby sea compatible con las verdaderas enumeraciones. Sin embargo, todavía hay soluciones disponibles.
La forma más fácil de definir un Enum en ruby ??para usar una clase con variables constantes.
class WindowState
Open = 1
Closed = 2
Max = 3
Min = 4
end
Hacer una clase o un hash como otros han dicho funcionará. Sin embargo, lo que Ruby debe hacer es usar símbolos . Los símbolos en Ruby comienzan con dos puntos y se ven así:
greetingtype = :hello
Son objetos similares a los que solo tienen un nombre.