enum in ruby ?

A

Andreas Habel

Hi,

I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?

Maybe something short like the 'attr_accessor' syntax would be great!

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def :CONST_B1, :CONST_B2, :CONST_B3
end

eq.

class MyClass

CONST_A1 = 1
CONST_A2 = 2
CONST_A3 = 3

CONST_B1 = 1
CONST_B2 = 2
CONST_B3 = 3
end

Thanks,
Andreas
 
B

Bill Atkins

------=_Part_8642_26450347.1115055939005
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Don't know if there's anything built-in, but you can try (untested):

[:CONST_1, :CONST_2].each_with_index { |name, i| eval name.to_s + " =3D " +=
(i=20
+ 1).to_s }

=20
Hi,
=20
I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?
=20
Maybe something short like the 'attr_accessor' syntax would be great!
=20
class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def :CONST_B1, :CONST_B2, :CONST_B3
end
=20
eq.
=20
class MyClass
=20
CONST_A1 =3D 1
CONST_A2 =3D 2
CONST_A3 =3D 3
=20
CONST_B1 =3D 1
CONST_B2 =3D 2
CONST_B3 =3D 3
end
=20
Thanks,
Andreas
=20
=20


--=20
Bill Atkins

------=_Part_8642_26450347.1115055939005--
 
A

Ara.T.Howard

Hi,

I`ve a simple question about constants in ruby. Is there a possibility to
define constants in a module or a class like a enum in c?

Maybe something short like the 'attr_accessor' syntax would be great!

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def :CONST_B1, :CONST_B2, :CONST_B3
end

eq.

class MyClass

CONST_A1 = 1
CONST_A2 = 2
CONST_A3 = 3

CONST_B1 = 1
CONST_B2 = 2
CONST_B3 = 3
end

harp:~ > cat a.rb
class MyClass
CONSTANTS = [
CONST_A1 = 1,
CONST_A2 = 2,
CONST_A3 = 3,
CONST_B1 = 1,
CONST_B2 = 2,
CONST_B3 = 3,
]
end

p MyClass::CONST_A1
p MyClass::CONST_B2

# OR

class Module
def enumerate(*list)
[ list ].flatten.each_with_index{|c,i| const_set "#{ c }".upcase, i + 1}
end
end

class MyClass2
enumerate :CONST_A1, :CONST_A2, :CONST_A3
enumerate %w( CONST_B1 CONST_B2 CONST_B3 )
end

p MyClass2::CONST_A1
p MyClass2::CONST_B2

harp:~ > ruby a.rb
1
2
1
2

HTH.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================
 
M

mark sparshatt

Andreas said:
Hi,

I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?

Maybe something short like the 'attr_accessor' syntax would be great!

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def :CONST_B1, :CONST_B2, :CONST_B3
end

eq.

class MyClass

CONST_A1 = 1
CONST_A2 = 2
CONST_A3 = 3

CONST_B1 = 1
CONST_B2 = 2
CONST_B3 = 3
end

The following is a simple implementation of what you want


class Class
def const_def(*symbols)
symbols.each_with_index do |symbol, index|
const_set(symbol, index + 1)
end
end
end

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3

p CONST_A1, CONST_A2, CONST_A3
end

#=>
1
2
3


HTH
 
A

Andreas Schwarz

Andreas said:
Hi,

I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?

Maybe something short like the 'attr_accessor' syntax would be great!

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def :CONST_B1, :CONST_B2, :CONST_B3
end

What do you need constants for; why not directly use symbols?
 
A

Andreas Habel

mark said:
The following is a simple implementation of what you want


class Class
def const_def(*symbols)
symbols.each_with_index do |symbol, index|
const_set(symbol, index + 1)
end
end
end

class MyClass
const_def :CONST_A1, :CONST_A2, :CONST_A3

p CONST_A1, CONST_A2, CONST_A3
end

#=>
1
2
3


HTH

Thanks to all for your fast answers! That`s perfect, const_set is the
miracle I searched for ;)

Andreas
 
A

Andreas Habel

Andreas said:
What do you need constants for; why not directly use symbols?

