Larry Smith withOpenFile looks like something tk-related. I would use something like "with filename {};" "using filename {};" or "accessing filename {}" "With" is popular with dicts, so usings or accessing might be better. Ideally, an ensemble, "file with <name> do {}'".
2014-01-11: with open file is an old programming pattern or idiom that abstracts the following:
(When I started this page, I first searched this wiki for similar pages, but still missed a couple of pages (keyword search will only get you so far): Playing with with and using, both of which address the same subject.)
In Tcl code, e.g. on this wiki, this procedure is usually written step-by-step, usually without error handling (and sometimes without actually closing the file):
set f [open $myfile] # ... $f ... close $f
Abstracting away such sequences will make the code less cluttered. A couple of examples:
proc slurp {filename} { set f [open $filename] set res [chan read $f] chan close $f set res } proc fileputs {filename str} { set f [open $filename a] chan puts $f $str chan close $f }
Doing it this way, one command is needed for every file action. Instead, a generic command can be used for all cases where some kind of operation is to be done on a temporarily open file:
proc withOpenFile args { if {[llength $args] < 3} { error {wrong # args: should be "withOpenFile channelIdName filename ?access? ?permissions? script"} } upvar 1 [lindex $args 0] channelid try { open {*}[lrange $args 1 end-1] } on ok channelid { uplevel 1 [lindex $args end] } finally { catch {chan close $channelid} } }
The point of having a try structure without error handling is that it ensures that the channel will be closed even if the script terminates with an exception.
So, instead of
set filename foo.bar set mytext {foo bar} # ... set f [open $filename a] chan puts $f $mytext chan close $f # ... set f [open $filename] set result [chan read $f] chan close $f
you could write
set filename foo.bar set mytext {foo bar} # ... fileputs $filename $mytext # ... set result [slurp $filename]
or
set filename foo.bar set mytext {foo bar} # ... withOpenFile f $filename a {chan puts $f $mytext} # ... set result [withOpenFile f $filename {chan read $f}]
andrewsh 2015-03-11: Here's something similar I hacked together about three years ago. As dbohdan pointed out, I could probably do without redefining proc, but anyway. I must admit I never used this code in production :)
#!/usr/bin/env tclsh namespace eval ::autofile { } rename ::proc ::autofile::proc rename ::open ::autofile::open set ::autofile::files(::) {} ::autofile::proc proc {name args body} { set ns [uplevel { namespace current }] if {$ns eq "::"} { set ns {} } set name $ns\::$name ::autofile::proc $name $args $body trace add execution $name leave ::autofile::autoclose } ::autofile::proc open args { set cmd [uplevel { if {[dict exists [info frame -2] proc]} { namespace which [dict get [info frame -2] proc] } }] set file [::autofile::open {*}$args] lappend ::autofile::files($cmd) $file puts "don't forget to close $::autofile::files($cmd) for $cmd" return $file } ::autofile::proc ::autofile::autoclose {cmd args} { foreach file $::autofile::files($cmd) { puts "closing $file for $cmd" ::close $file } } namespace eval ::test { proc hi args { set f [open /dev/urandom] puts [binary encode base64 [read $f 4]] } } ::test::hi puts bye