2
$\begingroup$

I'll show one specific example of what I am trying to do, I think it will explain things.

On the default $Path there exist (in version 8) the following 4 packages

DifferentialEquations`BoundaryRegionPlot`
DifferentialEquations`NDSolveProblems`
DifferentialEquations`NDSolveUtilities`
DifferentialEquations`InterpolatingFunctionAnatomy`

These happened to be located in

C:\Program Files\Wolfram Research\Mathematica\8.0.4\AddOns\ExtraPackages\DifferentialEquations

Currently to load these packages, I load each one explicitly, using the full name.

I have a list of all packages, and go over each package listed to load it. (I searched all the folders and opened all the .m files to find listing of all packages, then copied the names and put them in a list).

I am trying to find a way to automatically obtain the full names of these packages. Then load them, so that I do not have to have the names hardcoded in a list, which I have to update when things changes. (say when version 9 is out)

I will be happy if I can find a way to find obtain full name of packages that starts with some context name. For example, here, if I can find a way to find names of packages that start with context DifferentialEquations before loading the packages ofcourse.

I'd like to be able to tell Mathematica: Please load all packages you find on the $Path that has such a name, and I give a name as a string pattern, may be using wildcard.

Then I can type

 <<DifferentialEquations`*

and have all those 4 packages loaded. The above does not work, since there is no such package.

Or tell Mathematica to find me the full name of all packages in the $Path, then I can use the result of this to load them. Ofcourse all of this would this will require a program to go open each .m file found in the $Path, parse the content of the file to determine if it is a package or not, and if so, read the package name from the .m file.

I thought to ask in case there is a way or a command or a trick to do this already that I have overlooked.

thanks

$\endgroup$

1 Answer 1

4
$\begingroup$

Here is some code that can be a start:

Clear[$maxLevel, packageOrDirQ, pckgname, hasPackagesQ, hasInitFileQ]
    $maxLevel = 4;

packageOrDirQ[name_String] :=
   DirectoryQ[name] || (
     StringMatchQ[name, "*.m"] && 
       !StringMatchQ[FileBaseName[name], "init" | "PacletInfo"]);


hasPackagesQ[dir_String?DirectoryQ, level_] :=
    FileNames["*.m", {dir}, level] =!= {};
hasPackagesQ[_, _] = False;


hasInitFileQ[dir_String] :=
   FileExistsQ[FileNameJoin[{dir, "Kernel", "init.m"}]];
hasInitFileQ[_] = False;


pckgname[{parents___String}, dir_String?DirectoryQ, level_ /; level < $maxLevel] :=
    pckgname[{parents, FileBaseName[dir]}, #, level + 1] & /@ 
       Select[FileNames["*", {dir}], packageOrDirQ];

pckgname[{parents__String}, file_String, level_ /; level < $maxLevel] :=
    StringJoin[Riffle[{parents, FileBaseName[file]}, "`"], "`"];

pckgname[_, _, _] := {};

pckgname[dir_String] := Flatten@pckgname[{}, dir, 0];


Clear[getAllPackageNames];
getAllPackageNames[level_: $maxLevel] :=
      Module[{dirs, packagesWithInit, packageNamesWithInit, justPackages},
         dirs  =  Quiet@Select[FileNames["*", $Path], hasPackagesQ[#, level] &];
     packagesWithInit = Select[dirs, hasInitFileQ];
     packageNamesWithInit = FileBaseName[#] <> "`" & /@ packagesWithInit;
     justPackages = 
       Block[{$maxLevel = level},
         Quiet@Flatten[pckgname /@ Complement[dirs, packagesWithInit ]]
       ];
     Join[packageNamesWithInit, justPackages]]

In particular,

StringCases[getAllPackageNames[],"DifferentialEquations"~~___]//Flatten

(*
 {DifferentialEquations`BoundaryRegionPlot`,
  DifferentialEquations`InterpolatingFunctionA natomy`,
  DifferentialEquations`NDSolveProblems`,
  DifferentialEquations`NDSolveUtilities`}
*)

The idea is that we filter out directories with Kernel/init.m files and do not list individual packages there, while for other packages we construct their names from their locations.

The function can be a bit slow, and it will also occasionally pick some Matlab files if you have some Matlab files on the $Path. If you want to add more checks, you can use something like

realPackageQ[name_String?FileExistsQ] :=
   SyntaxQ[Import[name, "String"]]

and change one of the definitions of pckgname to

pckgname[{parents__String}, file_String?realPackageQ, level_ /; level < $maxLevel] :=
    StringJoin[Riffle[{parents, FileBaseName[file]}, "`"], "`"];
$\endgroup$
3
  • $\begingroup$ @NasserM.Abbasi That's because AuthorTools` has init.m, and in fact a non-trivial one. If you look at AuthorTools/Kernel/init.m, you will see that it delcares other packages in that folder, using DeclarePackage. Normally, when you have a project with init.m, which has many packages, it is the business of init.m to properly load those packages. In particular, some of those packages may not even define the corresponding contexts, but be just source files. So, I explicitly iltered those out. If you'd like to include them, change my code, but, as I said, this may be inaccurate. $\endgroup$ Nov 28, 2012 at 14:35
  • $\begingroup$ @NasserM.Abbasi No problem :) $\endgroup$ Nov 28, 2012 at 15:10
  • $\begingroup$ You could add the extension ".wl" that it uses for new version for packages too. $\endgroup$ Jun 1, 2015 at 7:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.