I'm writing a small wrapper around ruby, meant to be used as part of a
unix pipeline filter - e.g.

 ls -l | rbx 'cols(8,4).mapf(:to_s).formatrow(" ", 30, 8).endl'

It basically consists of a small 'rbx' executable, and a 'linefilter'
library, which contains useful extensions to String - ideally, it'll let
rbx be used as a convenient replacement for awk, sed and perl for quick
one-liners (code below). 

Any suggestions for improvements or useful additional methods? One thing
I'm considering is an Array#apply, which invokes a differnt method on
each member of an array (for instance the above example could have it
inserted as .mapf(:to_s).apply(:ljust, :rjust).formatrow(...)) - do
people like the name?

martin

rbx (for want of a better short name) is

#----------------------------------------------------------------------------
#!/usr/bin/ruby

class Array
  def take_while!
    r = []
    while yield(at(0))
      r << shift
    end
    r
  end
end
    
# -- MAIN --

flags = ARGV.take_while! {|i| i =~ /^-/}
command = "'print \$_.to_s.instance_eval {#{ARGV.shift}}'"
files = ARGV.dup

system("ruby -rlinefilter #{flags.join(" ")} -ne #{command} #{files.join(" ")}")

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

and linefilter contains the following methods (mostly from standard
class extensions):

module Enumerable
  def map_with_index
    a = []
    each_with_index {|e, i| a << yield(e,i)}
    a
  end

  def mapf(method, *args)
    collect do |value|
      value.send(method, *args)
    end
  end

end


class String
  
  def endl
    concat("\n")
  end

  def cols(*args)
    a = split(/\s+/)
    args.map {|i| a[i]}
  end

  def spjoin
    join(" ")
  end

  # from http://www.rubygarden.org/ruby?StringSub

  # 'number' leftmost chars
  def left(number = 1)
    self[0..number-1]
  end

  # 'number' rightmost chars
  def right(number = 1)
    self[-number..-1]
  end

  # 'number' chars starting at position 'from'
  def mid(from, number=1)
    self[from..from+number-1]
  end

  # chars from beginning to 'position'
  def head(position = 0)
    self[0..position]
  end

  # chars following 'position'
  def tail(position = 0)
    self[position+1..-1]
  end

  # Tabs left or right by n chars, using spaces
  def tab(n)
    if n >= 0
      gsub(/^/, ' ' * n)
    else
      gsub(/^ {0,#{-n}}/, "")
    end
  end

  alias_method :indent, :tab

  # Preserves relative tabbing.
  # The first non-empty line ends up with n spaces before nonspace.
  def tabto(n)
    if self =~ /^( *)\S/
      tab(n - $1.length)
    else
      self
    end
  end

end

class Array
  def formatrow(separator, *widths)
    map_with_index {|a,i| 
      w = widths[i]
      (a.to_s).slice(0..(w-1)).ljust(w)
    }.join(separator)
  end
end