Как я могу использовать перечисления в стиле C # в Ruby? - PullRequest
8 голосов
/ 03 октября 2008

Я просто хочу узнать, как лучше всего эмулировать перечисление в стиле C # в Ruby.

Ответы [ 5 ]

5 голосов
/ 03 октября 2008

В частности, я хотел бы иметь возможность выполнять логические тесты с набором значений, заданных некоторой переменной. Примером может служить состояние окна: «свернуто, развернуто, закрыто, открыто»

Если вам нужны перечисления для сопоставления со значениями (например, вам нужно минимизировать до 0, максимизировать до 100 и т. Д.), Я бы использовал хэш символов для значений, например:

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

Замораживание (как говорит Нейт) останавливает вас от случайного нарушения в будущем. Вы можете проверить, является ли что-то действительным, выполнив это

WINDOW_STATES.keys.include?(window_state)

В качестве альтернативы, если вам не нужны какие-либо значения и вам просто нужно проверить «членство», тогда массив в порядке

WINDOW_STATES = [:minimized, :maximized].freeze

Используйте это так

WINDOW_STATES.include?(window_state)

Если ваши ключи будут строками (как, например, поле 'state' в приложении RoR), тогда вы можете использовать массив строк. Я делаю это ВСЕ ВРЕМЯ во многих наших приложениях rails.

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

Это почти то, для чего предназначен rails validates_inclusion_of validator: -)

Личная заметка:

Я не люблю печатать include? все время, поэтому у меня есть это (это сложно только из-за случая .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

Это позволяет вам печатать

window_state.in? WINDOW_STATES
5 голосов
/ 03 октября 2008

Это не совсем то же самое, но я часто буду создавать хэш для таких вещей:

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

Замораживание хеша не дает мне случайно изменить его содержимое.

Более того, если вы хотите вызвать ошибку при доступе к чему-то, что не существует, вы можете использовать для этого процедуру по умолчанию:

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
3 голосов
/ 03 октября 2008

Самый простой способ определить Enum в ruby ​​- использовать класс с постоянными переменными.

class WindowState
  Open = 1
  Closed = 2
  Max = 3
  Min = 4
end
3 голосов
/ 03 октября 2008

Я не думаю, что Ruby поддерживает истинные перечисления - хотя, все еще есть доступные решения.

Перечисления и Ruby

1 голос
/ 03 октября 2008

Создание класса или хэша, как говорили другие, сработает. Тем не менее, Ruby должен использовать символов . Символы в Ruby начинаются с двоеточия и выглядят так:

greetingtype = :hello

Они похожи на объекты, состоящие только из имени.

...