I have to synchronize a lot of constants in my code with "constants" in
a database which were generated using a sequence. With the enum function
I don`t have to matter which value the constant has in my database nor
in ruby. Only the order is important.

Or has someone a better suggestion for that ?
 
J

Jannis Harder

--------------010600040706040805070703
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

I've extended mark sparshatt's code and wrote an UnitTest.

const_def.rb is the code and const_def_test.rb the test

Examples:

class MyClass
const_def 4, :CONST_A1, :CONST_A2, :CONST_A3

p CONST_A1, CONST_A2, CONST_A3
end

#=>
4
5
6

class MyClassTwo
const_def "a",:CONST_A1, :CONST_A2, 7, :CONST_A3

p CONST_A1, CONST_A2, CONST_A3
end

#=>
"a"
"b"
7


--
Jannis Harder

--------------010600040706040805070703
Content-Type: text/plain; x-mac-type="2A2A2A2A"; x-mac-creator="48647261";
name="const_def_test.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="const_def_test.rb"

require 'const_def'
require 'test/unit'

class ConstDefTest < Test::Unit::TestCase
def test_integers
c = Class.new
c.instance_eval do
const_def :CONST_A1, :CONST_A2, :CONST_A3
const_def 10, :CONST_B1, :CONST_B2, :CONST_B3
const_def 10, :CONST_C1, 2, :CONST_C2, 1, :CONST_C3
end
assert_equal([c::CONST_A1,c::CONST_A2,c::CONST_A3],[1, 2 ,3 ])
assert_equal([c::CONST_B1,c::CONST_B2,c::CONST_B3],[10,11,12])
assert_equal([c::CONST_C1,c::CONST_C2,c::CONST_C3],[10,2 ,1 ])
end
def test_floats
c = Class.new
c.instance_eval do
const_def 1.5, :CONST_A1, :CONST_A2, :CONST_A3
const_def 2.5, :CONST_B1, 7.0, :CONST_B2, :CONST_B3
const_def 3.5, :CONST_C1, 2.5, :CONST_C2, 0.5, :CONST_C3
end
assert_equal([c::CONST_A1,c::CONST_A2,c::CONST_A3],[1.5, 2.5 ,3.5 ])
assert_equal([c::CONST_B1,c::CONST_B2,c::CONST_B3],[2.5, 7.0 ,8.0 ])
assert_equal([c::CONST_C1,c::CONST_C2,c::CONST_C3],[3.5, 2.5 ,0.5 ])
end
def test_strings
c = Class.new
c.instance_eval do
const_def "jix", :CONST_A1, :CONST_A2, :CONST_A3
const_def "ruby", :CONST_B1, "zzz", :CONST_B2, :CONST_B3
const_def "hello", :CONST_C1, "world", :CONST_C2, "!", :CONST_C3
end
assert_equal([c::CONST_A1,c::CONST_A2,c::CONST_A3],%w{jix jiy jiz})
assert_equal([c::CONST_B1,c::CONST_B2,c::CONST_B3],%w{ruby zzz aaaa})
assert_equal([c::CONST_C1,c::CONST_C2,c::CONST_C3],%w{hello world !})
end
def test_custom
c = Class.new
c.instance_eval do
const_def CustomClass.new(1,1), :CONST_A1,
:CONST_A2,
:CONST_A3

const_def CustomClass.new(3,1), :CONST_B1,
CustomClass.new("a","a"), :CONST_B2,
:CONST_B3

const_def CustomClass.new(1,2), :CONST_C1,
CustomClass.new(3,4), :CONST_C2,
CustomClass.new(5,6), :CONST_C3
end
assert_equal([c::CONST_A1,c::CONST_A2,c::CONST_A3],[
CustomClass.new(1,1),
CustomClass.new(1,3),
CustomClass.new(2,3)
])
assert_equal([c::CONST_B1,c::CONST_B2,c::CONST_B3],[
CustomClass.new(3,1),
CustomClass.new("a","a"),
CustomClass.new("a","c")
])
assert_equal([c::CONST_C1,c::CONST_C2,c::CONST_C3],[
CustomClass.new(1,2),
CustomClass.new(3,4),
CustomClass.new(5,6)
])
end
def test_mixed
c = Class.new
current_time = Time.new
c.instance_eval do
const_def 1, :CONST_A1, :CONST_A2, "hi",:CONST_A3
const_def current_time, :CONST_B1, 50, :CONST_B2, :CONST_B3
const_def 3.141, :CONST_C1, [1,2], :CONST_C2, "!", :CONST_C3
end
assert_equal([c::CONST_A1,c::CONST_A2,c::CONST_A3],[1, 2, "hi"])
assert_equal([c::CONST_B1,c::CONST_B2,c::CONST_B3],[current_time, 50, 51 ])
assert_equal([c::CONST_C1,c::CONST_C2,c::CONST_C3],[3.141, [1,2], "!" ])
end
class CustomClass
include Comparable
attr_accessor :a,:b
def initialize(a,b)
@a = a
@b = b
end
def succ
if @a < @b
CustomClass.new(@a.succ,@b)
else
CustomClass.new(@a,@b.succ.succ)
end
end
def <=> other
if (res = (@a <=> other.a)) == 0
@b <=> other.b
else
res
end
end
def inspect
"<#CC #{@a.inspect} #{@b.inspect}>"
end
end

end
--------------010600040706040805070703
Content-Type: text/plain; x-mac-type="2A2A2A2A"; x-mac-creator="48647261";
name="const_def.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="const_def.rb"


class Class
def const_def(*symbols)
val = 1
symbols.each_with_index do |symbol, index|
unless symbol.is_a? Symbol
val = symbol
else
const_set(symbol, val)
begin
if val.respond_to? :succ
val = val.succ
else
val+=1
end
rescue
val = nil
end
end
end
end
end


--------------010600040706040805070703--
 
M

Mark Hubbart

Hi,

I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?

Others have given good direct solutions... But I wonder why you would
want this? For most situations, symbols would be a cleaner solution:

MyClass.new(data, MyClass::CONST_A1, MyClass::CONST_B3)
vs.
MyClass.new(data, :a1, :b2)

They can also be used as flags:

MyClass.new(data, MyClass::CONST_A1 | MyClass::CONST_A2)
vs.
MyClass.new(data, :a1, :a2)

Constants are used in core classes like File and IO, but i think it's
mainly due to them being based on the underlying system calls, which
use C. ISTM that most rubysts prefer to use symbols for flags and
enumerated values.

HTH,
Mark
 
S

Saynatkari

Le 2/5/2005 said:
I have to synchronize a lot of constants in my code with "constants" in
a database which were generated using a sequence. With the enum function
I don`t have to matter which value the constant has in my database nor
in ruby. Only the order is important.

