SS 2007-03-13:
I like to program in a functional style, so many times I end writing in Tcl and other languages something like [a [b [c [d $arg]]]]. Semantically this is like the Unix shell pipe, so I wrote the following function.
Example:
set s " supercalifragilistichespiralitoso " pipe {string trim $s} {split * {}} {lsort -unique} {join * {}} > s \ {string length} > l puts $s puts $l
Will output
acefghiloprstu 14
The code:
proc pipe args { set r [uplevel 1 [lindex $args 0]] for {set i 1} {$i < [llength $args]} {incr i} { set e [lindex $args $i] if {[llength $e] == 1} { if {$e eq {>}} { incr i uplevel 1 [list set [lindex $args $i] $r] } else { set r [uplevel 1 [list $e $r]] } } else { set cmd {} set substdone 0 foreach arg $e { if {$arg eq {*}} { lappend cmd $r set substdone 1 } else { lappend cmd $arg } } if {$substdone == 0} { lappend cmd $r } set r [uplevel 1 $cmd] } } return $r } set s " supercalifragilistichespiralitoso " pipe {string trim $s} {split * {}} {lsort -unique} {join * {}} > s \ {string length} > l puts $s puts $l
If you read italian there is a longer article about this concept in my blog at http://antirez.com/post/49
Brian Theado: Nice! I have a slightly different version I use sometimes. Unlike yours it only works for commands that return other commands (i.e. jacl, tcom and tdom are all good candidates). Also, it actually uses a | character as the separator.
proc pipe {cmd args} { while {[llength $args]} { set n [lsearch -exact $args |] if {$n < 0} { set n [llength $args]; lappend args | } set a [lreplace $args $n end] if {[llength $a]} { set cmd [eval [linsert $a 0 $cmd]] } set args [lreplace $args 0 $n] } return $cmd }
I adapted the above code from some version of ratcl (my all-time favorite Tcl extension). It uses the "|" to chain together view operators.
Examples
tdom:
pipe [dom parse $xml] documentElement | firstChild | getAttribute style # Instead of: set document [dom parse $xml] set root [$document documentElement] [$root firstChild] getAttribute style tcom]: set excel [::tcom::ref createobject Excel.Application] set worksheets [pipe $excel Workbooks | Add | Worksheets] set lastWorksheet [$worksheets Item [$worksheets Count]] # Instead of: set application [::tcom::ref createobject "Excel.Application"] set workbooks [$application Workbooks] set workbook [$workbooks Add] set worksheets [$workbook Worksheets] set lastWorksheet [$worksheets Item [$worksheets Count]]
JBR 2009-11-22: I've updated the code above for 8.6 features:
proc | { cmd args } { while { [set n [lsearch -exact $args |]] >= 0 } { set cmd [uplevel 1 [list $cmd {*}[lrange $args 0 $n-1]]] if { [llength [set args [lrange $args $n+1 end]]] == 0 } { error "Null command at end of pipeline" } } uplevel 1 [list $cmd {*}$args] }