Pregunta

Solo quiero saber la mejor manera de emular una enumeración de estilo C # en Ruby.

¿Fue útil?

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.

Enumerations and Ruby

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top