From: Martin DeMello Date: 2004-06-03T21:23:41+09:00 Subject: linefilter - looking for suggestions 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