373 Stimmen

Wie implementiert man Enums in Ruby?

Was ist der beste Weg, um die enum Idiom in Ruby zu implementieren? Ich bin auf der Suche nach etwas, das ich (fast) wie die Java/C# enums verwenden können.

12voto

dB. Punkte 4542

Sehen Sie sich das Rubin-Emaille an, https://github.com/dblock/ruby-enum .

class Gender
  include Enum

  Gender.define :MALE, "male"
  Gender.define :FEMALE, "female"
end

Gender.all
Gender::MALE

12voto

Oded Niv Punkte 2320

Ich weiß, es ist schon lange her, dass der Mann diese Frage gestellt hat, aber ich hatte dieselbe Frage und dieser Beitrag hat mir keine Antwort gegeben. Ich wollte eine einfache Möglichkeit, um zu sehen, was die Zahl darstellt, einfachen Vergleich, und vor allem ActiveRecord Unterstützung für Lookup mit der Spalte, die die Enum.

Da ich nichts gefunden habe, habe ich eine geniale Implementierung namens yinum die alles erlaubte, was ich suchte. Made Tonne von Spezifikationen, so bin ich ziemlich sicher, dass es sicher ist.

Einige Beispielfunktionen:

COLORS = Enum.new(:COLORS, :red => 1, :green => 2, :blue => 3)
=> COLORS(:red => 1, :green => 2, :blue => 3)
COLORS.red == 1 && COLORS.red == :red
=> true

class Car < ActiveRecord::Base    
  attr_enum :color, :COLORS, :red => 1, :black => 2
end
car = Car.new
car.color = :red / "red" / 1 / "1"
car.color
=> Car::COLORS.red
car.color.black?
=> false
Car.red.to_sql
=> "SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 1"
Car.last.red?
=> true

11voto

johnnypez Punkte 141

Dies ist mein Ansatz für Enums in Ruby. Ich wollte kurz und bündig sein, nicht unbedingt das C-ähnlichste. Irgendwelche Ideen?

module Kernel
  def enum(values)
    Module.new do |mod|
      values.each_with_index{ |v,i| mod.const_set(v.to_s.capitalize, 2**i) }

      def mod.inspect
        "#{self.name} {#{self.constants.join(', ')}}"
      end
    end
  end
end

States = enum %w(Draft Published Trashed)
=> States {Draft, Published, Trashed} 

States::Draft
=> 1

States::Published
=> 2

States::Trashed
=> 4

States::Draft | States::Trashed
=> 5

9voto

Daniel Lubarov Punkte 7644

Der beste leichtgewichtige Ansatz wäre vielleicht

module MyConstants
  ABC = Class.new
  DEF = Class.new
  GHI = Class.new
end

Auf diese Weise haben Werte zugehörige Namen, wie in Java/C#:

MyConstants::ABC
=> MyConstants::ABC

Um alle Werte zu erhalten, können Sie Folgendes tun

MyConstants.constants
=> [:ABC, :DEF, :GHI] 

Wenn Sie den Ordinalwert einer Aufzählung benötigen, können Sie Folgendes tun

MyConstants.constants.index :GHI
=> 2

7voto

Andrew Grimm Punkte 73882

Wenn Sie sich Sorgen um Tippfehler bei Symbolen machen, stellen Sie sicher, dass Ihr Code eine Ausnahme auslöst, wenn Sie auf einen Wert mit einem nicht existierenden Schlüssel zugreifen. Sie können dies tun, indem Sie fetch statt [] :

my_value = my_hash.fetch(:key)

oder indem der Hash standardmäßig eine Ausnahme auslöst, wenn Sie einen nicht existierenden Schlüssel angeben:

my_hash = Hash.new do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

Wenn der Hash bereits vorhanden ist, können Sie ein Verhalten, das Ausnahmen auslöst, hinzufügen:

my_hash = Hash[[[1,2]]]
my_hash.default_proc = proc do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

Normalerweise müssen Sie sich bei Konstanten keine Gedanken über die Sicherheit von Tippfehlern machen. Wenn Sie einen Konstantennamen falsch schreiben, wird normalerweise eine Ausnahme ausgelöst.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X