enum pattern

H

hammett

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,
 
M

Markus

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
 
T

Tim Hunter

hammett said:
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.

I've contributed an Enum class to the Gavin Sinclair's addlib project. You
can get the code at http://addlib.rubyforge.org/wiki/wiki.pl?EnumClass.
 
B

Brian Candler

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.

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 :) 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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top