class Shippo::API::Category::Base

Base is a convenience abstract class that provides the following functionality to it's subclasses, which are meant to be enumerations with a fixed number of possible values.

Base populates a global hash Shippo::API::Category.categories which is keyed by the lower cased and symbolized category name (eg, :status or :purpose), each value is another hash consisting of keys (values of each category, eg :success, :error) and value being the constant created for such a value.

__WARNING__: You are not supposed to instantiate these classes, to be honest. The “correct” way is via the Facåde +Shippo::API::Category.for(name, value)+.

Example

“`ruby require 'shippo/api' class Size < ::Shippo::API::Category::Base

allowed_values :small, :medium, :large, :xlarge, :xxlarge

end # ⤷ [:small, :medium, :large, :xlarge, :xxlarge]

my_size = Shippo::API::Category.for('size', 'xlarge') # ⤷ size:xlarge

my_size.xlarge? # ⤷ true my_size.medium? # ⤷ false my_size.name # ⤷ size my_size.value # ⤷ xlarge

medium_1 = Size.new('medium')

 size:medium

medium_2 = Size.new('medium')

 size:medium

medium_3 = Shippo::API::Category.for(:size, :medium)

 size:medium

# But keep in mind these instances are all different objects, # which are +eql?()+ to each other, but not identical. medium_1.object_id # ⤷ 70282669124280 medium_2.object_id # ⤷ 70282669580500 medium_3.object_id # ⤷ 70282681963740 medium_1.eql?(medium_2) # ⤷ true medium_2.eql?(medium_3) # ⤷ true “`

Attributes

categories[RW]
name[RW]
value[RW]

Public Class Methods

allowed_values(*values) click to toggle source
# File lib/shippo/api/category/base.rb, line 77
def allowed_values(*values)
  return @allowed_values if values.nil? || values.empty? || !@allowed_values.empty?

  @allowed_values = self.value_transformer(values)
  @allowed_values.each do |allowed_value|
    category_value = Category.key(allowed_value)
    category_const = category_value.to_s.upcase

    raise ::Shippo::API::Category::DuplicateValueError.new(
      "Constant #{category_const} is already defined in #{self.name}") if self.const_defined?(category_const)

    new_instance = self.new(category_value)
    self.const_set(category_const, new_instance)

    define_method "#{category_value}?".to_sym do
      value.eql?(category_value)
    end

    categories[new_instance.name]                     ||= {}
    categories[new_instance.name][new_instance.value] = new_instance
  end
end
inherited(klazz) click to toggle source
# File lib/shippo/api/category/base.rb, line 65
def self.inherited(klazz)
  klazz.instance_eval do
    @allowed_values = Set.new
    class << self
      def categories
        ::Shippo::API::Category::Base.categories
      end

      def value_transformer(values)
        values.map(&:downcase).map(&:to_sym)
      end

      def allowed_values(*values)
        return @allowed_values if values.nil? || values.empty? || !@allowed_values.empty?

        @allowed_values = self.value_transformer(values)
        @allowed_values.each do |allowed_value|
          category_value = Category.key(allowed_value)
          category_const = category_value.to_s.upcase

          raise ::Shippo::API::Category::DuplicateValueError.new(
            "Constant #{category_const} is already defined in #{self.name}") if self.const_defined?(category_const)

          new_instance = self.new(category_value)
          self.const_set(category_const, new_instance)

          define_method "#{category_value}?".to_sym do
            value.eql?(category_value)
          end

          categories[new_instance.name]                     ||= {}
          categories[new_instance.name][new_instance.value] = new_instance
        end
      end
    end
  end
end
new(value) click to toggle source
# File lib/shippo/api/category/base.rb, line 105
def initialize(value)
  raise ::Shippo::Exceptions::AbstractClassInitError.new('Can not instantiate Base!') if self.class.eql?(::Shippo::API::Category::Base)
  self.name = Category.key(self.class.name.gsub(%r{.*::}, ''))
  self.value = assign_value(value)
end
value_transformer(values) click to toggle source
# File lib/shippo/api/category/base.rb, line 73
def value_transformer(values)
  values.map(&:downcase).map(&:to_sym)
end

Public Instance Methods

eql?(other) click to toggle source
# File lib/shippo/api/category/base.rb, line 111
def eql?(other)
  self.class.eql?(other.class) && self.value.eql?(other.value)
end
to_s() click to toggle source
# File lib/shippo/api/category/base.rb, line 115
def to_s
  "#{self.value.upcase}"
end

Private Instance Methods

assign_value(value) click to toggle source
# File lib/shippo/api/category/base.rb, line 125
def assign_value(value)
  value = clean(value)

  if value_allowed?(value)
    @value = value
  else
    raise ::Shippo::Exceptions::InvalidCategoryValueError.new(
      "Value #{value} is not allowed for Category #{self.class.name}, allowed values are: #{self.class.allowed_values})")
  end
  @value
end
clean(value) click to toggle source
# File lib/shippo/api/category/base.rb, line 137
def clean(value)
  Category.key(value)
end
value_allowed?(value) click to toggle source
# File lib/shippo/api/category/base.rb, line 121
def value_allowed?(value)
  self.class.allowed_values.include?(value)
end