class Object
  def in?(*args)
    if args.length > 1
      args.include? self
    else
      another_object = args.first
      if another_object.respond_to? :include?
        another_object.include? self
      else
        raise ArgumentError.new("The single parameter passed to #in? must respond to #include?")
      end
    end
  end
end

class Array
  def any_in?(container)
    container.has_any? self
  end

  def all_in?(container)
    container.has_all? self
  end

  def has?(obj)
    self.include? obj
  end

  def has_any?(*arr)
    arr.flatten.any?{ |i| i.in? self }
  end

  def has_all?(*arr)
    arr.flatten.all?{ |i| i.in? self }
  end

  def cut(start=nil, stop=nil, step=1)
    step = 1 if step==0
    if step > 0
      start = 0 if start==nil
      if step == 1
        stop==nil ? self.slice(start..-1) : self.slice(start...stop)
      else
        arr = stop==nil ? self.slice(start..-1) : self.slice(start...stop)
        arr.select{ |x| arr.index(x)%step==0 }
      end
    else
      start = -1 if start==nil
      if step == -1
        stop==nil ? self.reverse.slice(-start-1..-1) : self.reverse.slice(-start-1...-stop-1)
      else
        arr = stop==nil ? self.reverse.slice(-start-1..-1) : self.reverse.slice(-start-1...-stop-1)
        arr.select{ |x| arr.index(x)%step==0 }
      end
    end
  end
end

class String
  def has?(obj)
    self.include? obj
  end

  def has_any?(*arr)
    arr.flatten.any?{ |i| i.in? self }
  end

  def has_all?(*arr)
    arr.flatten.all?{ |i| i.in? self }
  end

  def cut(start, stop, step)
    self.chars.to_a.cut(start, stop, step).join
  end

  def first(n=1)
    n==1 ? self[0] : self[0...n]
  end

  def last(n=1)
    n==1 ? self[-1] : self[-n..-1]
  end

  def startswith?(obj)
    if obj.is_a?(String)
      self.index(obj) == 0
    elsif obj.is_a?(Array)
      obj.any?{ |i| self.index(i)==0 }
    end
  end

  def endswith?(obj)
    if obj.is_a?(String)
      self.reverse.index(obj.reverse) == 0
    elsif obj.is_a?(Array)
      obj.any?{ |i| self.reverse.index(i.reverse)==0 }
    end
  end

  def gsub_a(arr1, arr2)
    dup = self.dup
    arr1.each_index do |i|
      dup.gsub!(arr1[i], arr2[i])
    end
    dup
  end

  def gsub_a!(arr1, arr2)
    dup = self.dup
    self.replace(self.gsub_a(arr1, arr2))
    if self == dup
      nil
    else
      self
    end
  end

  def trim(*arr)
    arr = arr.flatten
    if arr.length == 0
      self.strip
    else
      dup = self.dup
      arr.each{ |i| dup.gsub!(%r{(^(#{i})+|(#{i})+$)}, '') }
      dup
    end
  end

  def trim!(*arr)
    dup = self.dup
    self.replace(self.trim(*arr))
    if self == dup
      nil
    else
      self
    end
  end

  def ltrim(*arr)
    arr = arr.flatten
    if arr.length == 0
      self.lstrip
    else
      dup = self.dup
      arr.each{ |i| dup.gsub!(%r{^(#{i})+}, '') }
      dup
    end
  end

  def ltrim!(*arr)
    dup = self.dup
    self.replace(self.ltrim(*arr))
    if self == dup
      nil
    else
      self
    end
  end

  def rtrim(*arr)
    arr = arr.flatten
    if arr.length == 0
      self.lstrip
    else
      dup = self.dup
      arr.each{ |i| dup.gsub!(%r{(#{i})+$}, '') }
      dup
    end
  end

  def rtrim!(*arr)
    dup = self.dup
    self.replace(self.rtrim(*arr))
    if self == dup
      nil
    else
      self
    end
  end
end