[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Ohad Lutzky

9/5/2006 9:24:00 AM

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?


--
Posted via http://www.ruby-....

6 Answers

Paolo Negri

9/5/2006 12:04:00 PM

0

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

On 05/09/06, Ohad Lutzky <lutzky@gmail.com> wrote:
> 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?
>
>
> --
> Posted via http://www.ruby-....
>
>

Logan Capaldo

9/5/2006 12:50:00 PM

0


On Sep 5, 2006, at 5:24 AM, Ohad Lutzky wrote:

> 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
>
> [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.


>
> --
> Posted via http://www.ruby-....
>


Ohad Lutzky

9/5/2006 12:58:00 PM

0

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.

--
Posted via http://www.ruby-....

Ohad Lutzky

9/5/2006 1:06:00 PM

0

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

--
Posted via http://www.ruby-....

Logan Capaldo

9/5/2006 1:42:00 PM

0


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

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

We do:

require 'enumerator'
['a', 'b', 'c'].to_enum(:each_with_index).map { |value, index|
{ index => value } } #=> [{0=>'a'}, {1=>'b'}, {2=>'c'}]

> --
> Posted via http://www.ruby-....
>


Matthew Harris

9/29/2006 2:01:00 PM

0

Use Struct.

On 9/5/06, Ohad Lutzky <lutzky@gmail.com> wrote:
> 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?
>
>
> --
> Posted via http://www.ruby-....
>
>


--
Matt