Skip navigation

Externalise functions into a library

357 Views 3 Replies Latest reply: Jul 19, 2013 10:33 PM by Rob de Jonge RSS
Rob de Jonge Level 3 Level 3 (510 points)
Currently Being Moderated
Jun 19, 2013 6:43 PM

Hi,

 

I've been working on a new Applescript which is intended as a customizable template. When it's done, I will be publishing it on GitHub. But right now, I'm still a long way from it being done. In order to allow updates of the framework provided with this template separately from updates in the custom code bits, I've decided I want to split as much as possible off into a library file. There are a whole number of questions I have about this, as it's the first time I'm trying to do this.

 

Please keep in mind this is just a fun thing on the side. I'm not a developer, never have been.

 

I'll reference the following files below ...

 

  • library.scpt is the script with the main, common functions that don't change from one to the next use of this framework
  • template.scpt is the template document which provides the minimal structure for using this framework
  • main.scpt is an actual script that I am writing, it started out as a copy of template.scpt and then I started changing it

 

Loading an external library

There are comments all over the web about how to get one applescript to load another, but for some reason none of it seems to work. Although it seems broken again as I write this, I did at one point get the following line to work

 

set _library to load script alias ((path to desktop as text) & "library.scpt")

 

Q1: Where do I find a comprehensive reference and step-by-step guide to making the loading of a library script work?

 

Configuration settings and variables

The idea is that template.scpt contains a number of properties that library.scpt will need to determine behavior. The configuration settings of the framework, if you will. So I make a copy of template.scpt to main.scpt and I start editing these variables. In addition to this, there are certain variables which will be used by functions in library.scpt and in template/main.

 

Q2: How do I set a property or variable in main.scpt, which can then be used by functions in library.scpt? And how do I set a property or variable inside a specific function in library.scpt, that a function in main.scpt can read and alter if needed?

 

Structure

There is effectively one function in template/main that does the bulk of the work. This function gets called by the framework, which lives in library.scpt. Let's call that function getLiveData(). My intention is to structure this framework as follows.

 

library.scpt contains

 

  • a function init() that does the prep-work like validation of files existing, configuration settings existing, setting starting values of variables, etc.
  • a function main() that is the main routine that runs the script
  • - and a bunch of other functions that are called by init, main or getLiveData.

 

template/main will look like this

 

  • property setting A-Z that are essentially configuration settings
  • function getLiveData() : does the getting of live data, which is what the script is centered around
  • init() : invoke the init function
  • main() : invoke the main function

 

Q3: Does that seem like a sensible setup for a split of common and custom stuff?

 

Validation

One of the things I'm struggling with is how do I validate settings having been made and functions existing in main.scpt. This is effectively what the init() function is for, but I have no idea how I test for a property existing or not.

 

Q4: In main.scpt I say 'property aSetting : TRUE', how can library.scpt then check if this property exists or not?

Q5: In main.scpt I call init() after the getLiveData() has been declared, but how do I check from init() in library.scpt that a function getLiveData() exists in main.scpt?

 

Your help and comments will be much appreciated.

And as soon as the script is ready, I'll share it here.

 

thanks,

Rob

MacBook Air, OS X Mountain Lion (10.8.3), 2GHz i7, 8GB RAM, 256GB SSD
  • Hiroto Level 5 Level 5 (4,815 points)
    Currently Being Moderated
    Jun 22, 2013 2:28 AM (in response to Rob de Jonge)

    Hello

     

    In brief, what you're trying to do would be accomplished by setting parent of library script object to the caller script which loads the library at run-time.

     

    Here's silly scripts just to demonstrate the concepts. The lib.scpt is the complied script of library saved on desktop. The template.applescript is the template of caller. Note that lib.scpt consists of constructor which is to set the parent property of lib script object at run-time and caller (template) calls the constructor with the parent argument set to self. This construct will realise the features requested in Q2, Q4 and Q5. As for Q4 & Q5, you'd need to resort to something like exists_handler() and exists_reference() in lib.scpt because AppleScript language itself does not provide introspection facilities.

     

     

    --lib.scpt
    on new_lib(pobj)
        script lib
            property parent : pobj
            property p1 : 1 * minutes -- unit 1
            property p2 : 1 * hours -- unit 2
            property p3 : missing value -- base date
            
            on exists_handler(h)
                try
                    return h's class = handler
                on error number -1700
                    return false
                end try
            end exists_handler
            
            on exists_reference(s)
                try
                    s's contents
                    return true
                on error number -1700
                    return false
                end try
            end exists_reference
            
            on init()
                -- validation of parent's handlers and properties
                set chk1 to exists_handler(a reference to parent's getLiveData)
                set chk2 to ¬
                    exists_reference(a reference to parent's q1) and ¬
                    exists_reference(a reference to parent's q2)
                
                if not chk1 then error "some handler missing" number 8000
                if not chk2 then error "some property missing" number 8001
                
                -- get live data from parent
                set p3 to my getLiveData()
            end init
            
            on main()
                --
            end main
            
            on f1(x)
                (*
                    number x : shift amount
                    return string : string representation of a date (= my q1 ? p3 + x * p1 : p3 + x * p2)
                *)
                if my q1 then
                    return f2(p3 + x * p1)
                else
                    return f2(p3 + x * p2)
                end if
            end f1
            
            on f2(x)
                (*
                    date x : source date
                    return string : string representation of x
                        my q2 ? localised string : iso string
                *)
                if my q2 then
                    x as string
                else
                    x as «class isot» as string
                end if
            end f2
        end script
    end new_lib
    --end of lib.scpt
    

     

     

    --template.applescript
    property lib : missing value
    property q1 : true -- unit = minute or hour
    property q2 : false -- output format = localised date or iso date
    
    on getLiveData() -- to be invoked by lib
        return current date
    end getLiveData
    
    on init()
        -- create and initialize a instance of lib with its parent set to self
        set lib to new_lib(me) of (load script POSIX file ((path to desktop)'s POSIX path & "lib.scpt"))
        lib's init()
    end init
    
    on main()
        tell lib
            -- modify properties in lib
            set {its p1, its p2} to {(its p1) * 2, (its p2) * 2}
        end tell
        -- retrieve property and invoke handler in lib
        return {lib's p3, lib's f1(5)}
    end main
    
    init()
    main()
    --end of template.applescript
    

     

     

    As for Q3, it depends. In my opinion, the simpler, the better. AppleScript is not designed for large-scale libraries. It's rather involved if not impossible to implement multiple inclusions and manage dependencies. By the way, I don't understand the use of main() in lib.scpt because it is supposed to be a collection of handlers. So I did not implement it in the sample codes listed above.

     

     

    As for Q1, AppleScript Language Guide is the primary document you must peruse. Especially the chapters "Variables and Properties" and "Script Objects".

     

    https://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/App leScriptLangGuide/

    https://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/App leScriptLangGuide/AppleScriptLanguageGuide.pdf

     

    Also you might find the following old thread of some use. There I've written an afterword for reference.

     

    tell/scoping problem

    https://discussions.apple.com/thread/2477010?start=0&tstart=0

     

    Re: re: my parent

    https://discussions.apple.com/message/11852193#11852193

     

     

    Hope this may help,

    H

Actions

More Like This

  • Retrieving data ...

Bookmarked By (0)

Legend

  • This solved my question - 10 points
  • This helped me - 5 points
This site contains user submitted content, comments and opinions and is for informational purposes only. Apple disclaims any and all liability for the acts, omissions and conduct of any third parties in connection with or related to your use of the site. All postings and use of the content on this site are subject to the Apple Support Communities Terms of Use.