On the use of Script Libraries

I have found a method of configuring Scrip Libraries which saves me a lot of trouble.
Many are familar with the process of creating a script library file in ~/Library/Script Libraries.
However, there is extra work in debugging a crash in a handler in a script library file. It’s also difficult structuring a series of handlers if the handler you want in your Script Library has to call a handler or refer to a property in the main script.

I solve it like this:

At the top of my main script:

property traceHandlers : false

use U : script "Utilities_1502" --		General Utilities with no dependencies
use L : script "Loqqing_1525" --		Handlers for Logging and Reporting	
use C : script "CaptureOne_1525" --	Handlers for Capture One
use G : script "GUI_1525" --			Handlers for my General User Interface
use P : script "PreferenceFile 1525" --	Handlers for Preference Files

    set L's M to a reference to me
    set G's M to a reference to me
    set P's M to a reference to me

then in for example in GUI_1525.scpt

use U : script "Utilities_1502"
use L : script "Loqqing_1525"

property M : missing value

true
display alert "You can't run this Script Library File - there is no content in the Run Handler"

So how does all this help?

  1. In a handler of the Script Library I can refer to a property in the main script, like `M’s traceHandlers’ and thus control my tracehandlers feature in all my Script Libraries by a setting in the main script.
  2. I can call a handler in the main script from the Script Library like this M's loadScriptDefaults()
  3. I can setup for debugging a handler in a script library by copying that handler to my main script.
    Lets says this handler is
on initGuiGlobals2(enableFastWorkFlow)
        blah
        blah
        blah
        etc
	return guiData
end initGuiGlobals2

After copying the handler to the main script, I then replace the handler in the script library by

on initGuiGlobals2(enableFastWorkFlow)
	return M's initGuiGlobals2(enableFastWorkFlow)
end initGuiGlobals2

Now Script Debugger quite happily tracks the variables and states of initGuiGlobals2 as the main script executes.

When I’m done debugging, I copy my changed handler back to the Script Library

The main Caveat is don’t tell Preferences to use GUI, and GUI to use Preferences. That will result in a subtle Applescript mental breakdown that is difficult to cure.

I have been using this for about 5 years now, and except for the caveat it appears to be stable and predictable.

A comment on the hierarchy of Use commands in Script Libraries.

I maintain the following hierarchy, where each Library Script has a Layer number, and may not have a “Use” statement connecting to Library Scripts of the same or higher layer.

I think this is critical.

The Library Script Utilities is at the bottom of the hierarchy (layer 0). It’s handlers can have no external dependencies, so that they can be can be used by handlers in any other script. There is no use command, no M property.

The Library Script Loqqing is at layer 1 of the hierarchy; it’s handlers can be used by any other script except Layer 0 and Layer 1. It’s handlers can have no external dependencies except Utilities (layer 0)
The script header includes only U : script "Utilities"

The Library Scripts GUI, Preferences and Capture One are at layer 2 of the hierarchy. It’s handlers can have have dependencies only on Layer 0 and Layer 1. It’s handlers can be used by any other script except Layer 0 , 1 and 2. I broke this rule once and had some very subtle problems that were difficult to recover from.
The script header includes only use U : script "Utilities" and use U : script "Loqqing"

The Library Script Overflow is at layer 3 of the hierarchy. It’s handlers can have have dependencies only on Layer 0, Layer 1 and Layer 2. It’s handlers can be used by any script above Layer 3.
The script header includes use statements for all the layer 0,1 and 2 script libraries.

The main script is at the top of the hierarchy, and has use statements for all the script libraries.