# Running a package automatically when it's saved

When developing some new code (eg. a function to analyse something) I usually make a .m and .nb file. The code goes in to .m is then called from the .nb.

But sometimes I forget to run the package after saving and then spend some time wondering why my code changes don't have the desired effect.

Is there a way to run a package automatically after it's saved?

Basically I would like that when I press [Ctrl]+S the package is saved and that the effect of this button being pressed is achieved.

Currently I put Import["MyPackage.m"] at the top of the evaluation cell I'm currently working on in the notebook. Perhaps I could also abuse $Pre for this, but then the package would get imported on every cell evaluation (which is a bit needles). EDIT Well, this is what I have so far based on Chirs's answer FrontEndExecute[ FrontEndAddMenuCommands[ "Save", {Delimiter, MenuItem["Save and Run &Package", FrontEndKernelExecute[NotebookSave[SelectedNotebook[]]; If[FileExtension[NotebookFileName[SelectedNotebook[]]] == "m",(*then*) Get[NotebookFileName[SelectedNotebook[]]]; ]; ], MenuKey["S", Modifiers -> {"Control"}], SystemMenuEvaluator -> Automatic]}]]  - If you are willing to use Wolfram Workbench for package development, it reloads the package automatically when you save it. You can also customize what is being reloaded. – Leonid Shifrin May 10 '12 at 19:51 @LeonidShifrin Yes, I was afraid that would be one of the answers. I tried to start using the workbench about twice, but it always wanted to do things it's way and not my way (especially regarding the layout of files). Perhaps I was doing something wrong and it's time to give it another go. – Ajasja May 10 '12 at 19:57 @ Ajasja - re. your edit, instead of If[FileExtension...] you could use Function[filecheck, If[filecheck =!=$Failed, If[FileExistsQ[#], Get[#]]]& @ StringJoin[StringDrop[filecheck, -3], ".m"]] @ Quiet[NotebookFileName[SelectedNotebook[]]]. This checks if the current notebook is saved, then checks for existence of a package before trying to load it. – Chris Degnen May 10 '12 at 22:09
@ Ajasja - ah, I see you are not coding in a notebook, but wouldn't that be easier? – Chris Degnen May 10 '12 at 23:42
@ChrisDegnen I find coding in a package has a number of advantages: Code is not auto-rearranged as you type and it's simple to have a package under version control. – Ajasja May 11 '12 at 7:09

This will assign a 'Save and Run function to control-shift F:

FrontEndExecute[FrontEndAddMenuCommands["Save",
FrontEndKernelExecute[NotebookSave[SelectedNotebook[]];
Get[StringJoin[
StringDrop[NotebookFileName[SelectedNotebook[]], -3], ".m"]]],
MenuKey["F", Modifiers -> {"Control", "Shift"}],
SystemMenuEvaluator -> Automatic]}]]


To test, include the following as an initialisation cell in the working notebook (with auto-create package):

test := Print["Change this text, then execute Save and Run and run test"]


By using AddMenuCommands the menu addition only appears when the procedure is run, so doesn't affect the standard setup. It only needs to be run once, and the menu addition disappears upon restart. The 'Save and Run' command is placed under Save on the File menu.

-
Hmm, it doesn't seem to run the package in the front end, only saves it. (All the symbols remain blue, but the package is saved). – Ajasja May 10 '12 at 20:06
@Ajasja The blue to black change isn't necessarily a good indicator if a package was loaded. Check to see if the definition is visible via ?FunctionName. – rcollyer May 10 '12 at 20:10
@ChrisDegnen Aha, I want to run the package when I save it, not run the package when I save the notebook as  Get[StringJoin[ StringDrop[NotebookFileName[SelectedNotebook[]], -3], ".m"]]], seems to do. – Ajasja May 10 '12 at 20:11
Amm, now I have about 10 "Save and Run Demo" menu entries (as I've been playing around a bit). Is the last one used? – Ajasja May 10 '12 at 20:17
@ Ajasja - I have read KernelExecute and FrontEndExecute are the same, but think the latter may know some further commands specific to the front end. To use NotebookEvaluate you need something like NotebookEvaluate[SelectionMove[SelectedNotebook[], "All", Notebook]]` to specify what selection to evaluate. – Chris Degnen May 10 '12 at 20:59