Class: IS::Enum

Inherits:
Object
  • Object
show all
Extended by:
Enumerable
Includes:
Comparable
Defined in:
lib/is-enum.rb,
lib/is-enum/info.rb

Overview

Note:

Thread safety

Enum definition (Enum.define) and finalization (Enum.finalize!) are thread-safe. Lookup operations are thread-safe after definition.

Note:

Class variables

Uses class variables ( @@enums, @@mutex ) shared across inheritance hierarchy. All enum classes register in global @@enums for Enum.parse.

Note:

Custom attributes

Additional attributes passed to Enum.define are stored in ‘@attrs`. Subclasses may access this hash directly to implement custom properties.

class Status < IS::Enum
  define :error, 1, http_code: 500, retryable: false

  def http_code
    @attrs[:http_code]
  end

  def retryable?
    @attrs[:retryable]
  end
end

Defined Under Namespace

Modules: Info

Instance Attribute Summary collapse

Conversion collapse

Collection collapse

Ordering collapse

Instance Attribute Details

#descriptionString? (readonly)

Returns optional value description.

Returns:

  • (String, nil)

    optional value description



298
299
300
# File 'lib/is-enum.rb', line 298

def description
  @description
end

#nameSymbol (readonly)

Returns value name.

Returns:

  • (Symbol)

    value name



295
296
297
# File 'lib/is-enum.rb', line 295

def name
  @name
end

#order_noInteger (readonly)

Note:

Non-unique order numbers Multiple values may be defined with the same order_no. This affects sorting order (undefined when equal) and comparison behavior. See #<=> for comparison semantics.

Order No for sorting and comparison

Returns:

  • (Integer)


292
293
294
# File 'lib/is-enum.rb', line 292

def order_no
  @order_no
end

Class Method Details

.[](name_or_order) ⇒ IS::Enum?

Lookup by name or order number. Returns nil if not found. See of for strict lookup that raises on missing value

Parameters:

  • name_or_order (String, Symbol, Integer)

Returns:



117
118
119
120
121
122
123
124
125
126
127
# File 'lib/is-enum.rb', line 117

def [](name_or_order)
  case name_or_order
  when String, Symbol
    key = name_or_order.to_sym
    @values[key] || @aliases[key]
  when Integer
    @values.values.find { |v| v.order_no == name_or_order }
  else
    raise ArgumentError, "Invalid value for name or order_no: #{name_or_order.inspect}", caller_locations
  end
end

.aliasesHash<Symbol, IS::Enum>

Returns hash of alias names to target values.

Returns:

  • (Hash<Symbol, IS::Enum>)

    hash of alias names to target values



142
143
144
# File 'lib/is-enum.rb', line 142

def aliases
  @aliases
end

.eachEnumerator, self

Returns:

  • (Enumerator, self)


130
131
132
133
134
# File 'lib/is-enum.rb', line 130

def each
  return to_enum(__method__) unless block_given?
  values.each { |v| yield v }
  self
end

.firstIS::Enum?

Returns first value by order_no, or nil if empty.

Returns:

  • (IS::Enum, nil)

    first value by order_no, or nil if empty



152
153
154
# File 'lib/is-enum.rb', line 152

def first
  values.first
end

.from(value) ⇒ IS::Enum, ...

Converts various types to enum values.

Examples:

Convert range

MyEnum.from(:alpha..:gamma)  # => range of enum values

Convert array

MyEnum.from([:alpha, :beta]) # => [MyEnum.alpha, MyEnum.beta]

Parameters:

  • value (IS::Enum, nil, Range, Set, Enumerable, Symbol, String, Integer)

Returns:



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/is-enum.rb', line 89

def from value
  case value
  when nil
    nil
  when self
    value
  when Range
    Range::new from(value.begin), from(value.end), value.exclude_end?
  when Set
    Set[*value.map { |v| from(v) }]
  when Enumerable
    value.map { |v| from(v) }
  else
    result = self[value] 
    raise ArgumentError, "Invalid value of #{ self }: #{ value.inspect }", caller_locations unless result
    result
  end
end

.lastIS::Enum?

Returns last value by order_no, or nil if empty.

Returns:

  • (IS::Enum, nil)

    last value by order_no, or nil if empty



147
148
149
# File 'lib/is-enum.rb', line 147

def last
  values.last
end

.of(name) ⇒ IS::Enum

Strict lookup by name. Raises if not found. See [] for lenient lookup

Parameters:

  • name (Symbol)

Returns:

Raises:

  • (ArgumentError)

    if name is not a Symbol or value not found



74
75
76
77
78
79
# File 'lib/is-enum.rb', line 74

def of name
  raise ArgumentError, "Invalid name of #{ self }: #{ name.inspect }" unless name.is_a?(Symbol)
  val = @values[name] || @aliases[name]
  raise ArgumentError, "Invalid name of #{ self }: #{ name }" unless val
  return val
end

.parse(source) ⇒ IS::Enum

Note:

Security consideration Converts strings to Symbols internally. Do not use with untrusted user input to avoid memory exhaustion from symbol creation.

In specific enum class: get enum value by name; in IS::Enum itself: parse string like “Class.name” to enum value.

Parameters:

  • source (String)

    the string to parse

Returns:

Raises:

  • (ArgumentError)

    if source is not a String or value not found



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/is-enum.rb', line 51

def parse source
  raise ArgumentError, "Invalid source for parsing: #{ source.inspect }", caller_locations unless source.is_a?(String)
  if self == IS::Enum
    parts = source.split '.'
    raise ArgumentError, "Parsing error from #{ source.inspect }", caller_locations unless parts.is_a?(Array) && parts.size == 2
    cls = @@enums[parts[0]]
    raise ArgumentError, "Enum class not found: #{ parts[0] }", caller_locations unless cls
    val = cls[parts[1].to_sym]
    raise ArgumentError, "#{ cls.name } value not found: #{ parts[1] }", caller_locations unless val
    return val
  else
    val = self[source.to_sym]
    raise ArgumentError, "#{ self.name } value not found: #{ source }", caller_locations unless val
    return val
  end
end

.to_a(range = nil) ⇒ Array<IS::Enum>

Parameters:

  • range (Range) (defaults to: nil)

Returns:

Raises:

  • (ArgumentError)


170
171
172
173
174
# File 'lib/is-enum.rb', line 170

def to_a range = nil
  return values unless range
  raise ArgumentError, "Invalid 'range' argument: #{ range.inspect }", caller_locations unless range.is_a?(Range)
  values.select { |item| (range.begin.nil? || item >= range.begin) && (range.end.nil? || item < range.end || (!range.exclude_end? && item == range.end)) }
end

.to_hHash<Symbol => IS::Enum>

Note:

Both canonical names and aliases are included. To distinguish, check aliases for alias keys.

Returns hash of all names and aliases.

Returns:

  • (Hash<Symbol => IS::Enum>)

    hash of all names and aliases



164
165
166
# File 'lib/is-enum.rb', line 164

def to_h
  @values.merge(@aliases)
end

.to_rangeRange<IS::Enum>

Returns range from first to last value.

Returns:

  • (Range<IS::Enum>)

    range from first to last value



157
158
159
# File 'lib/is-enum.rb', line 157

def to_range
  (first .. last)
end

.valuesArray<IS::Enum>

Returns:



137
138
139
# File 'lib/is-enum.rb', line 137

def values
  @sorted ||= @values.values.sort_by { |v| v.order_no }
end

Instance Method Details

#<=>(other) ⇒ Integer?

Note:

Comparison semantics ‘==` and `<=>` compare by order_no, while eql? compares object identity. Multiple values may share the same order_no; they compare as equal but are distinct objects.

