module Collectible::Collection::EnsuresItemEligibility

Constants

ENSURE_TYPE_EQUALITY

Private Instance Methods

allow_item(&block) click to toggle source

@example

# Allows any item that responds to :even? with a truthy value
allow_item { |item| item.even? }

for block { |item| … } @yield [*] Yields each inserted item to the provided block. The item will only be allowed into

the collection if the block resolves to a truthy value; otherwise, an error is raised.
The block shares the context of the collection +instance+, not the class.
# File lib/collectible/collection/ensures_item_eligibility.rb, line 82
def allow_item(&block)
  raise Collectible::TypeEnforcementAlreadyDefined if item_enforcement.present?
  raise ArgumentError, "must provide a block" unless block_given?

  self.item_enforcement = block
end
allows_item?(item) click to toggle source

@param item [*] @return [Boolean]

# File lib/collectible/collection/ensures_item_eligibility.rb, line 33
def allows_item?(item)
  if ensure_item_validity_with.respond_to?(:call)
    instance_exec(item, &ensure_item_validity_with)
  elsif ensure_item_validity_with.present?
    item.class <= ensure_item_validity_with
  else
    true
  end
end
ensure_allowed_in_collection!(*new_items) click to toggle source

Raises an error if any items fail the class' item validity block/class

# File lib/collectible/collection/ensures_item_eligibility.rb, line 21
def ensure_allowed_in_collection!(*new_items)
  ensure_type_equality!(*new_items) and return if ensures_type_equality?

  invalid_items = new_items.flatten.reject { |item| allows_item?(item) }
  return if invalid_items.empty?

  raise Collectible::ItemNotAllowedError,
        "not allowed: #{invalid_items.first(3).map(&:inspect).join(", ")}#{"..." if invalid_items.length > 3}"
end
ensure_item_validity_before(*methods) click to toggle source

Inserts a check before each of the methods provided to validate inserted objects

@param *methods [Array<Symbol>]

Calls superclass method
# File lib/collectible/collection/ensures_item_eligibility.rb, line 118
def ensure_item_validity_before(*methods)
  methods.each do |method_name|
    around_method(method_name, prevent_double_wrapping_for: "EnsureItemValidity") do |*items|
      ensure_allowed_in_collection!(items)

      super(*items)
    end
  end
end
ensure_item_validity_with() click to toggle source

@return [Class, Proc] Either a class that all collection items must belong to,

or a proc that validates each item as it is inserted.
# File lib/collectible/collection/ensures_item_eligibility.rb, line 67
def ensure_item_validity_with
  item_enforcement ||
    (superclass.ensure_item_validity_with if superclass.respond_to?(:ensure_item_validity_with, true))
end
ensure_type_equality!(*new_items) click to toggle source
# File lib/collectible/collection/ensures_item_eligibility.rb, line 48
def ensure_type_equality!(*new_items)
  new_items = new_items.flatten
  first_item = items.blank? ? new_items.first : items.first

  new_items.each do |item|
    next if item.class == first_item.class

    raise Collectible::ItemTypeMismatchError, "item mismatch: #{first_item.inspect}, #{item.inspect}"
  end
end
ensures_item_class(klass) click to toggle source

@example

# Allows any item where item.class <= TargetDate
ensures_item_class TargetDate

@param klass [Class] A specific class all items are expected to be. Items of this type will be

allowed into collection; otherwise, an error is raised.
# File lib/collectible/collection/ensures_item_eligibility.rb, line 95
def ensures_item_class(klass)
  raise Collectible::TypeEnforcementAlreadyDefined if item_enforcement.present?

  self.item_enforcement = klass
end
ensures_type_equality() click to toggle source

Allows any object initially, but any subsequent item must be of the same class

@example

collection << Meal.first
=> #<ApplicationCollection items: [ #<Meal id: 1> ]

collection << User.first
=> Collectible::ItemNotAllowedError: not allowed: #<User id: 1>
# File lib/collectible/collection/ensures_item_eligibility.rb, line 109
def ensures_type_equality
  raise Collectible::TypeEnforcementAlreadyDefined if item_enforcement.present?

  self.item_enforcement = ENSURE_TYPE_EQUALITY
end
ensures_type_equality?() click to toggle source

@return [Boolean]

# File lib/collectible/collection/ensures_item_eligibility.rb, line 44
def ensures_type_equality?
  ensure_item_validity_with == ENSURE_TYPE_EQUALITY
end
item_class() click to toggle source

@return [Class] The class or superclass of all items in the collection

# File lib/collectible/collection/ensures_item_eligibility.rb, line 61
def item_class
  item_enforcement.is_a?(Class) ? item_enforcement : name.gsub(%r{Collection.*}, "").safe_constantize
end