Class: Philiprehberger::Enum

Inherits:
Object
  • Object
show all
Extended by:
Enumerable
Includes:
Comparable
Defined in:
lib/philiprehberger/enum.rb,
lib/philiprehberger/enum/version.rb

Overview

Type-safe enumerations with ordinals, custom values, and pattern matching.

Subclass Enum and use the ‘member` class method to define members:

class Status < Philiprehberger::Enum
  member :draft
  member :published
  member :archived
end

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
'0.4.0'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, ordinal, value) ⇒ Enum

Returns a new instance of Enum.

Parameters:

  • name (Symbol)

    the member name

  • ordinal (Integer)

    the ordinal position

  • value (Object, nil)

    an optional custom value



34
35
36
37
38
39
# File 'lib/philiprehberger/enum.rb', line 34

def initialize(name, ordinal, value)
  @name = name
  @ordinal = ordinal
  @value = value
  freeze
end

Instance Attribute Details

#nameSymbol (readonly)

Returns the member name.

Returns:

  • (Symbol)

    the member name



23
24
25
# File 'lib/philiprehberger/enum.rb', line 23

def name
  @name
end

#ordinalInteger (readonly)

Returns the ordinal position (declaration order).

Returns:

  • (Integer)

    the ordinal position (declaration order)



26
27
28
# File 'lib/philiprehberger/enum.rb', line 26

def ordinal
  @ordinal
end

#valueObject? (readonly)

Returns the custom value, or nil if not set.

Returns:

  • (Object, nil)

    the custom value, or nil if not set



29
30
31
# File 'lib/philiprehberger/enum.rb', line 29

def value
  @value
end

Class Method Details

.each {|Enum| ... } ⇒ Enumerator

Yield each member in declaration order

Yields:

  • (Enum)

    each member

Returns:

  • (Enumerator)

    if no block given



84
85
86
87
# File 'lib/philiprehberger/enum.rb', line 84

def each(&)
  freeze_members!
  member_registry.values.each(&)
end

.fetch(name) ⇒ Enum

Look up a member by name, raising if not found

Parameters:

  • name (Symbol, String)

    the member name

Returns:

  • (Enum)

    the member

Raises:

  • (Error)

    if the name is not a valid member



176
177
178
# File 'lib/philiprehberger/enum.rb', line 176

def fetch(name)
  from_name(name) || raise(Error, "no member #{name.inspect} on #{self}")
end

.fetch_by_value(val) ⇒ Enum

Look up a member by value, raising if not found

Parameters:

  • val (Object)

    the value to search for

Returns:

  • (Enum)

    the member

Raises:

  • (Error)

    if the value is not found



185
186
187
# File 'lib/philiprehberger/enum.rb', line 185

def fetch_by_value(val)
  from_value(val) || raise(Error, "no member with value #{val.inspect} on #{self}")
end

.firstEnum?

Return the first declared member

Returns:

  • (Enum, nil)

    the first member, or nil if empty



208
209
210
211
# File 'lib/philiprehberger/enum.rb', line 208

def first
  freeze_members!
  member_registry.values.first
end

.from_name(name) ⇒ Enum?

Look up a member by its name, with case-insensitive fallback

Parameters:

  • name (Symbol, String)

    the member name

Returns:

  • (Enum, nil)

    the member, or nil if not found



148
149
150
151
152
# File 'lib/philiprehberger/enum.rb', line 148

def from_name(name)
  freeze_members!
  key = name.to_sym
  member_registry[key] || member_registry.values.find { |m| m.name.to_s.downcase == key.to_s.downcase }
end

.from_string(string) ⇒ Enum?

Look up a member by its string representation

Parameters:

  • string (String)

    the member name as a string

Returns:

  • (Enum, nil)

    the member, or nil if not found



158
159
160
# File 'lib/philiprehberger/enum.rb', line 158

def from_string(string)
  from_name(string)
end

.from_value(val) ⇒ Enum?

Look up a member by its custom value

Parameters:

  • val (Object)

    the value to search for

Returns:

  • (Enum, nil)

    the member, or nil if not found



166
167
168
169
# File 'lib/philiprehberger/enum.rb', line 166

def from_value(val)
  freeze_members!
  member_registry.values.find { |m| m.value == val }
end

.lastEnum?

Return the last declared member

Returns:

  • (Enum, nil)

    the last member, or nil if empty



216
217
218
219
# File 'lib/philiprehberger/enum.rb', line 216

def last
  freeze_members!
  member_registry.values.last
end

.member(name, value: nil) ⇒ Enum

Define a new member on this enum class

Parameters:

  • name (Symbol)

    the member name

  • value (Object, nil) (defaults to: nil)

    an optional custom value

Returns:

  • (Enum)

    the created member

Raises:

  • (Error)

    if the enum is frozen or name is already defined



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/philiprehberger/enum.rb', line 95

def member(name, value: nil)
  raise Error, "cannot add members to #{self} after freeze" if @frozen

  name = name.to_sym
  raise Error, "member #{name} is already defined on #{self}" if member_registry.key?(name)

  ord = member_registry.size
  instance = new(name, ord, value)

  member_registry[name] = instance
  const_set(name.upcase, instance)

  instance
end

.membersArray<Enum>

Return all members in declaration order

Returns:

  • (Array<Enum>)

    frozen array of all members



113
114
115
116
# File 'lib/philiprehberger/enum.rb', line 113

def members
  freeze_members!
  member_registry.values.freeze
end

.members_by_valueHash{Object => Enum}

Return a reverse lookup hash of values to members

Returns:

  • (Hash{Object => Enum})

    value => member pairs



129
130
131
132
# File 'lib/philiprehberger/enum.rb', line 129

def members_by_value
  freeze_members!
  member_registry.each_value.to_h { |m| [m.value, m] }
end

.namesArray<Symbol>

Return all member names in declaration order

Returns:

  • (Array<Symbol>)

    frozen array of member names



192
193
194
195
# File 'lib/philiprehberger/enum.rb', line 192

def names
  freeze_members!
  member_registry.keys.freeze
end

.sample(n = nil) ⇒ Enum+

Return a random member or array of random members

Parameters:

  • n (Integer, nil) (defaults to: nil)

    number of members to return; nil returns a single member

Returns:

  • (Enum, Array<Enum>)

    single member if n is nil, array of n members otherwise



243
244
245
246
# File 'lib/philiprehberger/enum.rb', line 243

def sample(n = nil)
  freeze_members!
  n.nil? ? member_registry.values.sample : member_registry.values.sample(n)
end

.sizeInteger Also known as: count

Return the number of defined members

Returns:

  • (Integer)

    the member count



137
138
139
140
# File 'lib/philiprehberger/enum.rb', line 137

def size
  freeze_members!
  member_registry.size
end

.slice(*names) ⇒ Array<Enum>

Return members matching the given symbol names, silently skipping unknown names

Parameters:

  • names (Array<Symbol>)

    the member names to look up

Returns:

  • (Array<Enum>)

    array of matching members in the given order



234
235
236
237
# File 'lib/philiprehberger/enum.rb', line 234

def slice(*names)
  freeze_members!
  names.filter_map { |n| member_registry[n.to_sym] }
end

.to_hHash{Symbol => Object}

Return a hash of name symbols to values

Returns:

  • (Hash{Symbol => Object})

    name => value pairs



121
122
123
124
# File 'lib/philiprehberger/enum.rb', line 121

def to_h
  freeze_members!
  member_registry.transform_values(&:value)
end

.valid?(name) ⇒ Boolean

Check if a name is a valid member

Parameters:

  • name (Symbol, String)

    the member name

Returns:

  • (Boolean)

    true if the name is a valid member



225
226
227
228
# File 'lib/philiprehberger/enum.rb', line 225

def valid?(name)
  freeze_members!
  member_registry.key?(name.to_sym)
end

.valuesArray<Object>

Return all member values in declaration order

Returns:

  • (Array<Object>)

    frozen array of member values



200
201
202
203
# File 'lib/philiprehberger/enum.rb', line 200

def values
  freeze_members!
  member_registry.values.map(&:value).freeze
end

Instance Method Details

#<=>(other) ⇒ Integer?

Compare members by ordinal

Parameters:

  • other (Enum)

    another member of the same enum class

Returns:

  • (Integer, nil)

    -1, 0, 1, or nil if not comparable



45
46
47
48
49
# File 'lib/philiprehberger/enum.rb', line 45

def <=>(other)
  return nil unless other.is_a?(self.class)

  ordinal <=> other.ordinal
end

#deconstruct_keys(keys) ⇒ Hash

Support Ruby 3.x pattern matching with ‘in` expressions

Parameters:

  • keys (Array<Symbol>, nil)

    the keys to deconstruct

Returns:

  • (Hash)

    hash of requested keys



72
73
74
75
# File 'lib/philiprehberger/enum.rb', line 72

def deconstruct_keys(keys)
  h = { name: name, ordinal: ordinal, value: value }
  keys ? h.slice(*keys) : h
end

#inspectString

Returns a human-readable representation.

Returns:

  • (String)

    a human-readable representation



57
58
59
# File 'lib/philiprehberger/enum.rb', line 57

def inspect
  "#<#{self.class} #{name}>"
end

#to_json(*args) ⇒ String

Serialize to a JSON-compatible hash

Returns:

  • (String)

    JSON string with name, ordinal, and value



64
65
66
# File 'lib/philiprehberger/enum.rb', line 64

def to_json(*args)
  { name: name, ordinal: ordinal, value: value }.to_json(*args)
end

#to_sString

Returns the member name as a string.

Returns:

  • (String)

    the member name as a string



52
53
54
# File 'lib/philiprehberger/enum.rb', line 52

def to_s
  name.to_s
end