Forum: Ruby Idiomatic Ruby: Enumerations

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
List R. (Guest)
on 2006-02-21 09:31
(Received via mailing list)
Hi.  I'd appreciate comments/criticisms on the following approach &
code:

For some variables, we need to be able to choose from enumerations.
For instance, we track different choices on a webform - each has an
integer code, as well as some other properties.  I want to implement a
class which these are made out of.

How's this?:

class TimeSlot

	# Only use predefined
	private_class_method :new

	# The text description
	attr_reader :text

	# The integer code
	attr_reader :code

          # The legacy_id (key in a legacy database)
	attr_reader :legacy_id

	def initialize(text, code, legacy_id)
		@text = text
		@code = code
		@legacy_id = legacy_id
	end

	MORNING = new('morning', 2, 1001)
	AFTERNOON = new('morning', 3, 1002)
	EVENING = new('evening', 4, 1003)
	NIGHT = new('night', 5, 1004')

          # This next line is unDRY, but I'm not sure how to eliminate
it.
           # Perhaps instead of just listing the constansts, use a
register_value method which both defines the constant
          # and adds it to the @@values - but I'm not sure how to
implement this
	@@members = [MORNING, AFTERNOON, EVENING, NIGHT]

	def self.from_code(c)
		@@members.find { |t| t.code == c } || raise ArgumentError, "No
TimeSlot has code #{c}"
	end

end

Also - we have several of these - how would I extract a common
Enumeration mixin?  I'd like to be able to include Enumeration, much as
you include Singleton, to turn a class into an enumeration type along
these lines.
Robert K. (Guest)
on 2006-02-21 11:50
(Received via mailing list)
removed_email_address@domain.invalid wrote:
> class TimeSlot
>          # The legacy_id (key in a legacy database)
> EVENING = new('evening', 4, 1003)
> NIGHT = new('night', 5, 1004')
>
>          # This next line is unDRY, but I'm not sure how to eliminate
> it.
>           # Perhaps instead of just listing the constansts, use a
> register_value method which both defines the constant
>          # and adds it to the @@values - but I'm not sure how to
> implement this
> @@members = [MORNING, AFTERNOON, EVENING, NIGHT]

I would not use a class variable here as it does not seem needed.  A
simple
class member will be sufficient.  As for the definition method:

def self.enum(*a)
  c = new(*a).freeze
  (@members || = []) << c
  c
end

Then you can do

MORNING = enum 'morning', 2, 1001

OTOH, you do not need this at all.  You can simply use
TimeSlot.constants to
get all constants defined in this class.  If you need to be more
selective
(foe example if you define nested classes in this class) you can do

def self.enums
  constants.select {|x| self === x}
end

Which will select only instances of TimeSlot.

> along these lines.
I think I've seen an enumeration module on RAA.  If not it will be quite
easy to put some code in a module and implement YourModule#included or
YourModule#extended to make certain changes (like making new private).
HTH

Kind regards

    robert
This topic is locked and can not be replied to.