Enum pattern

Hiya!

I'm pretty new to Ruby and I'm looking for an enum-like-type just to make my
code more readeable, but maybe I'm taking a wrong approach (badly influenced
bu others languages I know, no names please :-)) and going against some ruby
pragmatic principles, don't know.
Anyway, if you do know something in the language that might help to
accomplish modeling enums like the example below, in a more clever way, I'll
appreciate the tip.

require 'test/unit'

class DaysOfWeek < String

  @@monday = DaysOfWeek.new("monday")
  @@tuesday = DaysOfWeek.new("tuesday")
  @@wednesday = DaysOfWeek.new("wednesday")
  @@thursday = DaysOfWeek.new("thursday")
  @@friday = DaysOfWeek.new("friday")
  @@saturday = DaysOfWeek.new("saturday")
  @@sunday = DaysOfWeek.new("sunday")

  def DaysOfWeek.Monday
    return @@monday
  end
  def DaysOfWeek.Tuesday
    return @@tuesday
  end
  def DaysOfWeek.Wednesday
    return @@wednesday
  end
  def DaysOfWeek.Thursday
    return @@thursday
  end
  def DaysOfWeek.Friday
    return @@friday
  end
  def DaysOfWeek.Saturday
    return @@saturday
  end
  def DaysOfWeek.Sunday
    return @@sunday
  end

  def DaysOfWeek.to_list
    [ @@monday, @@tuesday, @@wednesday, @@thursday, @@friday, @@saturday,
@@sunday ]
  end

  def DaysOfWeek.from_s(content)
    to_list().find { |item| item == content }
  end

  private
    def initialize(str)
      super(str)
    end
end

class TempTest < Test::Unit::TestCase
  def test_enum
    assert_equal "monday", DaysOfWeek.Monday
    assert_equal "tuesday", DaysOfWeek.Tuesday
    assert_equal DaysOfWeek.Monday, DaysOfWeek.from_s("monday")
  end
end

Cheers,

···

--
hammett
http://www.apache.org/~hammett/
http://jroller.com/page/hammett

Just to get you thinking in other directions (WARNING: THIS CODE WAS
TYPED OFF THE TOP OF MY HEAD AND HAS NOT BE DEBUGGED (OR EVEN RUN)):

class DaysOfWeek < string
    Names = %w{ monday tuesday wednesday thursday friday saturday sunday }
    Objects = Hash.new
    Names.each { |day|
        eval %Q{
            def DaysOfWeek.#{day}
                Objects["#{day}"] ||= DaysOfWeek.new("#{day}")
                end
            }
        }
    def DaysOfWeek.to_list
        Objects.values
        end
    def DaysOfWeek.from_s(content)
        Objects[content]
        end
    private
        def initialize(str)
            super(str)
            end
    end

Something along these lines would do pretty much what the original did.

-- MarkusQ

One way is to use module constants:

  module DaysOfWeek
    Sunday=0
    Monday=1
    Tuesday=2
    Wednesday=3
    Thursday=4
    Friday=5
    Saturday=6
    TO_S = { 0=>"Sunday", 1=>"Monday", } # etc
  end

  a = DaysOfWeek::Sunday
  p DaysOfWeek::TO_S[a] # not very pretty

It feels a bit too much like C, doesn't it :slight_smile: But it's simple and
efficient, especially if the numeric values are useful for ordering.

But since modules and classes are themselves constants, you can use them for
a more intelligent form of enum:

  module DaysOfWeek
    class Sunday; def self.to_s; "Sunday"; end; end
    class Monday; def self.to_s; "Monday"; end; end
    # etc
  end

  a = DaysOfWeek::Sunday # a is a Class
  p a.to_s # that's nice

You can compare a == DaysOfWeek::Sunday, but unfortunately not with === (so
it's doesn't sit well with case statements)

Another way is to have one object instance to represent each day of the
week:

  class DaysOfWeek
    def initialize(c,s)
      @day = c
      @str = s
    end
    def to_s
      @str
    end
  end
  class DaysOfWeek
    Sunday = self.new(0,'Sunday')
    Monday = self.new(1,'Monday')
    # etc
  end

  a = DaysOfWeek::Sunday # a is a DaysOfWeek
  p a.to_s

If the constants have a logical ordering, then this lets you make use of it:

  class DaysOfWeek
    include Comparable
    attr_reader :day
    def <=>(other)
      @day <=> other.day
    end
  end

  p DaysOfWeek::Sunday < DaysOfWeek::Monday # => true

Note that Sunday is still a constant, refering to a single instance of
DaysOfWeek; we are not creating a fresh object every time we use Sunday
anywhere. So statements like

   a = DaysOfWeek::Sunday
   puts "How are you?" if b == DaysOfWeek::Monday

should still be reasonably efficient.

Regards,

Brian.

···

On Fri, Sep 24, 2004 at 01:17:40PM +0900, hammett wrote:

I'm pretty new to Ruby and I'm looking for an enum-like-type just to make my
code more readeable, but maybe I'm taking a wrong approach (badly influenced
bu others languages I know, no names please :-)) and going against some ruby
pragmatic principles, don't know.
Anyway, if you do know something in the language that might help to
accomplish modeling enums like the example below, in a more clever way, I'll
appreciate the tip.

Really nice, thanks everyone!

Cheers,

···

--
hammett
http://www.apache.org/~hammett/
http://jroller.com/page/hammett