Come posso usare le enumerazioni in stile C # in Ruby?
-
03-07-2019 - |
Domanda
Voglio solo sapere il modo migliore per emulare un'enumerazione in stile C # in Ruby.
Soluzione
In particolare, vorrei essere in grado di eseguire test logici rispetto all'insieme di valori dati alcune variabili. Esempio potrebbe essere lo stato di una finestra: " minimized, maximized, closed, open "
Se hai bisogno delle enumerazioni per mappare i valori (ad esempio, devi minimizzarli su 0, massimizzare su 100, ecc.) Userei un hash di simboli sui valori, come questo:
WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze
Il congelamento (come dice Nate) ti impedisce di rompere le cose in futuro per caso. Puoi verificare se qualcosa è valido facendo questo
WINDOW_STATES.keys.include?(window_state)
In alternativa, se non hai bisogno di alcun valore e devi solo controllare 'appartenenza', allora un array va bene
WINDOW_STATES = [:minimized, :maximized].freeze
Usalo in questo modo
WINDOW_STATES.include?(window_state)
Se le tue chiavi diventeranno stringhe (come ad esempio un campo 'state' in un'app RoR), puoi usare un array di stringhe. Lo faccio TUTTO IL TEMPO in molte delle nostre app Rails.
WINDOW_STATES = %w(minimized maximized open closed).freeze
Questo è praticamente ciò che rails validates_inclusion_of
validator è appositamente progettato per :-)
Nota personale:
Non mi piace digitare include? tutto il tempo, quindi ho questo (è complicato solo per il 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
Questo ti permette di digitare
window_state.in? WINDOW_STATES
Altri suggerimenti
Non è esattamente lo stesso, ma spesso costruirò un hash per questo tipo di cose:
STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()
Il congelamento dell'hash mi impedisce di modificare accidentalmente il suo contenuto.
Inoltre, se si desidera generare un errore quando si accede a qualcosa che non esiste, è possibile utilizzare un Proc predefinito per farlo:
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
Non credo che Ruby supporti i veri enum - tuttavia, ci sono ancora soluzioni disponibili.
Il modo più semplice per definire un Enum in ruby ??per usare una classe con variabili costanti.
class WindowState
Open = 1
Closed = 2
Max = 3
Min = 4
end
Fare una lezione o un hash come altri hanno detto funzionerà. Tuttavia, la cosa di Ruby da fare è usare simboli . I simboli in Ruby iniziano con i due punti e assomigliano a questo:
greetingtype = :hello
Sono oggetti simili che consistono solo in un nome.