Module: EnumExt

Defined in:
lib/enum_ext.rb,
lib/enum_ext/version.rb

Overview

Let’s assume we have model Request with enum status, and we have model Order with requests like this: class Request

extend EnumExt
belongs_to :order
enum status: [ :in_cart, :waiting_for_payment, :payed, :ready_for_shipment, :on_delivery, :delivered ]

end

class Order

has_many :requests

end

Constant Summary collapse

VERSION =
"0.1.5"

Instance Method Summary collapse

Instance Method Details

#ext_enum_sets(enum_name, options) ⇒ Object

Rem:

ext_enum_sets can be called twice defining a superpositoin of already defined sets:
class Request
  ...
  ext_enum_sets (... first time call )
  ext_enum_sets :status, {
                    already_payed: ( [:payed] | delivery_set_statuses ),
                    outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
                 }


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/enum_ext.rb', line 112

def ext_enum_sets( enum_name, options )
  self.instance_eval do
    options.each do |set_name, enum_vals|
      scope set_name, -> { where( enum_name => self.send( enum_name.to_s.pluralize ).slice( *enum_vals.map(&:to_s) ).values ) }

      define_singleton_method( "#{set_name}_#{enum_name.to_s.pluralize}" ) do
        enum_vals
      end

      define_method "#{set_name}?" do
        self.send(enum_name) && ( enum_vals.include?( self.send(enum_name) ) || enum_vals.include?( self.send(enum_name).to_sym ))
      end

    end

    scope "with_#{enum_name.to_s.pluralize}", -> (sets_arr) {
      where( enum_name => self.send( enum_name.to_s.pluralize ).slice(
                 *sets_arr.map{|set_name| self.try( "#{set_name}_#{enum_name.to_s.pluralize}" ) || set_name }.flatten.uniq.map(&:to_s) ).values )
    } unless respond_to?("with_#{enum_name.to_s.pluralize}")

    scope "without_#{enum_name.to_s.pluralize}", -> (sets_arr) {
      where.not( id: self.send("with_#{enum_name.to_s.pluralize}", sets_arr) )
    } unless respond_to?("without_#{enum_name.to_s.pluralize}")
  end
end

#localize_enum(enum_name, localizations) ⇒ Object

if you need some substitution you can go like this

localize_enum :status, {
      ..
 delivered: "Delivered at: %{date}"
}
request.delivered!
request.t_status % {date: Time.now.to_s} # >> Delivered at: 05.02.2016

Using in select:

f.select :status, Request.t_statuses.invert.to_a


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/enum_ext.rb', line 54

def localize_enum( enum_name, localizations )
  self.instance_eval do
    define_singleton_method( "t_#{enum_name.to_s.pluralize}" ) do
      localizations.try(:with_indifferent_access) || localizations
    end
    define_method "t_#{enum_name}" do
      t = localizations.try(:with_indifferent_access)[send(enum_name)]
      if t.try(:lambda?)
        t.try(:arity) == 1 && t.call( self ) || t.try(:call)
      elsif t.is_a?(Proc)
        instance_eval(&t)
      else
        t
      end.to_s
    end
  end
end

#mass_assign_enum(*options) ⇒ Object

association_relation: true - Order.first.requests.scope.new_stat! - works but it wouldn’t works without ‘scope’ part! If you want to use it without ‘scope’ you may do it this way: class Request

...
mass_assign_enum( :status, association_relation: false )

end class Order

has_many :requests, extend: Request::MassAssignEnum

end

Order.first.requests.respond_to?(:in_cart!) # >> true

Rem2: you can mass-assign more than one enum ::MassAssignEnum module will contain mass assign for both. It will break nothing since all enum name must be uniq across model



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/enum_ext.rb', line 186

def mass_assign_enum( *options )
  relation_options = (options[-1].is_a?(Hash) && options.pop || {relation: true, association_relation: true} ).with_indifferent_access
  enums_names = options
  enums_names.each do |enum_name|
    enum_vals = self.send( enum_name.to_s.pluralize )

    mass_ass_module = ( defined?(self::MassAssignEnum) && self::MassAssignEnum || Module.new )

    mass_ass_module.instance_eval do
      enum_vals.keys.each do |enum_el|
        define_method( "#{enum_el}!" ) do
          self.update_all( {enum_name => enum_vals[enum_el]}.merge( self.column_names.include?('updated_at') ? {updated_at: Time.now} : {} ))
        end
      end
    end
    self.const_set( :MassAssignEnum, mass_ass_module ) unless defined?(self::MassAssignEnum)

    self::ActiveRecord_Relation.include( self::MassAssignEnum ) if relation_options[:relation]
    self::ActiveRecord_AssociationRelation.include( self::MassAssignEnum ) if relation_options[:association_relation]
  end
end