2
votes

Is there any command to trace the package file location and to display the procedures that are defined in that package? If this capability is present, that would be a great help in searching and quick debugging when the programmer has to maintain huge number of packages.

2

2 Answers

2
votes

I'm not aware of any command that answers your question directly. However,

package ifneeded <packageName> <packageVersion>

will tell you the commands that are executed in order to pull in the package, which will often include a source command letting you work out where the package sources are located.

As to working out which procs are defined in a package, the best way I've found of doing this is to do info procs to work out what procs you have defined before requiring the package, the require the package, repeat the info procs command and determine what's been added. Klunky, I know, but it works.

2
votes

I have dealt with a similar problem before. There is no magic in getting your answer, just a lot of elbow grease. Here is my suggestion:

  1. Before importing a package, record the list of name spaces and commands
  2. Import the package in question
  3. Record the list of name spaces and commands again
  4. From the "before" and "after" lists, we can derive a list of new name spaces and commands

Discussion

  • I am using an array stat to ease debugging: during development of the code, I can just parray stat to debug
  • A package such as csv neatly puts new commands in a name space of the same name: ::csv, whereas others such as Tcx puts things in the global name space. We need to address both cases

Caveats

  • A package might import other packages, which throw off the counts (of name spaces and commands)
  • I don't know the differences between info commands and info procs. I always use the former
  • The procedure packageStatistics requires a valid package name. Give it an invalid name, unexpected behaviors will happen

The Code

package require struct::set 

proc packageStatistics {packageName} {
    # Record "before" statistics
    set stat(ns,before) [namespace children]
    set stat(cmd,before) [info commands]

    # Now, import the package in question
    set stat(version) [package require $packageName]

    # Record "after" statistics
    set stat(location) [package ifneeded $packageName $stat(version)]
    set stat(ns,after) [namespace children]
    set stat(cmd,after) [info commands]

    # Report package name, version and location
    puts "Package: $packageName version $stat(version)"
    puts "Location:"
    puts "$stat(location)"

    # Show a list of extra commands in the global namespace
    puts "Commands:"
    set stat(cmd,new) [lsort [struct::set difference $stat(cmd,after) $stat(cmd,before)]]
    foreach cmd $stat(cmd,new) {
        puts "- $cmd"
    }

    # Show a list of extra commands in each of the extra namespace
    set stat(ns,new) [lsort [struct::set difference $stat(ns,after) $stat(ns,before)]]
    foreach ns $stat(ns,new) {
        foreach cmd [info commands ${ns}::*] {
            puts "- $cmd"
        }
    }
}

packageStatistics csv

The Output

Package: csv version 0.7.2
Location:
source /System/Library/Tcl/tcllib1.12/csv/csv.tcl
Commands:
- ::csv::writematrix
- ::csv::split
- ::csv::Split
- ::csv::writequeue
- ::csv::join
- ::csv::read2matrix
- ::csv::read2queue
- ::csv::split2matrix
- ::csv::Split2matrix
- ::csv::split2queue
- ::csv::joinlist
- ::csv::report
- ::csv::joinmatrix
- ::csv::iscomplete