The Preferences Pattern

June 16th, 2005 | Tags:

When writing [my AppleScripts](http://applescript.plaidcow.net/) I try to allow for enough flexibility for each user to set the script up to his/her liking, without requiring that all of the questions be answered each time the action is performed. In other words: saved preferences.

In my latest scripts to be updated ([Rename Files][] and [Remove Missing Tracks][]), I have switched to a new form of preferences (writing a structure to a file) and have tried to create a series of functions and properties which can work together and be the same in all of the scripts.

[Rename Files]: http://applescript.plaidcow.net/iTunes/RenameFiles/
[Remove Missing Tracks]: http://applescript.plaidcow.net/iTunes/RemoveMissingTracks/

The `preferencesFilename` property stores the name of the file that will be stored in the preferences directory. All of these files names should begin with `net.plaidcow.`

The `LoadPreferences()` function is responsible for loading the preferences from the disk and assigning them into the global variables. A template of is shown in this code
(Edit):

on LoadPreferences()
  SetDefaultPreferences()

  set theFile to (path to preferences from user domain as string) ¬
    & preferencesFilename as file specification
  try
    set thePreferences to item 1 of (read theFile as list)

    -- Set all of the globals based on the data in the file,
    -- wrapping each set statement in its own try block
    try
      -- Set the global to the data from the file
    end try
  end try

  my UpdatePreferencesDependencies()
end LoadPreferences

The function starts off with a call to `UpdatePreferencesDependencies()` which will ensure that all of the preferences have been set to valid values. Since the `read` command is located within a try block, not error will be thrown if the file doesn’t exist. Assuming that the file was read, each of the parameters can then be read out of the structure that was read from the file. By wrapping each of the command to set a single parameter in its own try block, any parameter can not exist the the reading of the preferences will not fail. (This should allow the adding and removing of parameters between versions with no ill effects.)

The `SavePreferences()` function calls is a simple aggregation of the global preferences into a list, and then the writing of that to the `preferencesFilename`. In this sample code (Edit), the global `notificationType` is being saved:

on SavePreferences()
  set thePreferences to {notificationType:notificationType}
  set theFile to (path to preferences from user domain as string) ¬
    & preferencesFilename as file specification
  try
    open for access theFile with write permission
    set eof of theFile to 0
    write (thePreferences) to theFile starting at eof as list
    close access theFile
  on error
    try
      close access theFile
    end try
  end try
end SavePreferences

`UpdatePreferences()` calls a series of user interface command to get the user to input new values for some or all of the preferences. After inputing these, the `UpdatePreferencesDependencies()` function is called. Unless another mechanism is being used, this is the time to cal `SavePreferences()`

The `ResetPreferences()` function calls the private `SetDefaultPreferences()`, followed by private `UpdatePreferencesDependencies()`. This code should be the same for every implementation (Edit):

on ResetPreferences()
  SetDefaultPreferences()
  UpdatePreferencesDependencies()
end ResetPreferences

The last of the preferences function are two that should not be called from outside of the other preferences functions. (Alas, there is no way to declare private functions, so just don’t do it.) `SetDefaultPreferences()` sets all of the global preferences to their default values. `UpdatePreferencesDependencies()` updates any of the other variables in the script which may depend on the value of one of the preferences. One example of this is the [notifier][1] object, which saves it’s type of notification in a global variable.

[1]: http://applescript.plaidcow.net/PCS/DialogLibrary/

No comments yet.
You must be logged in to post a comment.