Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Is there any way (other than the manual one) to grab all the functions a notebook uses from the different user-defined packages and putting everything into one file to deploy the code for e.g. CDF? I understand that this involves a recursive search through a possibly large number of package files, and the discovery of heavy interrelations between functions, but it is definitely not impossible to be done (I've done it myself many times by hand), and thus Mathematica should be able to do it. Perhaps Wolfram Workbench?

share|improve this question
    
That would be so useful to have! Did you ever continue working on a solution? –  sebhofer Jul 15 '13 at 11:44
    
@sebhofer Unfortunately: no. It turned out in the long run that for deployment, the easiest way (at least for me) was to manually gather all the packaged functions, or don't use packaged functions at all. It becomes really tedious when deploying projects more complex than a simple demonstration... –  István Zachar Jul 15 '13 at 13:59
    
That's a pitty. I'm often faced with the problem that I need to send a notebook to one of my collaborators. Often these notebooks use a handful oft functions from several of my packages (maybe only one function per package), and it is a pain to collect all the packages. So the functionality you proposed would be just perfect. –  sebhofer Jul 15 '13 at 14:22

2 Answers 2

up vote 13 down vote accepted

I am not aware of such functionality "out of the box", but you can use various symbol dependency frameworks (I have my version published here, although at present it does contain some bugs), to figure out a set of symbols being used. You will need a few auxiliary functions to extract all symbols used in a notebook, and prepare boxed form of the code for them, from their global properties.

Here is some code which can get you started:

ClearAll[getCodePieces];
getCodePieces[nb : (_NotebookObject | Automatic) : Automatic] :=
  With[{nbl = If[nb === Automatic, EvaluationNotebook[], nb]},
    Flatten@
      Cases[NotebookGet[nbl], Cell[BoxData[boxes_], "Input", ___] :>
         ToExpression[boxes, StandardForm, HoldComplete], Infinity]];

ClearAll[getDependentSymbols];
getDependentSymbols[nb : (_NotebookObject | Automatic) : Automatic] :=  
  Union@Flatten[depends /@ getCodePieces[nb]]; 

ClearAll[createCodeBoxes];
createCodeBoxes[HoldComplete[sym_Symbol]] :=
  Module[{optionCode, attributeCode, dsocode, ocode, ucode, boxDefs},
   optionCode = 
     If[# === {}, {}, MakeBoxes[Options[sym] = #]] &@
        Options[Unevaluated[sym]];
   attributeCode = 
     If[# === {}, {}, MakeBoxes[SetAttributes[sym, #]]] &@
        Attributes[sym];
   boxDefs[defOper_] :=
     If[# === {}, {},
        Replace[#, (Verbatim[HoldPattern][lhs_] :> rhs_) :> 
             MakeBoxes[defOper[lhs, rhs]], {1}] &@#
     ] &;   
   dsocode = 
     boxDefs[SetDelayed][
        Flatten[{OwnValues[sym], DownValues[sym], SubValues[sym]}]];
   ucode = boxDefs[UpSetDelayed][UpValues[sym]];
   If[# === {}, {}, RowBox[Join[#, {";", "\n"}]]] &@
      Flatten@
         Riffle[Flatten[{optionCode, attributeCode, ucode,dsocode }], 
            {";", "\n"}]];

Clear[makeNbCode];
makeNbCode[nb : (_NotebookObject | Automatic) : Automatic] :=
  Cell[BoxData[#], "Input"] &@
     RowBox[Flatten[createCodeBoxes /@ getDependentSymbols[nb]]];

This depends on my dependency-tracking framework, particularly the depends function, from the mentioned answer. You use it as (I assume the evaluation notebook for simplicity):

CellPrint@makeNbCode[]

Note that the above code is not complete and will miss certain definitions (e.g. those for Format, default values, etc) - so treat this as a starting point. I tested this on a few examples, seems to work fine. Note also that this will keep the symbol names, including the namespaces / contexts they belong to. Finally, not that one can not fully reconstruct the original code from global properties, bacause the global properties do not encode the information on whether or not the definition was given as immediate or delayed. This should not matter much here, since definitions are used in the way they are stored in the global rule base, though.

An alternative approach would be to get the set of symbols your notebook depends on, as above, but then, rather than reconstructing code from in-memory definitions, find the set of packages you need, load them as Get[...,"HeldExpressions"], and then search the held code of those packages. This may be somewhat more robust, but a little more complex to implement well (although not really very difficult).

Both approaches rely on the fact that your kernel state reflects the fully-working (loaded into memory) functionality that you want to extract - so the recommended use is to first load everything and run your functionality, and then use any of the above methods. If you want to have more "static analysis", this is also possible, but again a bit more complex, and your notebook must be self-contained (loading all needed packages, etc).

share|improve this answer
    
This is exactly along the lines I have visualized. Will try to modify/apply it in near future. I probably will have some questions though. –  István Zachar Mar 6 '12 at 16:16
    
@Istvan Sounds great. I actually usually prefer the explicit code (top-level) solutions, since they give you both more control and more understanding. It is however often hard to make them robust. As to questions - always welcome (if not me, surely lots of other folks here will be able to help) - and you also know my email (on gmail). –  Leonid Shifrin Mar 6 '12 at 16:24

Use the SaveDefinitions option to the Manipulate(s) in your CDF.

share|improve this answer
    
This is useful, and I totally forgot it. One problem is though that if you have anything more complex than a Manipulate (e.g. DynamicModule), you are stuck again. –  István Zachar Mar 6 '12 at 14:15
    
@Istvan I actually took it as you really want the code you are using to be collected in the notebook, to have more control over it - this is why I was suggesting rather complex solutions. If all you have is Manipulate, and you don't care that the reader won't see the code for other symbols easily, the surely SaveDefinitions is the way to go. –  Leonid Shifrin Mar 6 '12 at 14:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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