Enum in ruby?

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

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 + " = " + (i
+ 1).to_s }

···

On 5/2/05, Andreas Habel <mail@exceptionfault.de> wrote:

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

--
Bill Atkins

Andreas Habel wrote:

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

···

--
Mark Sparshatt

Andreas Habel wrote:

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?

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

···

On Mon, 2 May 2005, Andreas Habel wrote:

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

--

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

===============================================================================

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

···

On 5/2/05, Andreas Habel <mail@exceptionfault.de> wrote:

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?

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

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

mark sparshatt wrote:

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

--
Mark Sparshatt

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

Andreas

Andreas Schwarz wrote:

Andreas Habel wrote:

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?

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 ?

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

const_def_test.rb (3.56 KB)

const_def.rb (395 Bytes)

···

--
Jannis Harder

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

···

Le 2/5/2005, "Andreas Habel" <mail@exceptionfault.de> a écrit:

Andreas Schwarz wrote:

Andreas Habel wrote:

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?

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 ?

--
template<typename duck>
void quack(duck& d) { d.quack(); }

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

···

On 5/2/05, Andreas Habel <mail@exceptionfault.de> wrote:

Andreas Schwarz wrote:
> Andreas Habel wrote:
>
>> 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?

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 ?

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

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

···

Le 2/5/2005, "Andreas Habel" <mail@exceptionfault.de> a écrit:

--
template<typename duck>
void quack(duck& d) { d.quack(); }

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

···

On 5/2/05, Andreas Habel <mail@exceptionfault.de> wrote:

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