My favorite hacks are small code-generating macros that allow you to replace a bunch of standard boilerplate commands with one short one. Alternatively, you can create commands for opening/creating notebooks.
Here is what I've been using for a while in my day-to-day Mathematica workflow. I found myself performing the following a lot:
- Make a notebook have a private context, load package(s) I need, make it autosave.
- After working with this notebook for a while, I'd want to do some throw away scratch computations in a separate notebook, with its own private context, while having access to definitions I've been using in the "main" notebook. Because I set up the private context, this requires to manually adjust $ContextPath
Doing all this by hand over and over is a pain, so let's automate! First, some utility code:
(* Credit goes to Sasha for SelfDestruct[] *)
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookDelete[]]; e)
writeAndEval[nb_,boxExpr_]:=(
NotebookWrite[nb, CellGroupData[{Cell[BoxData[boxExpr],"Input"]}]];
SelectionMove[nb, Previous, Cell];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb];
)
ExposeContexts::badargs =
"Exposed contexts should be given as a list of strings.";
ExposeContexts[list___] :=
Module[{ctList}, ctList = Flatten@List@list;
If[! MemberQ[ctList, Except[_String]],AppendTo[$ContextPath, #] & /@ ctList,
Message[ExposeContexts::badargs]];
$ContextPath = DeleteDuplicates[$ContextPath];
$ContextPath]
Autosave[x:(True|False)] := SetOptions[EvaluationNotebook[],NotebookAutoSave->x];
Now, let's create a macro that's going to put the following cells in the notebook:
SetOptions[EvaluationNotebook[], CellContext -> Notebook]
Needs["LVAutils`"]
Autosave[True]
And here's the macro:
MyPrivatize[exposedCtxts : ({__String} | Null) : Null]:=
SelfDestruct@Module[{contBox,lvaBox,expCtxtBox,assembledStatements,strList},
contBox = MakeBoxes[SetOptions[EvaluationNotebook[], CellContext -> Notebook]];
lvaBox = MakeBoxes[Needs["LVAutils`"]];
assembledStatements = {lvaBox,MakeBoxes[Autosave[True]],"(*********)"};
assembledStatements = Riffle[assembledStatements,"\[IndentingNewLine]"]//RowBox;
writeAndEval[InputNotebook[],contBox];
writeAndEval[InputNotebook[],assembledStatements];
If[exposedCtxts =!= Null,
strList = Riffle[("\"" <> # <> "\"") & /@ exposedCtxts, ","];
expCtxtBox = RowBox[{"ExposeContexts", "[", RowBox[{"{", RowBox[strList], "}"}], "]"}];
writeAndEval[InputNotebook[],expCtxtBox];
]
]
Now when I type in MyPrivatize[]
is creates the private context and loads my standard package. Now let's create a command that will open a new scratch notebook with its own private context (so that you can hack there with wild abandon without the risk of screwing up the definitions), but has access to your current contexts.
SpawnScratch[] := SelfDestruct@Module[{nb,boxExpr,strList},
strList = Riffle[("\"" <> # <> "\"") & /@ $ContextPath, ","];
boxExpr = RowBox[{"MyPrivatize", "[",
RowBox[{"{", RowBox[strList], "}"}], "]"}];
nb = CreateDocument[];
writeAndEval[nb,boxExpr];
]
The cool thing about this is that due to SelfDestruct
, when the command runs it leaves no trace in the current notebook -- which is good, because otherwise it would just create clutter.
For extra style points, you can create keyword triggers for these macros using InputAutoReplacements
, but I'll leave this as an exercise for the reader.