Pergunta

Eu só quero saber a melhor maneira para emular uma enumeração C # estilo em Ruby.

Foi útil?

Solução

Especificamente, eu gostaria de ser capaz de realizar testes lógicos contra o conjunto de valores dada alguma variável. Exemplo seria o estado de uma janela: "minimizada, maximizada, fechado, aberto"

Se você precisar as enumerações para mapear valores (por exemplo, você precisa minimizado para igual 0, maximizada para igual a 100, etc) eu usaria um hash de símbolos para valores, como este:

WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze

O congelamento (como Nate diz) você pára de quebrar as coisas no futuro por acidente. Você pode verificar se algo é válido, fazendo isso

WINDOW_STATES.keys.include?(window_state)

Como alternativa, se você não precisa de quaisquer valores, e só precisa verificar 'filiação', então um array é bom

WINDOW_STATES = [:minimized, :maximized].freeze

Use-o como este

WINDOW_STATES.include?(window_state)

Se suas chaves vão ser cordas (como por exemplo um campo de 'estado' em um aplicativo de RoR), então você pode usar uma matriz de strings. Eu faço isso o tempo todo em muitas das nossas aplicações Rails.

WINDOW_STATES = %w(minimized maximized open closed).freeze

Isso é muito bonito o que rails validador validates_inclusion_of é construído propositadamente para: -)

Nota pessoal:

Eu não gosto de digitação incluem? o tempo todo, então eu tenho isso (ele só é complicado por causa da .in (1, 2, 3) caso:?

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

Isso permite que você digite

window_state.in? WINDOW_STATES

Outras dicas

Não é bem a mesma coisa, mas muitas vezes eu vou construir um hash para este tipo de coisa:

STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()

Congelar o hash me impede de acidentalmente modificar seu conteúdo.

Além disso, se você quiser aumentar um erro ao acessar algo que não existe, você pode usar um defualt Proc para fazer isso:

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

Eu não acho que o Ruby suporta verdadeiros enums -., Porém, ainda existem soluções disponíveis

Enumerations e Ruby

A maneira mais fácil de definir um enum em Ruby para usar uma classe com variáveis ??constantes.

class WindowState
  Open = 1
  Closed = 2
  Max = 3
  Min = 4
end

Fazendo uma classe ou de hash como outros já disse que o trabalho vontade. No entanto, a coisa Ruby para fazer é usar símbolos . Símbolos em Ruby começar com dois pontos e ficar assim:

greetingtype = :hello

Eles são tipo como de objetos que consistem apenas de um nome.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top