Como posso usar C enumerações # estilo em Ruby?
-
03-07-2019 - |
Pergunta
Eu só quero saber a melhor maneira para emular uma enumeração C # estilo em Ruby.
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
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.