# Enum

**URL:** <https://www.ruby-forum.com/t/enum/67576>\
**Category:** Ruby\
**Created:** [September 5, 2006, 11:24am UTC](https://www.ruby-forum.com/t/enum/67576 "2006-09-05T11:24:17Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 11:24am UTC](https://www.ruby-forum.com/t/enum/67576/1 "2006-09-05T11:24:17Z")

</div>

I want an enum of sorts in my Rails application.

I have a Project object, which has four possible status settings, as  
indicated here:

class Project \< ActiveRecord:Base  
…  
class \<\< self  
def statuses  
[‘Hidden’, ‘Available’, ‘In progress’, ‘Complete’]  
end  
end  
…  
end

These are not expected to change, so hardcoding is preferable. Of  
course, there is a ‘status’ column in the project table, so rails  
creates a ‘status’ accessor.

However, later in the code I will want to check the status myself. For  
example, ‘Complete’ projects won’t be shown in the same place as  
‘Available’ ones, and ‘In progress’ and ‘Hidden’ projects won’t be shown  
at all (not sure about In progress ATM though, so I want to keep it  
flexible). Now, it would be pretty ugly checking

if a\_project.status == 2 # Project is in progress

So one possibility is to add methods like

class Project  
def in\_progress?  
self.status == 2  
end  
end

Another interesting option is this:

class Project  
def status\_is?(\_status)  
[:hidden, :available, :in\_progress, :complete][self.status] ==  
\_status  
end  
end

If only I could count on hashes staying in order, a very pretty solution  
would  
be:

class Project  
class \<\< self  
def statuses  
{ :hidden =\> ‘Hidden’, :available =\> ‘Available’,  
:in\_progress =\> ‘In progress’, :complete =\> ‘Complete’ }  
# Use Project.statuses.values for the dropdown  
end  
end  
def status\_is?(\_status)  
Project.statuses.keys[self.status] == \_status  
end  
end

Unfortunately, “The order in which you traverse a hash by either key or  
value may seem arbitrary, and will generally not be in the insertion  
order.” (ri).

Any other ideas for elegance?

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 2:06pm UTC](https://www.ruby-forum.com/t/enum/67576/2 "2006-09-05T14:06:19Z")

</div>

Hi

adding some informations to your hash may help, something like…

{ :hidden =\> {:id =\> 1, :label =\> ‘Hidden’}, :available =\> {:id =\> 2,  
:label =\> ‘Available’}, :in\_progress =\> {:id =\> 3, :label =\> ‘In  
progress’}, :complete =\> {:id =\> 4, :label =\> ‘Complete’ }}

gives you an index to trust

and next you can do something like

(note, the code isn’t checked so probably won’t work as it is)

statuses.each do |key, value|  
define\_method(key.to\_s + ‘?’) {  
self.status == value[:id]  
}  
end

to have all the hidden? available? etc. methods.

Anyway I think that if you have a look to the rails humanize method  
you could avoid the label field so you can manage the statuses with a  
simple hash or even an array.

Paolo

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 2:50pm UTC](https://www.ruby-forum.com/t/enum/67576/3 "2006-09-05T14:50:32Z")

</div>

On Sep 5, 2006, at 5:24 AM, Ohad L. wrote:

> ```
> end
> 
> ```
> 
> ‘Available’ ones, and ‘In progress’ and ‘Hidden’ projects won’t be  
> shown  
> at all (not sure about In progress ATM though, so I want to keep it  
> flexible). Now, it would be pretty ugly checking
> 
> if a\_project.status == 2 # Project is in progress
> 
> [snip]  
> Any other ideas for elegance?

I usually do:

class A  
[‘Hidden’, ‘Available’, ‘Etc’].each do |s|  
const\_set(s, k = Object.new)  
def k.to\_s  
“A::#{s}”  
end  
k.freeze  
end  
end

Then you can say if obj.status == A::Available, etc.

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 2:58pm UTC](https://www.ruby-forum.com/t/enum/67576/4 "2006-09-05T14:58:22Z")

</div>

Paolo, so beautiful it makes me weep. Thanks a bunch 🙂

I ended up going for a redundant combo solution, in case I wanted to use  
more than one way:

class Project  
…  
statuses.each\_with\_index do |\_status, i|  
define\_method("#{\_status.to\_s}?") do  
self.status == i  
end  
end

```
def status_is(sym)
  statuses[self.status] == sym
end
...

```

end

…and using humanize for the form.

Logan: Thanks, but that won’t give me numerical values like I want (I  
want the indices stored in mysql, this is a rails app). I can see how to  
apply that to my case though.

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 3:06pm UTC](https://www.ruby-forum.com/t/enum/67576/5 "2006-09-05T15:06:00Z")

</div>

Hmm, which reminds me. Why don’t we get one of these with ruby?

module Enumerable  
def collect\_with\_index  
arr = []  
self.each\_with\_index do |a,i|  
arr \<\< yield(a,i)  
end  
arr  
end  
end

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 5, 2006, 3:42pm UTC](https://www.ruby-forum.com/t/enum/67576/6 "2006-09-05T15:42:43Z")

</div>

On Sep 5, 2006, at 9:06 AM, Ohad L. wrote:

> end

We do:

require ‘enumerator’  
[‘a’, ‘b’, ‘c’].to\_enum(:each\_with\_index).map { |value, index|  
{ index =\> value } } #=\> [{0=\>‘a’}, {1=\>‘b’}, {2=\>‘c’}]

---

<div class="post-metadata">

**Author:** ![ohad](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/o/f04885/32.png) [@ohad](https://www.ruby-forum.com/u/ohad)\
**Post date:** [September 29, 2006, 4:02pm UTC](https://www.ruby-forum.com/t/enum/67576/7 "2006-09-29T16:02:25Z")

</div>

Use Struct.
