A way to bind procedure files into an experiment?

I am wishing for a way to "bind together" procedure files into an experiment file so that, when I distribute the experiment itself (e.g. as a demo package), users do not have to have the corresponding procedure files installed locally. Using the analogy with #pragma directives, I would see this ...

#bind <procedure file name>

At compile, the directive would load the procedure file (from User's Procedures) and "bind" it into the experiment by storing it within the experiment in some manner. At future compiles, the directive would run the procedure file from the embedded version, ignoring any external file by that name.

Use Case

I have utility procedure files that layout graphs + panels, that take snapshots into notebooks, and that scroll through traces. The tragedy for me is that, every time I develop an experiment that I would like to share with students or colleagues, I have to copy + paste the utility functions into my experiment procedure window.

I suspect that this request may also dovetail with requests for ways to make experiments "stand alone".

JJ - Have you looked at the AdoptFiles operation.  There is a flag for adopting procedure files.  This could be the basis for your requirement.

Oh. Gosh. I *knew* vaguely that something must have existed. It has been too long ago that I had used it to remember what.

Adopting is likely perfect for my use-case. Thank you!!!

Follow up ... It would be useful to have a way to show the adopted content and to UNadopt content. By experience, I did not realize/remember that we should save the experiment with a different name once we run AdoptFiles. I had to search about for an older copy of the original to recover back to include additional changes (and then re-adopt external content). :-/

Un-adopting an internal procedure file is called "Save As". You're right that it doesn't work as automatically as you probably want it to, but if it did, we would almost instantly hear about cases where that was bad :)

Oh. Save As removes the adoptions. This works for me. Thanks!!

ps -- The help for AdoptFiles might clarify that saving after adopting files keeps the adopted files whereas saving as a new name after adopting files removes the adopted files. As I recall, the implication in the help files seemed to suggest that we should adopt files and then save as a new file. Or at least it was not as clear as you've just made it.

Adopting a procedure file doesn't delete the disk file, unless you save something over that file. If you Save Procedure File As (I didn't use quite the right terminology the first time around) and use the original name, you will overwrite the original file, of course.

I'm sorry about the confusion- Save As saves the current experiment file as a new file.

OK. Let me clarify what I am doing. I create an experiment as a demo. It is self-contained except for two procedure files, Send to Layout.ipf and Send to Notebook.ipf. These are general purpose procedure files that I will want to use over and over again. They are independent modules (SendtoLayout and SendtoNotebook) with entry point function calls (sendtolayout#layout_frontset() and sendtonotebook#notebook_frontset()).

The demo experiment has a call to each function. At the start, before I adopt the two procedure files, I have to #include them. Once I am happy with the operation, I do a Save As and save the experiment as Demo Experiment - WORKING COPY. Note the extra - WORKING COPY suffix. I then do a call to AdoptFiles *while still in the non working copy*. I then remove the #include directives (comment them out). Finally, I save the demo experiment.

At next opening, the demo experiment should be / is self-contained.

I think this covers what I have found to work. My anxiety arose from the case that I forgot to save the working copy before I made the experiment self-contained. I could not recover back to un-adopt the adopted files. I had to dig up an older version of the original experiment.

In the meantime, we are probably meaning the same thing in how best to use AdoptFiles.

I've only translated one experiment so far. I am fixin' to (southern slang) do another one soon. I may have follow up questions or insights.


Ah- I think we were talking about slightly different things when we said "unadopt". From the point of view of the procedures in the experiment file, unadopt is the same as Save Procedure As. From the point of view of restoring the use of the existing external files, though, the unadopt step becomes restoring the #include lines. So, in fact, we were talking about different things there.

I am puzzled about "I then remove the #include directives". The whole point of adopting procedure files is to remove the connection to the external file, which means removing the #include statement. I wonder if that is some sort of bug with independent modules. In fact, I just tried it- Adopt commented the #include statement. My procedure file was NOT an IM procedure, though. Hopefully Jim "Mr. IM" will chime in on that one.

Yes. At one point I did not see the #include directives get commented out automatically.

But I am now able to have the adoptfiles/UP work properly even with the IMs.

I think I am getting the hang of what is needed. More later.

Here is one approach to create a minimalistic "stand alone" package.

* Remove all procedure files except those that are required for the package. This also means that you must remove your Igor Procedures (rename the folder to xIgor Procedures). A later step below will tell you why.

* Develop using #include pragmas for the packages that you need from Users Procedures. Put the #include pragmas in the first few lines at the top of the procedure window.

* Create your own Menu "My Demo Menu" with the directives that you want. Do not use the Macros menu for this.

* Include a Function AfterCompiledHook() with a directive to HideIgorMenus to remove all menus.

--> Debug until you are fully satisfied that your package works.

* Save the experiment with a different name (e.g. add a suffix WC for working copy).

* Run this on the command line ... AdoptFiles/UP. This will adopt all external procedures. This will adopt ALL CURRENTLY INCLUDED external procedures, including some (or all) of the unimportant ones that you forgot to remove in step 1 above.(*)

* Clear the history window. Save. Quit.

--> When you reopen the experiment, it should be self-contained and minimalistic in appearance.

I am attaching a demo experiment to show results from my implementation with the above practice.

(*) -- Yes, you *could* try figuring out the AdoptFiles/W=... syntax. For one procedure file, this will be better. After two includes, it seems a bit too convoluted. I cannot vouch for whether one master include with sub-includes would work for adoption.

I might return to my starting post. I think that having a #bind pragma (or #adopt or #embed) would be far easier to oversee compared to the AdoptFiles/UP or AdoptFiles/W=... approach. Users could develop entirely with #include pragmas. When they are happy, they simply switch to #bind pragmas. No fuss to decipher the command or its variations. No worries about what may other procedure files also get adopted; only those that they choose. Later, for example to update the bindings procedures, switch #bind to #include pragma, recompile, switch #include to #bind, and recompile again.

Demo - Meniscus on Wall.pxp (97.61 KB)

I have two comments-

1) You can hold down the shift key while pulling down the File menu, and then select Adopt All. That will put up a dialog that gives you a UI that makes the process of doing the adopt a bit more friendly.

2) A Nitpicky comment on terminology- a "pragma" is a statement that starts with #pragma. These are directives that are designed to not cause a compile error if they are unrecognized. That's why we often introduce new compiler behavior with #pragma rtglobals=somenumber. That way, you can still compile your code in a previous version of Igor that doesn't know what rtglobal=3 means.

As I said, nitpicky!

> You can hold down the shift key while pulling down the File menu, and then select Adopt All. That will put up a dialog that gives you a UI that makes the process of doing the adopt a bit more friendly.

In my case, I have done the HideIgorMenus already (using an AfterCompiledHook). So this option is lost to me. In the meantime, the command line approach shown below is effective. I could indeed store this in my note pad for easy retrieval as I move through my sets of demonstrations to convert.

print v_flag // confirm that only 2 procedures were adopted

> As I said, nitpicky!

Much appreciated.