Class: Safe::Enum

Inherits:
Object
  • Object
show all
Defined in:
lib/enums/enum.rb,
lib/enums/enum_builder.rb
more...

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, value) ⇒ Enum

Returns a new instance of Enum.

[View source]

12
13
14
15
16
17
# File 'lib/enums/enum.rb', line 12

def initialize( key, value )
  @key   = key
  @value = value
  self.freeze   ## make "immutable"
  self
end

Instance Attribute Details

#keyObject (readonly)

return a new Enum read-only class


9
10
11
# File 'lib/enums/enum.rb', line 9

def key
  @key
end

#valueObject (readonly)

Returns the value of attribute value.


10
11
12
# File 'lib/enums/enum.rb', line 10

def value
  @value
end

Class Method Details

._typecheck_enum!(o) ⇒ Object

[View source]

19
20
21
22
23
24
25
# File 'lib/enums/enum.rb', line 19

def self._typecheck_enum!( o )
  if o.instance_of?( self )
    o
  else
    raise TypeError.new( "[Enum] enum >#{name}< type expected; got >#{o.class.inspect}<" )
  end
end

.build_class(class_name, *args, **kwargs) ⇒ Object Also known as: new

meta-programming “macro” - build class (on the fly)

[View source]

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/enums/enum_builder.rb', line 10

def self.build_class( class_name, *args, **kwargs )

  if args.size > 0
    keys   = args
    values = (0...keys.size).to_a   # note: use ... (exclusive) range
    e = Hash[ keys.zip( values ) ]
  else
    ## assume kwargs
    e = kwargs
  end


  ## todo/fix:
  ##  check class name MUST start with uppercase letter

  ## check if all keys are symbols and follow the ruby id(entifier) naming rules
  e.keys.each do |key|
    if key.is_a?( Symbol ) && key =~ /\A[a-z][a-zA-Z0-9_]*\z/
    else
      raise ArgumentError.new( "[Enum] arguments to Enum.new must be all symbols following the ruby id naming rules; >#{key}< failed" )
    end
  end

  klass = Class.new( Enum )

  ## add self.new too - note: call/forward to "old" orginal self.new of Event (base) class
  klass.define_singleton_method( :new ) do |*new_args|
    old_new( *new_args )
  end

  e.each do |key,value|
    klass.class_eval( <<RUBY )
      #{key.upcase} = new( :#{key}, #{value} )

      def #{key}?
        self == #{key.upcase}
      end

      def self.#{key}
        #{key.upcase}
      end
RUBY
  end

  klass.class_eval( <<RUBY )
    def self.members
      @members ||= [#{e.keys.map {|key|key.upcase}.join(',')}].freeze
    end
RUBY

  ## note: use Kernel for "namespacing"
  ##   make all enums Kernel convenience converters (always) global
  ##     including uppercase methods (e.g. State(), Color(), etc.) does NOT work otherwise (with other module includes)

  ## add global convenience converter function
  ##  e.g. State(0) is same as State.convert(0)
  ##       Color(0) is same as Color.convert(0)
  Kernel.class_eval( <<RUBY )
    def #{class_name}( arg )
       #{class_name}.convert( arg )
    end
RUBY

  ## note: use Safe (module) and NO Object for namespacing
  ##   use include Safe to make all enums constants and machinery global
  Safe.const_set( class_name, klass )   ## returns klass (plus sets global constant class name)
end

.convert(arg) ⇒ Object

[View source]

82
83
84
85
86
87
88
# File 'lib/enums/enum.rb', line 82

def self.convert( arg )
  ## todo/check: support keys too - why? why not?
  ## e.g. Color(0), Color(1)
  ##      Color(:red), Color(:blue) - why? why not?
  ## note: will ALWAYS look-up by (member) index and NOT by value (integer number value might be different!!)
  members[ arg ]
end

.key(key) ⇒ Object Also known as: []

[View source]

47
48
49
50
51
52
# File 'lib/enums/enum.rb', line 47

def self.key( key )
  ## note: returns nil now for unknown keys
  ##   use/raise IndexError or something - why? why not?
  @hash_by_key ||= Hash[ keys.zip( members ) ].freeze
  @hash_by_key[key]
end

.keysObject

[View source]

42
43
44
45
# File 'lib/enums/enum.rb', line 42

def self.keys
  @keys ||= members.map {|member| member.key}.freeze
  @keys
end

.sizeObject Also known as: length

[View source]

77
# File 'lib/enums/enum.rb', line 77

def self.size() keys.size; end

.value(value) ⇒ Object

[View source]

65
66
67
68
69
70
# File 'lib/enums/enum.rb', line 65

def self.value( value )
  ## note: returns nil now for unknown values
  ##   use/raise IndexError or something - why? why not?
  @hash_by_value ||= Hash[ values.zip( members ) ].freeze
  @hash_by_value[value]
end

.valuesObject

[View source]

60
61
62
63
# File 'lib/enums/enum.rb', line 60

def self.values
  @values ||= members.map {|member| member.value}.freeze
  @values
end

.zeroObject

[View source]

73
# File 'lib/enums/enum.rb', line 73

def self.zero() members[0]; end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

[View source]

29
30
31
32
33
34
35
# File 'lib/enums/enum.rb', line 29

def ==( other )
  if other.is_a?( Integer ) && other == 0   ## note: only allow compare by zero (0) integer - why? why not?
    @value == 0
  else
    @value == _typecheck_enum!( other ).value
  end
end

#_typecheck_enum!(o) ⇒ Object

[View source]

26
# File 'lib/enums/enum.rb', line 26

def _typecheck_enum!( o ) self.class._typecheck_enum!( o ); end

#parse_boolObject Also known as: to_bool

nonzero == true, zero == false like numbers

[View source]

96
# File 'lib/enums/enum.rb', line 96

def parse_bool() @value != 0; end

#to_bObject

[View source]

95
# File 'lib/enums/enum.rb', line 95

def to_b()       parse_bool(); end

#to_iObject

add to_i, to_int - why? why not?

[View source]

92
# File 'lib/enums/enum.rb', line 92

def to_i()       @value; end

#to_intObject

allows Integer( .. )

[View source]

93
# File 'lib/enums/enum.rb', line 93

def to_int()     @value; end

#zero?Boolean

note: use compare by identity (object_id) and NOT value e.g. 0

Returns:

  • (Boolean)
[View source]

74
# File 'lib/enums/enum.rb', line 74

def zero?() self == self.class.zero; end