mwunsch/gilt

View on GitHub
lib/gilt/product.rb

Summary

Maintainability
B
4 hrs
Test Coverage
module Gilt
  autoload :Sku, "gilt/sku"

  class Product

    def self.defer(future)
      require 'weary/deferred'
      Weary::Deferred.new future, self, lambda {|product, response| product.new(response.parse) }
    end

    def self.client(apikey, affid=nil)
      Gilt::Client::Products.new(apikey, affid)
    end

    def self.detail(product_id, apikey, affid=nil)
      client(apikey, affid).detail(:product_id => product_id)
    end

    def self.create(product_id, apikey, affid=nil)
      response = detail(product_id, apikey, affid).perform
      self.new response.parse
    end

    def self.categories(apikey, affid=nil)
      response = client(apikey, affid).categories.perform
      response.parse["categories"] || []
    end

    def initialize(product_body)
      @product = product_body
    end

    def name
      @product["name"]
    end

    def product
      URI(@product["product"])
    end

    def id
      @product["id"].to_i
    end

    def brand
      @product["brand"]
    end

    def url
      URI(@product["url"])
    end

    def categories
      @product["categories"] || []
    end
    def description
      fetch_content :description
    end

    def fit_notes
      fetch_content :fit_notes
    end

    def material
      fetch_content :material
    end

    def care_instructions
      fetch_content :care_instructions
    end

    def origin
      fetch_content :origin
    end

    def content
      keys = [:description, :fit_notes, :material, :care_instructions, :origin]
      Hash[keys.map {|content| [content, self.send(content) ]}]
    end

    def skus
      @product["skus"].map {|sku| Sku.new(sku) }
    end

    def min_price
      sorted_price.last
    end

    def max_price
      sorted_price.first
    end

    def price_range
      [min_price, max_price]
    end

    def format_price
      range = price_range
      return range.first.format if range.first == range.last
      price_range.map(&:format).join(" - ")
    end

    def images
      @product["image_urls"]
    end

    def colors
      skus.map {|sku| sku.attributes[:color] }.uniq
    end

    def sizes
      skus.map {|sku| sku.attributes[:size] }.uniq
    end

    def skus_of_size(size)
      skus_with_attribute :size, size
    end

    def skus_of_color(color)
      skus_with_attribute :color, color
    end

    def skus_with_attribute(attribute, value)
      skus.select {|sku| !!sku.attributes[attribute.to_sym].match(value) }
    end

    def select_sku(attributes)
      attribute_map = attributes.map {|k, v| skus_with_attribute(k, v).map(&:id) }
      ids = attribute_map.reduce(:&)
      skus.find {|sku| sku.id == ids.first } if ids.size > 0
    end

    def inventory_status
      sku_inventory = skus.map(&:inventory_status).uniq
      if sku_inventory.include? Gilt::Sku::FOR_SALE
        Gilt::Sku::FOR_SALE
      elsif sku_inventory.all? {|status| status == Gilt::Sku::RESERVED}
        Gilt::Sku::RESERVED
      else
        Gilt::Sku::SOLD_OUT
      end
    end

    def for_sale?
      inventory_status == Gilt::Sku::FOR_SALE
    end

    def sold_out?
      inventory_status == Gilt::Sku::SOLD_OUT
    end

    def reserved?
      inventory_status == Gilt::Sku::RESERVED
    end

    private

    def fetch_content(key)
      content = @product["content"]
      content[key.to_s] unless content.nil?
    end

    def sorted_price
      set = skus.map(&:sale_price).uniq
      return set if set.size == 1
      set.sort
    end

  end
end