Or has someone a better suggestion for that ?

Hm. If these constants have no values that you care of in the
first place, then you could definitely use Symbols, which have
the exact behaviour you seem to be looking for (distinct but
meaningless values). The only situation where Symbols would not
work is if you had actual constant values (e.g. PI has to be 3.14~)
that needed to be stored.

Sure, this way works too (and produced some nice code;), but
it might not be necessary and perhaps counterintuitive to others?

E
 
M

Mark Hubbart

I have to synchronize a lot of constants in my code with "constants" in
a database which were generated using a sequence. With the enum function
I don`t have to matter which value the constant has in my database nor
in ruby. Only the order is important.

Or has someone a better suggestion for that ?

If you want to expose the enumerated values for use in the library,
then symbols are much more intuitive. It's worth a little effort
behind the scenes to make them available. Here's a quick
implementation for it:


class Class
def enumerate(*args)
@enumerations = {}
symbols.each_with_index do |sym, idx|
@enumerations[sym] = idx + 1
end
end

def enum_value(sym)
@enumerations[sym]
end
end

class MyClass
enumerate :a, :b, :c
enumerate :x, :y, :z
def foo( name, enum1, enum2 )
@database.fetch( name, enum_value(enum1), enum_value(enum2) )
end
end

MyClass.new.foo("test", :a, :y)


HTH,
Mark
 
A

Andreas Habel

Hi Mark,

I tried to implement your code and got very confused receiving the
following error.. What`s wrong ???