class Alpha < IS::Enum
  define :alpha, 10
  define :beta, 20
  define :bi, 20
  define :Gamma, 30
  define :g_letter, alias: :Gamma
end
Alpha.beta == Alpha.bi           # => true (same order_no: 20)
Alpha.beta.eql?(Alpha.bi)        # => false (different objects)
Alpha.Gamma.eql?(Alpha.g_letter) # => true (alias is same object)

Returns 1 if self > other; 0 if self == other; -1 if self < other. nil if other is not same type.

Returns:

  • (Integer, nil)

See Also:

  • Comparable


329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/is-enum.rb', line 329

def <=> other
  case other
  when self.class
    self.order_no <=> other.order_no
  when Symbol, String
    self.order_no <=> self.class[other.to_sym]&.order_no
  when Integer
    self.order_no <=> other
  else
    nil
  end
end

#inspectString

Returns detailed inspection string with class, name, order_no and attributes.

Returns:

  • (String)

    detailed inspection string with class, name, order_no and attributes



364
365
366
367
368
369
370
371
# File 'lib/is-enum.rb', line 364

def inspect
  data = [ "#{ self.class }.#{ self.name }", "order_no=#{ @order_no }" ]
  data << "description=#{ @description.inspect }" if @description
  @attrs.each do |key, value|
    data << "#{ key }=#{ value.inspect }"
  end
  "[enum #{ data.join(' ') }]"
end

#succIS::Enum?

Returns the next value by order_no, or nil if last.

Returns:



345
346
347
# File 'lib/is-enum.rb', line 345

def succ
  self.class.values.find { |v| v.order_no > self.order_no }
end

#to_sString

Returns name as string.

Returns:

  • (String)

    name as string



359
360
361
# File 'lib/is-enum.rb', line 359

def to_s
  name.to_s
end

#to_symSymbol

Returns name as symbol.

Returns:

  • (Symbol)

    name as symbol



354
355
356
# File 'lib/is-enum.rb', line 354

def to_sym
  name
end