Class: ConstantEnum::Base

Inherits:
Struct
  • Object
show all
Extended by:
Enumerable
Defined in:
lib/constant_enum/base.rb

Overview

This supports the creation of a constant class that is designed to work well with ActiveRecord enums. The benefit is you get additional functionality, like finders and slugs. Performance is excellent as these are in-memory structures and not DB calls.

In the simplest structure, you specify a name and an integer ID:

class Genre < ConstantEnum::Base
  enum_of skate:      1,
          surf:       2,
          snow:       3,
          bike:       4,
end

Then, in an ActiveRecord class that wants to use this enum:

 class Video < ActiveRecord::Base
   enum genre: Genre.enum
   ...
 end

From there, you can now do things like:

 @genre  = Genre.find_by_name!(:skate)
 @videos = Video.where(genre: genre)

Interesting routes can be created like:

# /videos/bike, /videos/surf, etc
get 'videos/:genre' => 'videos#index', as: 'videos_genre',
  constraints: { genre: Genre.all.map(&:slug) }

If you have extra data for your enum, you can specify a hash:

class AssetType < ConstantEnum::Base
  enum_of \
    photo: {id: 1, type: 'jpg', bucket: 'photos'},
    video: {id: 2, type: 'mp4', bucket: 'videos'}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object

Handle extra attribute methods like .label or .delivery_type



182
183
184
185
186
187
188
# File 'lib/constant_enum/base.rb', line 182

def method_missing(meth, *args, &block)
  if attributes.has_key?(meth)
    attributes[meth]
  else
    super
  end
end

Instance Attribute Details

#attributesObject

Returns the value of attribute attributes

Returns:

  • (Object)

    the current value of attributes



43
44
45
# File 'lib/constant_enum/base.rb', line 43

def attributes
  @attributes
end

#idObject

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



43
44
45
# File 'lib/constant_enum/base.rb', line 43

def id
  @id
end

#nameObject

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



43
44
45
# File 'lib/constant_enum/base.rb', line 43

def name
  @name
end

Class Method Details

.[](what) ⇒ Object

Role => 1 ; also Role => 1 so models don’t have to care.



72
73
74
75
76
77
78
# File 'lib/constant_enum/base.rb', line 72

def self.[](what)
  if what.is_a?(Integer)
    find(what).id
  else
    find_by_name!(what).id
  end
end

.allObject



114
115
116
# File 'lib/constant_enum/base.rb', line 114

def self.all
  where()
end

.countObject



153
154
155
# File 'lib/constant_enum/base.rb', line 153

def self.count
  enum.keys.length
end

Dropdown is actually [Title, name] for Rails 4.1 enums



158
159
160
# File 'lib/constant_enum/base.rb', line 158

def self.dropdown
  enum.collect{|name,id| [name.to_s.titleize, name] }
end

.each(&block) ⇒ Object

Enumerable support



140
141
142
# File 'lib/constant_enum/base.rb', line 140

def self.each(&block)
  all.each(&block)
end

.enumObject

Just return the hash. For use in ActiveRecord models, eg “enum role: Role.enum”



67
68
69
# File 'lib/constant_enum/base.rb', line 67

def self.enum
  @enum
end

.enum_of(hash) ⇒ Object

Raises:

  • (ArgumentError)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/constant_enum/base.rb', line 46

def self.enum_of(hash)
  raise ArgumentError, "#{self}.enum_of name1: id2, name2: id2" unless hash.is_a?(Hash)
  @data = {}
  @enum = {}
  hash.each do |name,value|
    if value.is_a?(Hash)
      @enum[name] = value[:id] # for Rails
      @data[name] = new(name, value[:id], value)
    else
      @enum[name] = value # for Rails
      @data[name] = new(name, value)
    end

    # Create constants such as ADMIN=1 etc
    const_name =
      name.to_s.upcase.strip.gsub(/[-\s]+/,'_').sub(/^[0-9_]+/,'').gsub(/\W+/,'')
    const_set const_name, @enum[name] unless const_defined?(const_name)
  end
end

.find(id) ⇒ Object



96
97
98
# File 'lib/constant_enum/base.rb', line 96

def self.find(id)
  find_by!(id: id)
end

.find_by(hash) ⇒ Object



104
105
106
# File 'lib/constant_enum/base.rb', line 104

def self.find_by(hash)
  where(hash).first
end

.find_by!(hash) ⇒ Object



108
109
110
111
112
# File 'lib/constant_enum/base.rb', line 108

def self.find_by!(hash)
  find_by(hash) or
    raise RecordNotFound,
       %Q(Couldn't find #{self} with #{hash.collect{|k,v| "#{k}=#{v.inspect}"} * ' '})
end

.find_by_id(id) ⇒ Object



100
101
102
# File 'lib/constant_enum/base.rb', line 100

def self.find_by_id(id)
  find(id) rescue nil
end

.find_by_name(name) ⇒ Object



84
85
86
# File 'lib/constant_enum/base.rb', line 84

def self.find_by_name(name)
  find_by_name!(name) rescue nil
end

.find_by_name!(name) ⇒ Object



80
81
82
# File 'lib/constant_enum/base.rb', line 80

def self.find_by_name!(name)
  find_by!(name: name)
end

.find_by_slug(slug) ⇒ Object



92
93
94
# File 'lib/constant_enum/base.rb', line 92

def self.find_by_slug(slug)
  find_by!(slug: slug) rescue nil
end

.find_by_slug!(slug) ⇒ Object



88
89
90
# File 'lib/constant_enum/base.rb', line 88

def self.find_by_slug!(slug)
  find_by!(slug: slug)
end

.idsObject



145
146
147
# File 'lib/constant_enum/base.rb', line 145

def self.ids
  enum.map{|r| r.last}
end

.namesObject



149
150
151
# File 'lib/constant_enum/base.rb', line 149

def self.names
  enum.map{|r| r.first}
end

.where(hash = {}) ⇒ Object

Allow simple detection, similar to ActiveRecord. This method is a little verbose because we need to mimic where({}) which returns everything. It also supports where(type: ‘video’, active: true) for multiple restrictions.

Raises:



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/constant_enum/base.rb', line 121

def self.where(hash={})
  raise RecordNotFound, "No records defined for #{self}" if @data.nil?
  results = []
  @data.each do |name,struct|
    found = true # where({})
    hash.each do |k,v|
      if k.to_s == 'name'
        found = false if name.to_s != v.to_s
      else
        found = false if struct.send(k) != v
      end
    end
    # for where({})
    results << struct if found
  end
  results
end

Instance Method Details

#slugObject

Instance methods: @role = Role.new ; @role.slug



165
166
167
# File 'lib/constant_enum/base.rb', line 165

def slug
  name.to_s.downcase.gsub(/\W+/,'')
end

#titleObject



169
170
171
# File 'lib/constant_enum/base.rb', line 169

def title
  name.to_s.titleize
end

#to_paramObject



177
178
179
# File 'lib/constant_enum/base.rb', line 177

def to_param
  id.to_s
end

#to_sObject



173
174
175
# File 'lib/constant_enum/base.rb', line 173

def to_s
  name.to_s
end