• how to pass a bound method to fileutil::traverse as a -prefilter

    From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Wed Jul 23 11:11:39 2025
    From Newsgroup: comp.lang.tcl

    I want to pass a bound method to fileutil::traverse as a -prefilter.
    I'm using `lambda` but it doesn't help. I can't work out what I'm
    doing wrong based on the error output.

    Below is a cut-down version of the code, followed by the error output.
    To test it run as, say, `tclsh9 find.txt /tmp`

    ### Code

    package require fileutil::traverse
    package require lambda 1
    package require textutil

    proc main {} {
    set config [Config new]
    $config folders $::argv
    process $config
    }

    proc process config {
    set pre_filter [lambda {ignore dirname} {
    dir_filter $ignore $dirname
    } [$config ignore]]
    foreach dir [$config folders] {
    fileutil::traverse iter -prefilter $pre_filter
    $iter foreach filename {
    puts $filename
    }
    $iter destroy
    }
    puts [$config to_string] ;# TODO delete
    }

    proc dir_filter {ignores dirname} {
    for ignore $ignores {
    if {[string match -nocase $ignore $dirname]} { return false }
    }
    return true
    }

    oo::class create Config {
    variable Ignore
    variable What
    variable Folders
    }

    oo::define Config constructor {} {
    set Ignore [list test*.* zOld]
    set What ".tcl"
    set Folders [list]
    }

    oo::define Config method ignore {{ignore ""}} {
    if {$ignore ne ""} { set Ignore $ignore }
    return $Ignore
    }

    oo::define Config method what {{what ""}} {
    if {$what ne ""} { set What $what }
    return $What
    }

    oo::define Config method folders {{folders ""}} {
    if {$folders ne ""} { set Folders $folders }
    return $Folders
    }

    oo::define Config method to_string {} {
    return "Config Ignore=$Ignore What=$What Folders=$Folders"
    }

    main

    ### Error

    $ ./find.tcl /tmp/
    unknown option "::apply {{ignore dirname} {
    dir_filter $ignore $dirname
    }} {test*.* zOld}"
    while executing
    "$self configurelist $args"
    (procedure "::fileutil::traverse::Snit_constructor" line 6)
    invoked from within
    "::fileutil::traverse::Snit_constructor ::fileutil::traverse ::fileutil::traverse::Snit_inst1 ::iter ::iter -prefilter {::apply {{ignore dirname} {
    ..."
    ("eval" body line 1)
    invoked from within
    "eval [linsert $arglist 0 ${type}::Snit_constructor $type $selfns $instance $instance]"
    (procedure "RT.ConstructInstance" line 9)
    invoked from within
    "RT.ConstructInstance $type $selfns $name $args"
    (procedure "::snit::RT.type.typemethod.create" line 45)
    invoked from within
    "fileutil::traverse iter -prefilter $pre_filter"
    (procedure "process" line 6)
    invoked from within
    "process $config"
    (procedure "main" line 4)
    invoked from within
    "main"
    (file "./find.tcl" line 66)
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Wed Jul 23 17:27:15 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | I want to pass a bound method to fileutil::traverse as a -prefilter.
    | I'm using `lambda` but it doesn't help. I can't work out what I'm
    | doing wrong based on the error output.
    --<snip-snip>--
    | fileutil::traverse iter -prefilter $pre_filter
    --<snip-snip>--
    | unknown option "::apply {{ignore dirname} {
    | dir_filter $ignore $dirname
    | }} {test*.* zOld}"

    man traverse(n)
    ::fileutil::traverse ?objectName? path ?option value...?

    I think you are missing the PATH argument to ::fileutil::traverse, so
    the '-prefilter' is taken as the path, and the $pre_filter as an option
    name (which does not exist, as the error message states :-)

    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Ralf Fassel@ralfixx@gmx.de to comp.lang.tcl on Wed Jul 23 17:43:01 2025
    From Newsgroup: comp.lang.tcl

    * Mark Summerfield <m.n.summerfield@gmail.com>
    | proc dir_filter {ignores dirname} {
    | for ignore $ignores {

    Also make this a 'foreach' instead.

    R'
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mark Summerfield@m.n.summerfield@gmail.com to comp.lang.tcl on Wed Jul 23 15:44:05 2025
    From Newsgroup: comp.lang.tcl

    On Wed, 23 Jul 2025 11:11:39 -0000 (UTC), Mark Summerfield wrote:

    I want to pass a bound method to fileutil::traverse as a -prefilter.
    I'm using `lambda` but it doesn't help. I can't work out what I'm
    doing wrong based on the error output.

    Below is a cut-down version of the code, followed by the error output.
    To test it run as, say, `tclsh9 find.txt /tmp`

    ### Code

    package require fileutil::traverse
    package require lambda 1
    package require textutil

    proc main {} {
    set config [Config new]
    $config folders $::argv
    process $config
    }

    proc process config {
    set pre_filter [lambda {ignore dirname} {
    dir_filter $ignore $dirname
    } [$config ignore]]
    foreach dir [$config folders] {
    fileutil::traverse iter -prefilter $pre_filter
    $iter foreach filename {
    puts $filename
    }
    $iter destroy
    }
    puts [$config to_string] ;# TODO delete
    }

    proc dir_filter {ignores dirname} {
    for ignore $ignores {
    if {[string match -nocase $ignore $dirname]} { return false }
    }
    return true
    }

    oo::class create Config {
    variable Ignore
    variable What
    variable Folders
    }

    oo::define Config constructor {} {
    set Ignore [list test*.* zOld]
    set What ".tcl"
    set Folders [list]
    }

    oo::define Config method ignore {{ignore ""}} {
    if {$ignore ne ""} { set Ignore $ignore }
    return $Ignore
    }

    oo::define Config method what {{what ""}} {
    if {$what ne ""} { set What $what }
    return $What
    }

    oo::define Config method folders {{folders ""}} {
    if {$folders ne ""} { set Folders $folders }
    return $Folders
    }

    oo::define Config method to_string {} {
    return "Config Ignore=$Ignore What=$What Folders=$Folders"
    }

    main

    ### Error

    $ ./find.tcl /tmp/
    unknown option "::apply {{ignore dirname} {
    dir_filter $ignore $dirname
    }} {test*.* zOld}"
    while executing
    "$self configurelist $args"
    (procedure "::fileutil::traverse::Snit_constructor" line 6)
    invoked from within
    "::fileutil::traverse::Snit_constructor ::fileutil::traverse ::fileutil::traverse::Snit_inst1 ::iter ::iter -prefilter {::apply {{ignore dirname} {
    ..."
    ("eval" body line 1)
    invoked from within
    "eval [linsert $arglist 0 ${type}::Snit_constructor $type $selfns $instance $instance]"
    (procedure "RT.ConstructInstance" line 9)
    invoked from within
    "RT.ConstructInstance $type $selfns $name $args"
    (procedure "::snit::RT.type.typemethod.create" line 45)
    invoked from within
    "fileutil::traverse iter -prefilter $pre_filter"
    (procedure "process" line 6)
    invoked from within
    "process $config"
    (procedure "main" line 4)
    invoked from within
    "main"
    (file "./find.tcl" line 66)

    I solved it myself eventually.

    proc process config {
    set pre_filter [lambda {foldcase ignore dirname} {
    dir_filter $foldcase $ignore $dirname
    } [$config foldcase] [$config ignore]]
    foreach dir [$config folders] {
    fileutil::traverse iter $dir -prefilter $pre_filter
    iter foreach filename {
    puts $filename
    }
    iter destroy
    }
    puts [$config to_string] ;# TODO delete
    }

    I'd made two mistakes, (1) forgot to put in the $dir arg;
    (2) used $iter instead of iter.
    --- Synchronet 3.21a-Linux NewsLink 1.2