# .irbrc (for interactive ruby)
# brendan o'connor - anyall.org/code

def softrequire(f)
  begin
    require f
  rescue LoadError
    puts $!
  end
end

%w[ fileutils open-uri pp yaml ].each {|x| softrequire x}
require 'rubygems'
softrequire 'hpricot'
softrequire 'andand'
# softrequire 'fastercsv'
# softrequire 'facets'   # there goes the neighborhood
# softrequire 'facets/enumerable'
# softrequire 'facets/array'
# softrequire 'facets/hash'
# softrequire 'facets/string'
# softrequire 'facets/regexp'
# softrequire 'facets/range'
# softrequire 'facets/symbol'
# softrequire 'facets/time'
# # softrequire 'facets/kernel/tap'


def ls(*args)
  opt = (PLATFORM =~ /darwin/) ? "-G" : "--color=always"
  mysystem "ls", opt, *args
end
def cd(*a);     FileUtils.cd(*a)                  end
def pwd;        FileUtils.pwd                     end
def cat(f);     literal_inspectify File.read(f)   end
def sh;         system(ENV['SHELL'])              end
def bash;       system("bash")                    end
def zsh;        system("zsh")                     end
def vim(*a);    mysystem("vim", *a)               end
def mate(*a);   mysystem("mate", *a)              end

def viewhtml(html, css="")
  # require 'markaby'
  open("|~/sw/bin/viewhtml",'w') do |f|
    f.write html
    # f.write Markaby::Builder.new { 
    #   # head { style { css } }
    #   # body { html }
    # }
  end
  nil
end


def literal_inspectify(s);  def s.inspect; self.to_s end;  s end
def mysystem(cmd, *args)
  # i dont understand why i need this function, it does what i thought
  # system(cmd, *args) would do.
  if args != []
    cmd << " "
    cmd << args.map{|a| '"'+ a.gsub('"','\"') +'"'}.join(" ")
  end
  system(ENV['SHELL'], "-c", cmd)
end

# pretty print as yaml -- is very nice for large complex objects, esp with
# multiline string elements
def ppy(obj)
  puts obj.to_yaml
end

def pp_se(o)
  PP::pp(o, STDERR, 70)
end


Kernel.class_eval {
  def ri(arg)
     puts `ri '#{arg}'`
  end
}

Module.instance_eval {
 def ri(meth=nil)
   if meth
     if instance_methods(false).include? meth.to_s
       puts `ri #{self}##{meth}`
     else
       super
     end
   else
     puts `ri #{self}`
   end
 end
}



# newline-delimited lists, tab-delimited tables (no escaping)

class IO
  def loadlist
    readlines.map!{|l| l.chomp}
  end
  def loadtab(sep="\t")
    loadlist.map!{|l| l.split(sep)}
  end
  def savetab(arr, sep="\t")
    arr.each {|item|  self.puts item.join(sep) }
    self
  end
  def savelist(arr)
    arr.each {|item|  self.puts item}
    self
  end
end
class Array
  def savelist(filename)
    open(filename, "w"){|f| f.savelist self}
    filename
  end
  def savetab(filename, sep="\t")
    open(filename, "w") {|f| f.savetab self,sep}
    filename
  end
end
def loadlist(filename)
  open(filename) {|f| f.loadlist}
end
def loadtab(filename, *args)
  open(filename) {|f| f.loadtab *args}
end
def savelist(arr, filename)
  arr.savelist(filename)
  filename
end
def savetab(arr, filename, *rest)
  arr.savetab(filename, *rest)
  filename
end

# yaml and marshal i/o

def loadyaml(filename)  YAML.load_file(filename)  end
def saveyaml(o, filename)
  open(filename,'w') { |f| YAML.dump o, f }
  filename
end
def load_yaml_docs(stream)
  x = []
  YAML.load_documents(stream) {|d| x << d }
  x
end
def save_yaml_docs(items, stream)
  items.each{|x| stream << x.to_yaml }
end

# class Object
#   def saveyaml(outfilename)
#     File.open(outfilename, "w") {|f| YAML.dump self, f}
#     outfilename
#   end
# end

def loadmar(filename)  open(filename) { |f| Marshal.load f}  end
def savemar(o, filename)
  open(filename,'w') { |f| Marshal.dump o, f}
  filename
end
# class Object
#   def savemar(filename);
#     open(filename,'w') { |f| Marshal.dump self, f}
#     filename
#   end
# end

module Enumerable
  def to_i
    map{|x| x.to_i}
  end
  def to_f
    map{|x| x.to_f}
  end
  def to_na
    NArray[*self]
  end
  # e.g.  matr.convert_cols(:s, :i, :f)
  # string, integer, float.  or any number of floats thereafter.
  def convert_cols(*types)
    types = types.flatten if types.respond_to? :flatten
    raise unless types.size > 0
    if types.size < self[0].size
      types = types + [types[-1]] * (self[0].size - types.size)
    end
    converters = types.map{|t| CONVERTERS[t]}
    map { |row| row.map_with_index{|x,j| x.send(converters[j]) }}
  end
  alias :cc :convert_cols
  CONVERTERS = {
    :int    => :to_i,
    :i      => :to_i,
    :float  => :to_f,
    :f      => :to_f,
    :string => :to_s,
    :str    => :to_s,
    :s      => :to_s,
  }
  
  def progress(method, interval=100)
    count = 0
    ret = send(method) { |x|
      print "." if (count+=1) % interval == 0
      yield x
    }
    puts
    ret
  end
