In this post I’ll explain my current method for using numerous large AppleScript libraries and my reasoning behind my choices. I hope this is interesting or helpful to someone else who’s interested in alternative AppleScript library loading methods.
Apple has provided an excellent AppleScript library loading method in ‘use script’ and it works very well. But not exactly the way that I would like for it to work. This isn’t a critique of the choices that Apple made, they’re sound, but a discussion of the way that I want my libraries to work and how I achieved it.
REQUIREMENTS:
- I have many script libraries and some of them are very large. I want to be able to easily use any handler from any library in a script with minimal code required to load them.
I designed many of my handlers to be able to be nested easily. i.e.
Array_Sort_Strings(NSURL_Names(NSURLArray))
- I want to avoid having to call handlers by including their library reference. i.e.
Array_Library's Array_Sort_Strings(NSURL_Library's NSURL_Names(NSURLArray)).
WORKING TOWARDS A SOLUTION:
I have some scripts that use handlers from almost every one of my libraries. Here I’m only using a few. Use your imagination and pretend I need all these libs in the following scripts.
I can load all of my libraries into a script using the ‘use script’ command. ‘use script’ just loads references to the scripts and doesn’t cause errOSAInternalTableOverflow errors on saving or running like load script or assigning libraries to properties will with too much AppleScript code.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use mol_AppleScript : script "mol_AppleScript"
use mol_Application : script "mol_Application"
use mol_Array : script "mol_Array"
use mol_Conversion : script "mol_Conversion"
use mol_Date : script "mol_Date"
use mol_FileSystem : script "mol_FileSystem"
use mol_Finder_App : script "mol_Finder_App"
use mol_Image : script "mol_Image"
use mol_Math : script "mol_Math"
use mol_Molecules : script "mol_Molecules"
use mol_NSURL : script "mol_NSURL"
use mol_Numbers_App : script "mol_Numbers_App"
use mol_PhotoShop_App : script "mol_PhotoShop_App"
use mol_ScriptDebugger_App : script "mol_ScriptDebugger_App"
use mol_String : script "mol_String"
use mol_System : script "mol_System"
use mol_SystemSettings_App : script "mol_SystemSettings_App"
use mol_User : script "mol_User"
set folderObject to path to the desktop folder from user domain
set folderObjectContainer to mol_FileSystem's FileSystem_Object_Container(folderObject)
set fileList to mol_FileSystem's FileSystem_List_Files(folderObjectContainer)
set fileNames to mol_NSURL's NSURL_Names(fileList)
set sortedStrings to mol_Array's Array_Sort_Strings(fileNames)
-->12621 files.
But all those use script statements are bulkier than the actual working code and the handler calls are just an ugly mess(IMHO).So I take all those use statements and save them all in a new script library.
--this is saved as script "molecules"
use AppleScript version "2.5"
use scripting additions
-->>LIBRARY REFERENCES
use mol_AppleScript : script "mol_AppleScript"
use mol_Application : script "mol_Application"
use mol_Array : script "mol_Array"
use mol_Conversion : script "mol_Conversion"
use mol_Date : script "mol_Date"
use mol_FileSystem : script "mol_FileSystem"
use mol_Finder_App : script "mol_Finder_App"
use mol_Image : script "mol_Image"
use mol_Math : script "mol_Math"
use mol_Molecules : script "mol_Molecules"
use mol_NSURL : script "mol_NSURL"
use mol_Numbers_App : script "mol_Numbers_App"
use mol_PhotoShop_App : script "mol_PhotoShop_App"
use mol_ScriptDebugger_App : script "mol_ScriptDebugger_App"
use mol_String : script "mol_String"
use mol_System : script "mol_System"
use mol_SystemSettings_App : script "mol_SystemSettings_App"
use mol_User : script "mol_User"
Now I can ‘use’ that library.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property molecules : script "molecules"
set folderObject to path to the desktop folder from user domain
set folderObjectContainer to molecules's mol_FileSystem's FileSystem_Object_Container(folderObject)
set fileList to molecules's mol_FileSystem's FileSystem_List_Files(folderObjectContainer)
set fileNames to molecules's mol_NSURL's NSURL_Names(fileList)
set sortedStrings to molecules's mol_Array's Array_Sort_Strings(fileNames)
-->12621 files.
.
All that library loading code is hidden away now, but the handler calls have gotten even worse! Now I have to refer to both the molecules library and its loaded libraries names! But I can remove that molecules name requirement if I assign this library, not to a normal property, but as the Parent property.
A script object that includes a parent property will take on the properties and handlers of a parent object. The parent script library has AppleScript as its parent so everything still behaves normally.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property parent : script "molecules"
set folderObject to path to the desktop folder from user domain
set folderObjectContainer to mol_FileSystem's FileSystem_Object_Container(folderObject)
set fileList to mol_FileSystem's FileSystem_List_Files(folderObjectContainer)
set fileNames to mol_NSURL's NSURL_Names(fileList)
set sortedStrings to mol_Array's Array_Sort_Strings(fileNames)
-->12621 files.
.
That’s better, but I still have this requirement to use molecules’ loaded library names. The normal way to make handlers local is to de-reference the handler by assigning it to a property.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property parent : script "molecules"
property Array_Sort_Strings : mol_Array's Array_Sort_Strings
property FileSystem_Convert_Object_To_NSURL : mol_FileSystem's FileSystem_Convert_Object_To_NSURL
property FileSystem_Convert_Object_To_PosixPath : mol_FileSystem's FileSystem_Convert_Object_To_PosixPath
property FileSystem_List_Contents : mol_FileSystem's FileSystem_List_Contents
property FileSystem_List_Files : mol_FileSystem's FileSystem_List_Files
property FileSystem_List_Folders_Files_Packages : mol_FileSystem's FileSystem_List_Folders_Files_Packages
property FileSystem_Object_Container : mol_FileSystem's FileSystem_Object_Container
property NSURL_Names : mol_NSURL's NSURL_Names
set folderObject to path to the desktop folder from user domain
set folderObjectContainer to FileSystem_Object_Container(folderObject)
set fileList to FileSystem_List_Files(folderObjectContainer)
set fileNames to NSURL_Names(fileList)
set sortedStrings to Array_Sort_Strings(fileNames)
-->12621 files.
.
This works, my handler calls are all tidy now! But now I’m right back to having all this loading/assignment code.
SOLUTION:
- This Isn’t Even My Final Form
What I’ve decided to do is, instead of writing the handler properties to the script I’m working in, I create a new, custom property library script that only holds the library loading code and the handler property assignments required by the calling script.
--this is saved as 'PropertyLibrary_ScriptName' where ScriptName is the name of the calling script.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property mol_AppleScript : script "mol_AppleScript"
property mol_Application : script "mol_Application"
property mol_Array : script "mol_Array"
property mol_Conversion : script "mol_Conversion"
property mol_Date : script "mol_Date"
property mol_FileSystem : script "mol_FileSystem"
property mol_Finder_App : script "mol_Finder_App"
property mol_Image : script "mol_Image"
property mol_Math : script "mol_Math"
property mol_Molecules : script "mol_Molecules"
property mol_NSURL : script "mol_NSURL"
property mol_Numbers_App : script "mol_Numbers_App"
property mol_PhotoShop_App : script "mol_PhotoShop_App"
property mol_ScriptDebugger_App : script "mol_ScriptDebugger_App"
property mol_String : script "mol_String"
property mol_System : script "mol_System"
property mol_SystemSettings_App : script "mol_SystemSettings_App"
property mol_User : script "mol_User"
property Array_Sort_Strings : mol_Array's Array_Sort_Strings
property FileSystem_Convert_Object_To_NSURL : mol_FileSystem's FileSystem_Convert_Object_To_NSURL
property FileSystem_Convert_Object_To_PosixPath : mol_FileSystem's FileSystem_Convert_Object_To_PosixPath
property FileSystem_List_Contents : mol_FileSystem's FileSystem_List_Contents
property FileSystem_List_Files : mol_FileSystem's FileSystem_List_Files
property FileSystem_List_Folders_Files_Packages : mol_FileSystem's FileSystem_List_Folders_Files_Packages
property FileSystem_Object_Container : mol_FileSystem's FileSystem_Object_Container
property NSURL_Names : mol_NSURL's NSURL_Names
I set the parent property in my developing script to point at ‘PropertyLibrary_ScriptName’, and I have a single line of library loading code, and direct access to whatever properties ( handlers ) I’ve added to the property library.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property parent : script "propertyLibrary_TestScript"
set folderObject to path to the desktop folder from user domain
set folderObjectContainer to FileSystem_Object_Container(folderObject)
set fileList to FileSystem_List_Files(folderObjectContainer)
set fileNames to NSURL_Names(fileList)
set sortedStrings to Array_Sort_Strings(fileNames)
-->12621 files.
I can neatly nest handlers like I wanted.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property parent : script "propertyLibrary_TestScript"
set folderObject to path to the desktop folder from user domain
set sortedStrings to Array_Sort_Strings(NSURL_Names(FileSystem_List_Files(FileSystem_Object_Container(folderObject))))
-->12621 files.
.
CONCLUSIONS:
I realize this may sound complicated and tenuous. But above I’ve described the process I went through to arrive at this solution. Not the current usage.
In actual use it’s almost invisible. To use handlers from my libraries I just run a ‘Insert Handler’ script. This could all be done manually, but we’re scripters!
The ‘Insert Handler’ script
- Lets me choose any handler from any library.
- Determines any other required handlers that are dependencies for the chosen handler.
- Inserts the handler call into the front script at the current selection or cursor point.
- If ‘PropertyLibrary_<the current frontmost script’s name>’ library doesn’t exist then it’s created in the Script Library folder.
- Adds the library loading code and necessary handler property(s) to the ‘PropertyLibrary_theCurrentFrontmostScriptName’ library.
- Adds the 'property parent : script “PropertyLibrary_theCurrentFrontmostScriptName” line to the script if it doesn’t exist.
That’s it. The ‘Insert Handler’ script inserts the handler call and the handler ‘just works’.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
property parent : script "PropertyLibrary_theCurrentFrontmostScriptName"
String_Case_Upper("hello world")
-->"HELLO WORLD"
Distribution is currently handled by running another script ‘Embed Dependencies’ which determines all dependencies, inserts the full code of each required handler, and removes the parent property.
NOTE: Frustratingly, I cannot get the above method to work when the libraries are stored within a .scptd bundle.