I am trying to create a documentated application inside FileNameJoin[{$UserBaseDirectory, "Applications"}]
I obviously dont fully understand the concept of the package-system, because I get troubles with loading in the packages using Needs
. The structure of my "TestApplication" is simple. Mainfolder "TestApplication" contains a package "TestPackage.m" wich looks like this:
BeginPackage["TestApplication`TestPackage`"]
TestFunction::usage = "TestFunction[x] gives x^2"
Begin["`Private`"]
TestFunction[x_] := x^2
End[]
EndPackage[]
To load the definitions I added a "init.m" file inside a folder "Kernel" and it contains the following line:
Get["TestApplication`TestPackage`"]
If I now call:
Needs["TestApplication`]
Mathematica gives me a warning:
Needs::nocont: Context TestApplication` was not created when Needs was evaluated. >>
This is very anoying, because I want to create a documentation for my TestPackage with many examples and since the input cells of a reference page have the option CellContext -> CellGroup
every CellGroup
has to call Needs
and the user would see this message everytime he wants to evaluate an example.
To avoid this message I thought of just creating that context "TestApplication`" so that Mathematica stops complaining about that. This is what I did: I added another Package named "TestApplication.m" into the folder "TestApplication" with the content:
BeginPackage["TestApplication`"]
EndPackage[]
And I extended the init.m file to
Get["TestApplication`TestPackage`"]
Get["TestApplication`TestApplication`"]
for loading in this new empty (root-)package of my application.
Well if I now call
Needs["TestApplication"]
TestFunction[3]
inside a fresh notebook, everything seems to be fine.
No Needs::nocont
-Message is produced anymore, BUT the problem starts if i call Needs
inside my reference page.
Here it just dont work anymore. It does not load the definition of TestApplication``TestPackage``TestFunction
!
To test this i made a small testnotebook for you:
<< TestApplication`
TestFunction[3]
CreateDocument[
Cell[CellGroupData[{Cell[
BoxData[RowBox[{"Needs", "[", "\"\<TestApplication`\>\"",
"]"}]], "Input"],
Cell[BoxData[RowBox[{"TestFunction", "[", "3", "]"}]], "Input"],Cell[BoxData["$ContextPath"], "Input"]}]],
StyleDefinitions ->
FrontEnd`FileName[{"Wolfram"}, "Reference.nb",
CharacterEncoding -> "UTF-8"]]
It will open a minimal "reference page" wich calles the function "TestFunction". Its important, that the application has been loaded previously with Get[TestApplication]
to reproduce the problem.
I tried to analyze the problem by looking at $ContextPath
inside of the reference notebook. If the application "TestApplication" has not been loaded before from a global notebook, $ContextPath
contains all the subcontexts of "TestApplication" after calling Needs
.
In:
$ContextPath
Out:
{"TestApplication`", "TestApplication`TestPackage`", "Notebook$$154$436091`", "System`"}
This way it works fine.
But if "TestApplication" allready has been loaded before from an empty notebook (fresh kernel) with a global context (not the reference nb) than the $ContextPath
only contains the toplevelcontext TestApplication. (after calling Needs
from inside the reference page)
In:
$ContextPath
Out:
{"TestApplication`", "Notebook$$154$436091`", "System`"}
This seems to be the problem, why `TestApplicationTestPackage
Testfunction is not loaded this time.
Does someone know why this happens or how I can do this better?
EDIT 1:
I meanwhile found a solution but it might be dirty. if someone knows a more convenient way to do this, any answer is still much appreciated!
I replaced the content of the init.m
file by:
BeginPackage["TestApplication`", {"TestApplication`TestPackage`"}]
EndPackage[]
And I deleted the file "TestApplication.m", since it was not neccessary anymore. With this if Needs["TestApplication``"]
is called, the empty context TestApplication
is created and this itself calls Needs["TestApplication``TestPackage``"]
. But i still have no idea why my first attempt did not worked. Remember that this problem only appears in the special case where a local CellContext
is used, e.g. in reference pages.
EDIT 2:
My first solution works not right for me because i want to be able to specify a file, wich Needs
loads, when a context is needed. For example if you use encoded files Test-encoded
for the packages inside of TestApplication
, its not enough to use `Needs["TestApplicationTestPackage
"], since the context is not written in clear text in the encoded file.
I also found a simple work around to do this:
My init.m
now looks like this:
Off[Needs::nocont]
SetDirectory[FileNameJoin[{$UserBaseDirectory,"Applications", "TestPackage"}]];
Needs["TestApplication`TestPackage`", "TestPackage-encoded"]
Needs["TestPackage`TestPackage2`", "TestPackage2-encoded"]
PrependTo[$ContextPath, "TestPackage`"]
ResetDirectory[];
(* On[Needs::nocont] *)
But i am still not happy with this solution. Because i have to turn out the Message and i am not able to turn it on again at the end of init.m, without throwing the message.
EDIT 3:
Adding a file TestApplication.m with the content:
BeginPackage["TestApplication`",{"TestApplication`TestPackage`"}];
EndPackage[];
as Ymareth suggested, is just another form of my own first answer (EDIT1) wich is not very satisfying because you can not specify where the Packages come from.
I want to have something like this:
BeginPackage["TestApplication`"];
Needs["TestApplication`TestPackage`", "fileOfTestPackage"]
EndPackage[];
But it does not work.
The documentation of BeginPackage
says:
BeginPackage["context``",{"need_1``","need_1``",...}]
calls Needs on the need_i.
So how can i call these Needs
manually with specifying the packagefiles?
Get["TestApplication`TestPackage`"]
ininit.m
and renaming your encoded files toTestPackage.m
instead ofTestPackage-encoded
is not good enough? It seems to not make much sense to useNeeds
in yourTestAppliation`init.m
as that will be read only once when loaded withNeeds["TestApplication`"]
anyway, so there is no gain in usingNeeds
there overGet
. I also don't understand why it would be a problem when the context is not human readable within an encoded file, Mathematica will happily load it anyway... $\endgroup$Get["TestApplication``TestPackage``"]
is not enough because then i get the Needs::nocont Message. This message strangely only appears inside a reference page. Open any reference page or use my example code to reproduce the problem. You are right with renaming the encoded files, but what if I want to give a key for encoding. Than I need to explicitly useGet["TestPackage.m", "key"]
and i can not use the syntaxBeginPackage["TestApplication``", {"TestApplication``TestPackage``}]
By the way how do you quote ``` inside of code? $\endgroup$