end

class NArray
  def map(*a,&b)
    collect(*a,&b)
  end
end


T = true
F = false


# some stuff kinda ripped off from facets.rubyforge.org

module Enumerable
  def mean
    return nil if size == 0
    sum * 1.0 / size
  end
  def median
    if size % 2 == 0
      sort.middle.mean
    else
      sort.middle
    end
  end
  # Flatten only once, not recursively like Array.flatten
  def flatten1
    inject([]){|r,n| n.respond_to?(:each) ? n.each {|i| r<< i} : (r<< n) ; r} 
  end 
  def uniq_c
    counts = {}
    each { |x| counts[x] = 1 + (counts[x] || 0) }
    uniq.map{ |x| [counts[x], x] }
  end
  def num_true
    select{|x| x}.size
  end
  # for lists of pairs
  def flip
    map{|a,b| [b,a]}
  end
  # for list of integers
  def gaps
    (min..max).to_a - self
  end
  def where(&b)  # like narray
    b ||= lambda {|x| x}
    map_with_index{|x,i| b.call(x) ? i : nil}.compact
  end
  def where2(&b)  # like narray
    b ||= lambda {|x| x}
    pass = map_with_index{|x,i|  b.call(x) ? i : nil}.compact
    fail = map_with_index{|x,i| !b.call(x) ? i : nil}.compact
    [pass, fail]
  end
  def where2e(&b)
    b ||= lambda {|x| x}
    [select(&b), select{|x| !b.call(x)}]
  end
end

# def crossproduct(a1, a2)   # in facets: Enumerable#**
#   a1.map{|x| a2.map{|y| [x,y]}}.flatten1
# end

# in facets
# def middle
#   if size % 2 == 0
#    slice( (size / 2) - 1, 2 )
#    #[slice((size / 2) - 1, 1), slice(size / 2, 1)]
#   else
#     slice(size / 2)
#   end
# end

# in facets
  def sum
    inject(nil) { |sum,x| sum ? sum+x : x }
  end

# # Assumes the array is a list of pairs; hashifies it.  IN FACETS
  def to_h
    ret = {}
    self.each{|x,y| next if x.nil?;  ret[x] = y }
    ret
  end
  def map_with_index   # IN FACETS and ruby 1.9
    range = 0..(size-1)
    ret = []
    each_with_index { |arg,i| ret << yield(arg,i) }
    ret
  end


class String
  def matches(regex)
    ret = []
    scan(regex) do |match_groups|
      ret << $~
    end
    ret
  end
end

class Regexp
  def matches(str)
    str.matches(self)
  end
end

#####################################################################

if ! $irbrc_extensions_only && $".grep(/^irb/).size > 0

  # wirble used to be here, but its lame.  removed

  require 'irb/completion'
  require 'irb/ext/save-history'
  IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
  IRB.conf[:PROMPT_MODE] = :SIMPLE

  # LONG-TERM HISTORY!  See explanation at dotfiles.org/~brendano/.inputrc how
  # this will change your life.  This is really nice for irb, where often you
  # need a string of setup commands, e.g. stack up a bunch of requires on the
  # same line, then "req" <up> gets it later.
  IRB.conf[:SAVE_HISTORY] = 10000
  IRB.conf[:AUTO_INDENT] = true 
  IRB.conf[:EVAL_HISTORY] = 100  # ??

  #--------------

  def timeit
    t = Time.now
    yield
    ensure puts "SECONDS ELAPSED: #{Time.now-t}"
  end

  # ------------

  begin
    require 'highline'
    $hl = HighLine.new
  rescue LoadError
  end

  # print methods
  def pm(obj, *options) 
    methods = obj.methods
    methods -= Object.methods unless options.include? :more
    filter = options.select {|opt| opt.kind_of? Regexp}.first
    methods = methods.select {|name| name =~ filter} if filter

    data = methods.sort.collect do |name|
      method = obj.method(name)
      if method.arity == 0
        args = "()"
      elsif method.arity > 0
        n = method.arity
        args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")})"
      elsif method.arity < 0
        n = -method.arity
        args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")}, ...)"
      end
      klass = $1 if method.inspect =~ /Method: (.*?)#/
      [name, args, klass]
    end
    max_name = data.collect {|item| item[0].size}.max
    max_args = data.collect {|item| item[1].size}.max
    data.each do |item| 
      print $hl.color(" " + item[0].rjust(max_name), :bold)
      print $hl.color(item[1].ljust(max_args), :green, :bold)
      print $hl.color("   #{item[2]}")
      puts
    end
    data.size
  end
  
  # Print object constants, sorted by name.
  def poc(o)
    o.constants.sort
  end
  

  ########################################################################

  #puts "ATTACH VIA:\n\tgdb ruby #{$$}\n"

end



if File.exists?(File.expand_path("~/locals.irbrc"))
  eval File.read(File.expand_path("~/locals.irbrc"))
end


# vim:filetype=ruby
