"Martin DeMello" <martindemello / yahoo.com> schrieb im Newsbeitrag news:0JEvc.620827$Pk3.157220 / pd7tw1no... > 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' I'd perfer to have something in front of cols() that does the splitting - otherwise it's always space separated which might limit usefulness. You could do class String alias split_old split def split(x) case x when Regexp split_old(x) when :space split_old( /\s+/ ) when String split_old( x ) else split_old( x.to_s ) end end end > 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! This name is misleading since it suggests that array is manipulated in place. Better remove the "!". Even better use optionparse to process options. > 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(" ")}") Why do you spawn an extra process here? IMHO that's superfluous. If you put the command into a block, your main loop will look like this: while ( line = gets ) line.chomp! command.call line end To do that you just need command = eval %Q{ lambda {|line| puts line.instance_eval( '#{ARGV.shift}' ) } } Regards robert > #------------------------------------------------------------------------- --- > > 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