M
Martin DeMello
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).mapfto_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 .mapfto_s).applyljust, :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}
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
(a.to_s).slice(0..(w-1)).ljust(w)
}.join(separator)
end
end
unix pipeline filter - e.g.
ls -l | rbx 'cols(8,4).mapfto_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 .mapfto_s).applyljust, :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}
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
(a.to_s).slice(0..(w-1)).ljust(w)
}.join(separator)
end
end