require "concurrent/map"

class Object

  def blank?
    respond_to?(:empty?) ? !!empty? : false
  end

  def present?
    !blank?
  end

  def presence
    self if present?
  end
end

class NilClass

  def blank?
    true
  end

  def present?
    false
  end
end

class FalseClass

  def blank?
    true
  end

  def present?
    false
  end
end

class TrueClass

  def blank?
    false
  end

  def present?
    true
  end
end

class Array

  alias_method :blank?, :empty?

  def present?
    !empty?
  end
end

class Hash

  alias_method :blank?, :empty?

  def present?
    !empty?
  end
end

class Symbol

  alias_method :blank?, :empty?

  def present?
    !empty?
  end
end

class String
  BLANK_RE = /\A[[:space:]]*\z/
  ENCODED_BLANKS = Concurrent::Map.new do |h, enc|
    h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING)
  end

  def blank?

    empty? ||
      begin
        BLANK_RE.match?(self)
      rescue Encoding::CompatibilityError
        ENCODED_BLANKS[self.encoding].match?(self)
      end
  end

  def present?
    !blank?
  end
end

class Numeric

  def blank?
    false
  end

  def present?
    true
  end
end

class Time

  def blank?
    false
  end

  def present?
    true
  end
end