module EnumExt::SupersetHelpers

Private Instance Methods

enum_supersets( enum_name, options = {} ) click to toggle source

enum_supersets Use-case whenever you need superset of enums to behave like a super enum.

You can do this with method **enum_supersets** it creates:
  - scopes for subsets,
  - instance methods with `?`

For example:
 enum status: [:in_cart, :waiting_for_payment, :paid, :packing, :ready_for_shipment, :on_delivery, :delivered],
      ext: [enum_supersets: {
              around_delivery: [:ready_for_shipment, :on_delivery], # for shipping department for example
              in_warehouse: [:packing, :ready_for_shipment],    # this scope is just for superposition example below
              sold: [:paid, :around_delivery, :in_warehouse, :delivered] # also you can define any superposition of already defined supersets or enum values
            }]

 # supersets will be stored inside enum wrapper object, and can be de-referenced to basic enum values
 # using wrapper defined methods: "superset_enum_plural", i.e. statuses.sold_statuses -> [:paid, :packing, :ready_for_shipment, :on_delivery, :delivered]
 # so new supersets could be defined using Array operations against newly defined methods
 enum_ext :status, enum_supersets: {
                outside_warehouse: ( statuses.around_delivery - statuses.in_warehouse ) #... any other array operations like &, + and so can be used
              }

it will generate:

instance:

- methods: around_delivery?, in_warehouse?

class:

- named scopes: around_delivery, in_warehouse

enum methods:

- Class.statuses.supersets -- will output superset definition hash
- Class.statuses.supersets_raw -- will output superset decompositions to basic enum types hash

- Class.statuses.around_delivery (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
- around_delivery_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])

translation helpers grouped for superset ( started with t_... ):
- Class.statuses.t_around_delivery_options (= [['translation or humanization', :ready_for_shipment] ...] ) for select inputs purposes
- Class.statuses.t_around_delivery_options_i (= [['translation or humanization', 3] ...]) same as above but with integer as value ( for example to use in Active admin filters )

In console:
request.on_delivery!
request.around_delivery?                    # >> true

Request.around_delivery.exists?(request)    # >> true
Request.in_warehouse.exists?(request)    # >> false

Request.statuses.around_delivery            # >> ["ready_for_shipment", "on_delivery", "delivered"]
# File lib/enum_ext/superset_helpers.rb, line 53
def enum_supersets( enum_name, options = {} )
  enum_plural = enum_name.to_s.pluralize

  self.instance_eval do
    suffix = send(enum_plural).suffix
    prefix = send(enum_plural).prefix
    send(enum_plural).supersets.merge!( options.transform_values{ _1.try(:map, &:to_s) || _1.to_s } )

    options.each do |superset_name, enum_vals|
      raise "Can't define superset with name: #{superset_name}, #{enum_plural} already has such method!" if send(enum_plural).respond_to?(superset_name)

      send(enum_plural).supersets_raw[superset_name] = send(enum_plural).superset_to_enum(*enum_vals)

      # class.enum_wrapper.superset
      send(enum_plural).define_singleton_method(superset_name) { base_class.send(enum_plural).superset_to_enum(*enum_vals) }

      superset_method_name = send(enum_plural).transform_enum_label(superset_name)
      # superset_name scope
      scope superset_method_name, -> { where( enum_name => send(enum_plural).send(superset_name) ) } if respond_to?(:scope)

      # instance.superset_name?
      define_method "#{superset_method_name}?" do
        send(enum_name) && self.class.send(enum_plural).send(superset_name).include?( send(enum_name) )
      end

      EnumExt::HumanizeHelpers.define_superset_humanization_helpers( self, superset_name, enum_name )
    end

  end
end
Also aliased as: ext_enum_sets
ext_enum_sets( enum_name, options = {} )
Alias for: enum_supersets