Friday, January 19, 2018

#1 2014-03-31 08:32:34 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Making AppleScript more reusable with the visitor pattern.

Hello.

Sometimes, you may think yourself obstructed when trying to write reusable code, because, the code that really makes it all work is in the very "meat" of what could have been reusable.

Then the visitor pattern may come in handy. Below is an illustration of it.

Applescript:

(*
   closestRootFolder:
   You can have several "roots" below the last one, say in a build-hierachy of c-source, or markdown/html.
   closestRootFolder traverses the directory structure upwards to the stopPath, and checks each folder on its way by the visitor you supplied.
   
   parameter: probePath
   Finds the closest root folder of a file. The closest root being some folder one or several folders up that satisifes some criteria.
   parameter: stopPath
   We supply a stopFolder, which is the heighest level, or last tier if you like, for this particular root.
   Parameter: Visitor
   A script you supply with the handler "validator", that tells us if the current path satisifes the criteria for a root folder.

   Returns false, if no root where found, or the path to the closest root for the probepath supplied.
   
   
   An example visitor script for which I wrote this library for.
   The root folder I am looking for contains a folder named "m4", and a makefile.
   
   script visitor
       on validator(probePxPath)
           tell application id "sevs"
               if not (exists disk item (probePxPath & "/makefile")) then return false
               if not (exists disk item (probePxPath & "/m4")) then return false
           end tell
           return true
       end validator
   end script
   
*)


on closestRootFolder(probePath, stopPath, visitorScript)
   
   -- We start checking that our arguments actual has some value.
   if not hasContents(probePath) then error "isInADomain: probePath can't be empty"
   if not hasContents(stopPath) then error "isInADomain: posixPath can't be empty"
   if not class of visitorScript is script then error "isInADomain: Visitor script needs to be a script "
   
   set probePxPath to UFS(probePath)
   set stopPxPath to UFS(stopPath)
   
   if stopPxPath is not in probePxPath then return false
   set containingFolder to pxpathExclFilename(probePxPath)
   repeat
       set testResult to visitorScript's validator(containingFolder)
       if testResult is true then
           return containingFolder
       else if containingFolder is stopPath then
           return false
       else
           -- we're iterating upwards
           set containingFolder to parentPxPathFolder(containingFolder)
       end if
   end repeat
   
   return true
end closestRootFolder

on hasContents(somePath)
   if class of somePath is list and somePath is {} then return false
   if class of somePath is text and somePath is "" then return false
   if somePath is null or somePath is missing value then return false
   return true
end hasContents

on UFS(whatever)
   local uxPth
   try
       if class of whatever is list then set whatever to whatever as text
       
       if class of whatever is not alias and class of whatever is not text then
           set uxPth to POSIX path of (whatever as alias)
           
       else if (class of whatever is alias) then
           set uxPth to POSIX path of whatever
       else
           if text 1 of whatever is "'" then ¬
               set whatever to text 2 thru -1 of whatever
           
           if text -1 of whatever is "'" then ¬
               set whatever to text 1 thru -2 of whatever
           
           if (offset of ":" in whatever) is not 0 then
               try
                   set uxPth to POSIX path of (whatever as alias)
               on error e number n
                   -- maybe it was ok as it was ..
                   try
                       (POSIX file whatever as alias)
                       set uxPth to whatever
                   on error e number n
                       error e number n
                   end try
               end try
           else
               (POSIX file whatever as alias)
               set uxPth to whatever
           end if
       end if
       return uxPth
   on error e number n
       return missing value
   end try
end UFS

to parentPxPathFolder(aPxPath)
   local tids, parFol
   set {tids, my text item delimiters} to {my text item delimiters, "/"}
   
   if (character (length of aPxPath) of aPxPath) = "/" then
       set parFol to text items 1 thru -3 of aPxPath as text
   else
       set parFol to text items 1 thru -2 of aPxPath as text
   end if
   set my text item delimiters to tids
   if parFol = "" then set parFol to "/"
   return parFol
end parentPxPathFolder

on pxpathExclFilename(pxPath)
   
   if not (class of pxPath is text and pxPath contains "/") then error "pxpathExclFilename: pxPath isn't a valid posixPath"
   if pxPath = "/" then error "pxpathExclFilename: rootfolder (\"/\") given as parameter"
   local tids, parFol
   set {tids, my text item delimiters} to {my text item delimiters, "/"}
   
   if (character (length of pxPath) of pxPath) = "/" then
       set parFol to text 1 thru -2 of pxPath
   else
       set parFol to text items 1 thru -2 of pxPath as text
   end if
   set my text item delimiters to tids
   if parFol = "" then set parFol to "/"
   return parFol
   
end pxpathExclFilename

Last edited by McUsrII (2014-03-31 08:36:01 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)