----

class Class

def enumerate(*symb)
@enumerations = {}
symb.each_with_index do |sym, idx|
@enumerations[sym] = idx + 1
end
end

def enum_val(sym)
@enumerations[sym]
end

end

class MyClass
enumerate :a, :b, :c
enumerate :x, :y, :z

def foo( enum1, enum2 )
p enum_val(enum1)
p enum_val(enum2)
end

end

p Class.public_method_defined?( 'enum_val' )
p MyClass.public_method_defined?( 'enum_val' )
p MyClass.new.foo( :a, :y)

===>

true
false
test.rb:21:in `foo': undefined method `enum_val' for
#<MyClass:0x2874d40> (NoMethodError)
from test.rb:29
 
S

Saynatkari

Le 2/5/2005 said:
Hi Mark,

I tried to implement your code and got very confused receiving the
following error.. What`s wrong ???

----

class Class

def enumerate(*symb)
@enumerations = {}
symb.each_with_index do |sym, idx|
@enumerations[sym] = idx + 1
end
end

def enum_val(sym)
@enumerations[sym]
end

end

class MyClass
enumerate :a, :b, :c
enumerate :x, :y, :z

def foo( enum1, enum2 )
p enum_val(enum1)
p enum_val(enum2)
end

end

enum_val is an instance method of Class; therefore, it should
be called as MyClass.enum_val (i.e. outside of an instance method).
p Class.public_method_defined?( 'enum_val' )
p MyClass.public_method_defined?( 'enum_val' )
p MyClass.new.foo( :a, :y)

===>

true
false
test.rb:21:in `foo': undefined method `enum_val' for
#<MyClass:0x2874d40> (NoMethodError)
from test.rb:29

That being said, I still think all this is overkill, depending
on what your application looks like. You can just use Symbols
on the fly:

MyClass.new.some_property = :some_discrete_value

E
 
B

Bertram Scharpf

Hi,

Am Dienstag, 03. Mai 2005, 02:34:31 +0900 schrieb Andreas Habel:
I`ve a simple question about constants in ruby. Is there a possibility
to define constants in a module or a class like a enum in c?

class MyClass

CONST_A1 = 1
CONST_A2 = 2
CONST_A3 = 3

CONST_B1 = 1
CONST_B2 = 2
CONST_B3 = 3
end

A, B, C = (1..3).to_a

Bertram
 
M

Mark Hubbart

Hi Mark,

I tried to implement your code and got very confused receiving the
following error.. What`s wrong ???

----

class Class

def enumerate(*symb)
@enumerations = {}
symb.each_with_index do |sym, idx|
@enumerations[sym] = idx + 1
end
end

def enum_val(sym)
@enumerations[sym]
end

end

class MyClass
enumerate :a, :b, :c
enumerate :x, :y, :z

def foo( enum1, enum2 )
p enum_val(enum1)
p enum_val(enum2)
end

end

p Class.public_method_defined?( 'enum_val' )
p MyClass.public_method_defined?( 'enum_val' )
p MyClass.new.foo( :a, :y)

===>

true
false
test.rb:21:in `foo': undefined method `enum_val' for
#<MyClass:0x2874d40> (NoMethodError)
from test.rb:29

:/ that's embarrassing. Obviously I didn't test the code before I sent
it, and there was a major logic error, regarding scope.

----8<----

class Class
def enumerate(*syms)
@enumerations ||= {}
enums = @enumerations
syms.each_with_index do |sym, idx|
enums[sym] = idx + 1
end
define_method:)enum_val) do |sym|
enums[sym]
end
end
end

class MyClass
enumerate :a, :b, :c
enumerate :x, :y, :z

def foo(enum1, enum2)
[enum_val(enum1), enum_val(enum2)]
end

end

p MyClass.new.foo:)a, :y)

----8<----

... prints "[1, 2]"

Sorry 'bout that. I should have caught the glaring error.

cheers,
Mark
 

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

Forum statistics

Threads
474,173
Messages
2,570,938
Members
47,473
Latest member
pioneertraining

Latest Threads

Top