I'd like to have a set of constants for a class, where their values need to be unique, and preferably compact. For instance: SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; SB_MAX = SB_LOGIC_ERR
but if I want to modify this list by adding something in the middle, then I have to remember to increment (by hand) all the values which come after that new value.
In C, I would do something like: typedef enum { SB_NONE, SB_GOOD, SB_BAD, SB_LOGICERR } sb_set;
Looking through the pickaxe book, it looks like the closest thing I can do is to create an array of words, and then use the indexes of where those words are in the array. But that isn't really the same thing. I'd like the efficiency of having constant values, which would be referred to by name.
(And after I have that for a compact set of values, I'd want a similar feature which would give me a bit-wise unique set of values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; SB_MODD = 8; -- such that I could combine the values together using '|', and tell which values were 'or'-ed together to get that combined value...)
-- Garance Alistair Drosehn = dros...@gmail.com Senior Systems Programmer or g...@FreeBSD.org Rensselaer Polytechnic Institute; Troy, NY; USA
Garance A Drosehn wrote: > I'd like to have a set of constants for a class, where their values > need to be unique, and preferably compact. For instance: > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > SB_MAX = SB_LOGIC_ERR
> but if I want to modify this list by adding something in the middle, > then I have to remember to increment (by hand) all the values > which come after that new value.
> In C, I would do something like: > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > SB_LOGICERR } sb_set;
> Looking through the pickaxe book, it looks like the closest thing > I can do is to create an array of words, and then use the indexes > of where those words are in the array. But that isn't really the > same thing. I'd like the efficiency of having constant values, > which would be referred to by name.
> (And after I have that for a compact set of values, I'd want a > similar feature which would give me a bit-wise unique set of > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > SB_MODD = 8; -- such that I could combine the values together > using '|', and tell which values were 'or'-ed together to get that > combined value...)
Use symbols. They are similar to strings, but every use of the same symbol uses the same value, and they are very compact.
state = :none state = :good if all_is_well # ... state = :logic_error
Jim -- Jim Menard, j...@io.com, http://www.io.com/~jimm "A language that doesn't affect the way you think about programming, is not worth knowing." -- Alan J. Perlis
>> I'd like to have a set of constants for a class, where their values >> need to be unique, and preferably compact. For instance: >> SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; >> SB_MAX = SB_LOGIC_ERR
>> but if I want to modify this list by adding something in the middle, >> then I have to remember to increment (by hand) all the values >> which come after that new value.
>> In C, I would do something like: >> typedef enum { SB_NONE, SB_GOOD, SB_BAD, >> SB_LOGICERR } sb_set;
>> Looking through the pickaxe book, it looks like the closest thing >> I can do is to create an array of words, and then use the indexes >> of where those words are in the array. But that isn't really the >> same thing. I'd like the efficiency of having constant values, >> which would be referred to by name.
>> (And after I have that for a compact set of values, I'd want a >> similar feature which would give me a bit-wise unique set of >> values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; >> SB_MODD = 8; -- such that I could combine the values together >> using '|', and tell which values were 'or'-ed together to get that >> combined value...)
> Use symbols. They are similar to strings, but every use of the same > symbol uses the same value, and they are very compact.
> state = :none > state = :good if all_is_well > # ... > state = :logic_error
> I'd like to have a set of constants for a class, where their values > need to be unique, and preferably compact. For instance: > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > SB_MAX = SB_LOGIC_ERR
> but if I want to modify this list by adding something in the middle, > then I have to remember to increment (by hand) all the values > which come after that new value.
> In C, I would do something like: > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > SB_LOGICERR } sb_set;
> Looking through the pickaxe book, it looks like the closest thing > I can do is to create an array of words, and then use the indexes > of where those words are in the array. But that isn't really the > same thing. I'd like the efficiency of having constant values, > which would be referred to by name.
> (And after I have that for a compact set of values, I'd want a > similar feature which would give me a bit-wise unique set of > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > SB_MODD = 8; -- such that I could combine the values together > using '|', and tell which values were 'or'-ed together to get that > combined value...)
> -- > Garance Alistair Drosehn = dros...@gmail.com > Senior Systems Programmer or g...@FreeBSD.org > Rensselaer Polytechnic Institute; Troy, NY; USA
Pit Capitain wrote: > Jim Menard schrieb: >>Use symbols. They are similar to strings, but every use of the same >>symbol uses the same value, and they are very compact.
I'm not sure I understand why you suggest the use of Set. Am I missing an advantage over the user of symbols?
The original poster was looking for the Ruby equivalent of C's enums, which are essentially a group of named constants. A Set---as implemented in Set.rb---contains a Hash whose keys are the elements of the set. Though this would work as intended, it is more work and overhead than necessary. The OP wanted something that was "preferably compact".
Jim -- Jim Menard, j...@io.com, http://www.io.com/~jimm "A language that doesn't affect the way you think about programming, is not worth knowing." -- Alan J. Perlis
On Wed, 3 Aug 2005, Garance A Drosehn wrote: > I'd like to have a set of constants for a class, where their values > need to be unique, and preferably compact. For instance: > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > SB_MAX = SB_LOGIC_ERR
> but if I want to modify this list by adding something in the middle, > then I have to remember to increment (by hand) all the values > which come after that new value.
> In C, I would do something like: > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > SB_LOGICERR } sb_set;
> Looking through the pickaxe book, it looks like the closest thing > I can do is to create an array of words, and then use the indexes > of where those words are in the array. But that isn't really the > same thing. I'd like the efficiency of having constant values, > which would be referred to by name.
> (And after I have that for a compact set of values, I'd want a > similar feature which would give me a bit-wise unique set of > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > SB_MODD = 8; -- such that I could combine the values together > using '|', and tell which values were 'or'-ed together to get that > combined value...)
> -- > Garance Alistair Drosehn = dros...@gmail.com > Senior Systems Programmer or g...@FreeBSD.org > Rensselaer Polytechnic Institute; Troy, NY; USA
class methods are your friend
harp:~ > cat a.rb module Enum def self::included other other.module_eval do def self::enum(*list) list.flatten.each_with_index{|e, i| const_set e.to_s.intern, i} end def self::bit_enum(*list) list.flatten.each_with_index{|e, i| const_set e.to_s.intern, 2 ** i} end end end end
-a -- =========================================================================== ==== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso =========================================================================== ====
> I'd like to have a set of constants for a class, where their values > need to be unique, and preferably compact. For instance: > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > SB_MAX = SB_LOGIC_ERR
> but if I want to modify this list by adding something in the middle, > then I have to remember to increment (by hand) all the values > which come after that new value.
> In C, I would do something like: > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > SB_LOGICERR } sb_set;
> Looking through the pickaxe book, it looks like the closest thing > I can do is to create an array of words, and then use the indexes > of where those words are in the array. But that isn't really the > same thing. I'd like the efficiency of having constant values, > which would be referred to by name.
> (And after I have that for a compact set of values, I'd want a > similar feature which would give me a bit-wise unique set of > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > SB_MODD = 8; -- such that I could combine the values together > using '|', and tell which values were 'or'-ed together to get that > combined value...)
> -- > Garance Alistair Drosehn = dros...@gmail.com > Senior Systems Programmer or g...@FreeBSD.org > Rensselaer Polytechnic Institute; Troy, NY; USA
Metaprogramming is your friend:
bschroed@black:~/svn/projekte/ruby-things$ cat enum.rb class Object def self.enums(*args) args.flatten.each_with_index do | const, i | class_eval %(#{const} = #{i}) end end
def self.bitwise_enums(*args) args.flatten.each_with_index do | const, i | class_eval %(#{const} = #{2**i}) end end end
class Foo enums %w(FOO BAR BAZ) bitwise_enums %w(ONE TWO FOUR EIGHT) end
p [Foo::FOO, Foo::BAR, Foo::BAZ] p [Foo::ONE, Foo::TWO, Foo::FOUR, Foo::EIGHT] bschroed@black:~/svn/projekte/ruby-things$ ruby enum.rb [0, 1, 2] [1, 2, 4, 8]
Oops I had not read your whole message. To handle the binary one, I think you would need to drop into some real code:
module Kernel
def enum(*syms) index = 0 puts self puts self.send(:binding) syms.each do |sym| eval "#{sym.to_s} = #{index}" index += 1 end end
def binary_enum(*syms) index = 1 syms.each do |sym| eval "#{sym.to_s} = #{index}" index *= 2 end end
end
enum :A, :B, :C binary_enum :X, :Y, :Z
would work, but they will always be at the global context. In rite, will we get a way to get the caller's binding? That would be very nice to make this method more versatile.
pth
On 8/2/05, Patrick Hurley <phur...@gmail.com> wrote:
> If your range at the end "goes too far" there is no problem, but if it > comes up short then some of your constants will silently not be > initialized.
> On 8/2/05, Garance A Drosehn <dros...@gmail.com> wrote: > > I'd like to have a set of constants for a class, where their values > > need to be unique, and preferably compact. For instance: > > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > > SB_MAX = SB_LOGIC_ERR
> > but if I want to modify this list by adding something in the middle, > > then I have to remember to increment (by hand) all the values > > which come after that new value.
> > In C, I would do something like: > > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > > SB_LOGICERR } sb_set;
> > Looking through the pickaxe book, it looks like the closest thing > > I can do is to create an array of words, and then use the indexes > > of where those words are in the array. But that isn't really the > > same thing. I'd like the efficiency of having constant values, > > which would be referred to by name.
> > (And after I have that for a compact set of values, I'd want a > > similar feature which would give me a bit-wise unique set of > > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > > SB_MODD = 8; -- such that I could combine the values together > > using '|', and tell which values were 'or'-ed together to get that > > combined value...)
> > -- > > Garance Alistair Drosehn = dros...@gmail.com > > Senior Systems Programmer or g...@FreeBSD.org > > Rensselaer Polytechnic Institute; Troy, NY; USA
> Oops I had not read your whole message. To handle the binary one, I > think you would need to drop into some real code:
> module Kernel
> def enum(*syms) > index = 0 > puts self > puts self.send(:binding) > syms.each do |sym| > eval "#{sym.to_s} = #{index}" > index += 1 > end > end
> def binary_enum(*syms) > index = 1 > syms.each do |sym| > eval "#{sym.to_s} = #{index}" > index *= 2 > end > end
> end
> enum :A, :B, :C > binary_enum :X, :Y, :Z
> would work, but they will always be at the global context. In rite, > will we get a way to get the caller's binding? That would be very nice > to make this method more versatile.
> pth
> On 8/2/05, Patrick Hurley <phur...@gmail.com> wrote: > > Not quite perfect, but not too bad you can:
> > SB_MODA, SB_MODB, SB_MODC = *0..2
> > If your range at the end "goes too far" there is no problem, but if it > > comes up short then some of your constants will silently not be > > initialized.
> > On 8/2/05, Garance A Drosehn <dros...@gmail.com> wrote: > > > I'd like to have a set of constants for a class, where their values > > > need to be unique, and preferably compact. For instance: > > > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > > > SB_MAX = SB_LOGIC_ERR
> > > but if I want to modify this list by adding something in the middle, > > > then I have to remember to increment (by hand) all the values > > > which come after that new value.
> > > In C, I would do something like: > > > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > > > SB_LOGICERR } sb_set;
> > > Looking through the pickaxe book, it looks like the closest thing > > > I can do is to create an array of words, and then use the indexes > > > of where those words are in the array. But that isn't really the > > > same thing. I'd like the efficiency of having constant values, > > > which would be referred to by name.
> > > (And after I have that for a compact set of values, I'd want a > > > similar feature which would give me a bit-wise unique set of > > > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > > > SB_MODD = 8; -- such that I could combine the values together > > > using '|', and tell which values were 'or'-ed together to get that > > > combined value...)
> > > -- > > > Garance Alistair Drosehn = dros...@gmail.com > > > Senior Systems Programmer or g...@FreeBSD.org > > > Rensselaer Polytechnic Institute; Troy, NY; USA
> I'd like to have a set of constants for a class, where their values > need to be unique, and preferably compact. For instance: > SB_NONE = 0; SB_GOOD = 1; SB_BAD = 2; SB_LOGIC_ERR = 3; > SB_MAX = SB_LOGIC_ERR
> but if I want to modify this list by adding something in the middle, > then I have to remember to increment (by hand) all the values > which come after that new value.
> In C, I would do something like: > typedef enum { SB_NONE, SB_GOOD, SB_BAD, > SB_LOGICERR } sb_set;
> Looking through the pickaxe book, it looks like the closest thing > I can do is to create an array of words, and then use the indexes > of where those words are in the array. But that isn't really the > same thing. I'd like the efficiency of having constant values, > which would be referred to by name.
> (And after I have that for a compact set of values, I'd want a > similar feature which would give me a bit-wise unique set of > values. Eg: SB_MODA = 1; SB_MODB = 2; SB_MODC = 4; > SB_MODD = 8; -- such that I could combine the values together > using '|', and tell which values were 'or'-ed together to get that > combined value...)
> -- > Garance Alistair Drosehn = dros...@gmail.com > Senior Systems Programmer or g...@FreeBSD.org > Rensselaer Polytechnic Institute; Troy, NY; USA
>>> Use symbols. They are similar to strings, but every use of the same >>> symbol uses the same value, and they are very compact.
>>> state = :none >>> state = :good if all_is_well >>> # ... >>> state = :logic_error
>> ... and for a set of values use the class Set.
> I'm not sure I understand why you suggest the use of Set. Am I missing > an advantage over the user of symbols?
I'm sorry that you didn't understand me. I also think that having numbers behind the names isn't necessary at all and maybe even misleading, so I also would suggest to use symbols.
But if you read the original message, Garance wanted to be able to build sets of his constants and combine the sets with an "or" operator. For this I suggested use sets (of symbols).
Pit Capitain wrote: > But if you read the original message, Garance wanted to be able to build > sets of his constants and combine the sets with an "or" operator. For > this I suggested use sets (of symbols).
That makes perfect sense. Thank you.
Jim -- Jim Menard, j...@io.com, http://www.io.com/~jimm "A language that doesn't affect the way you think about programming, is not worth knowing." -- Alan J. Perlis
On 8/2/05, Ara.T.Howard <Ara.T.How...@noaa.gov> wrote:
> On Wed, 3 Aug 2005, Garance A Drosehn wrote: > > I'd like to have a set of constants for a class, where their values > > need to be unique, and preferably compact. For instance: > class methods are your friend
> snip nice Enum module
I like the Enum module, but if I include it into the 'main' scope, I need to
self.class.enum to make it work. A bit more brute force, but works "automatically" in all contexts would be overloading Object. This then requires a smarter method of setting the const based upon where it is called from.
class Object
def const_setter set = if self.respond_to? :const_set lambda { |sym, val| self.const_set sym.to_s.intern, val } elsif self.class.respond_to? :const_set lambda { |sym, val| self.class.const_set sym.to_s.intern, val } else # I don't think this code would ever get called... lambda { |sym, val| eval "#{sym} = #{val}" } end end
def enum(*syms) set = const_setter syms.each_with_index do |sym,index| set.call sym, index end end
def binary_enum(*syms) set = const_setter syms.each_with_index do |sym,index| set.call sym, 2 ** index end end
On Wed, 3 Aug 2005, Patrick Hurley wrote: > On 8/2/05, Ara.T.Howard <Ara.T.How...@noaa.gov> wrote: >> On Wed, 3 Aug 2005, Garance A Drosehn wrote: >>> I'd like to have a set of constants for a class, where their values >>> need to be unique, and preferably compact. For instance: >> class methods are your friend
>> snip nice Enum module
> I like the Enum module, but if I include it into the 'main' scope, I need to
> self.class.enum to make it work. A bit more brute force, but works > "automatically" in all contexts would be overloading Object. This then > requires a smarter method of setting the const based upon where it is > called from.
> class Object
> def const_setter > set = if self.respond_to? :const_set > lambda { |sym, val| self.const_set sym.to_s.intern, val } > elsif self.class.respond_to? :const_set > lambda { |sym, val| self.class.const_set sym.to_s.intern, val } > else > # I don't think this code would ever get called... > lambda { |sym, val| eval "#{sym} = #{val}" } > end > end
> def enum(*syms) > set = const_setter > syms.each_with_index do |sym,index| > set.call sym, index > end > end
> def binary_enum(*syms) > set = const_setter > syms.each_with_index do |sym,index| > set.call sym, 2 ** index > end > end
> end
hmm. this is a bit shorter
harp:~ > cat a.rb class Object def enum(*list) mc = Module === self ? self : self.class list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, i} end def bit_enum(*list) mc = Module === self ? self : self.class list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, 2 ** i} end end
class C enum %w( FOO BAR FOOBAR BARFOO ) end
class B bit_enum %w( FOO BAR FOOBAR BARFOO ) end
enum %w( FOO BAR )
bit_enum %w( FOOBAR BARFOO )
p C::FOO p C::BARFOO printf "0b%8.8b\n", B::FOO printf "0b%8.8b\n", B::BARFOO
p FOO p BAR printf "0b%8.8b\n", FOOBAR printf "0b%8.8b\n", BARFOO
probably could also combine this idea with the Enum module...
nice mod btw.
-a -- =========================================================================== ==== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso =========================================================================== ====
harp:~ > cat a.rb def try begin yield rescue => e STDERR.puts "#{ e.message } (#{ e.class })" end end
class Object def enum(*list) mc = self list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, i} end def bit_enum(*list) mc = self list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, 2 ** i} end end
try do enum %w( FOO BAR ) p FOO end
class Object def enum(*list) mc = Module === self ? self : self.class list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, i} end def bit_enum(*list) mc = Module === self ? self : self.class list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, 2 ** i} end end
the 'mc = self.class' is when 'self == main'. maybe i misunderstood?
regards.
-a -- =========================================================================== ==== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso =========================================================================== ====
On 8/2/05, Ara.T.Howard <Ara.T.How...@noaa.gov> wrote:
> hmm. this is a bit shorter > class Object > def enum(*list) > mc = Module === self ? self : self.class > list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, i} > end > def bit_enum(*list) > mc = Module === self ? self : self.class > list.flatten.each_with_index{|e, i| mc.const_set e.to_s.intern, 2 ** i} > end > end
I changed the method names to enum_constants and enum_bit_constants.
> probably could also combine this idea with the Enum module...
I wasn't sure what you meant by this. I tried changing the above to be 'class Enum", and then have the method names be "Enum.constants" and "Enum.bit_constants", but that didn't seem to work. I checked Pickaxe 2, RAA, and RubyForge for an Enum module, but didn't come up with anything. Then again, this is the first time I tried searching RAA or RubyForge for some module, so I'm probably doing it wrong...
-- Garance Alistair Drosehn = dros...@gmail.com Senior Systems Programmer or g...@FreeBSD.org Rensselaer Polytechnic Institute; Troy, NY; USA