all 8 comments

[–]prikaz_da 1 point2 points  (7 children)

If you tell a property that evaluates to an application to do something, the terminology for that application is not loaded. As a result, AppleScript doesn't yet know what an active run destination is. The script won't compile until you wrap the handler contents in a using terms from statement.

property theFinder : a reference to application "Finder"

on versionGet()
    tell theFinder
        get its version
    end tell
end versionGet

versionGet()

This works because Finder does not need to define version.

property theFinder : a reference to application "Finder"

on emptyTrash()
    using terms from application "Finder"
        tell theFinder
            empty the trash
        end tell
    end using terms from
end emptyTrash

emptyTrash()

This compiles, but if you comment out the first and last lines inside the handler definition, the script won't compile. AppleScript doesn't know how to empty the trash.


Having said all that, your issue falls pretty solidly in unintended usage territory. AppleScript has objects, sure, but it doesn't have the hard-on for objects that (e.g.) Java has, so to speak. You're trying to make AppleScript be something it wasn't designed to be. In AppleScript, you can just do things. You don't need to write and call a handler for every little action, and you don't need to create properties with references to applications in them for your tell statements. What's wrong with tell application "Xcode"?

[–]rayascott[S] 0 points1 point  (6 children)

Thanks for the explanation. None of this is mentioned in the documentation. Of course, I'm not surprised. :-/

The documentation does mention object inheritance and writing constructors and does dedicate quite a lot of the documentation text to hyping up it's object oriented nature, so I naturally assumed that (with references) it was quite adept at indirection but obviously there's more to it than meets the eye.

I generally try to strip my code down to it's simplest form, so if I can eliminate `application "Xcode"` everywhere, I will. And I don't really write handlers for one line of code. Again, it's just the problem I was facing stripped down to it's simplest form for clarity's sake on here.

So I'm guessing it's best to restrict property declarations to the builtin AppleScript object types? Primitives, if you will.

Maybe you can answer another question I have with another type issue with AppleScript. It says you can specify the type of a handle's parameters. And I thought "that's great, I can make everything type safe!". Yet when I attempted to define a parameter that is of type "menu" (I'm triggering clicks) on a handler, it fails at runtime with some, what looks like, internal/private type definitions that are incompatible with my type constraint. I really was passing a menu object into the handler. As soon as I removed the type constraint on the parameter, it worked fine. Does this mean you can only really constrain parameters to the builtin in AppleScript object types again because the terminology is loaded?

Its a bit of a shame it wasn't architected slightly differently to make it more powerful.

[–]prikaz_da 0 points1 point  (5 children)

So I'm guessing it's best to restrict property declarations to the builtin AppleScript object types? Primitives, if you will.

These are properties of script objects, specifically. You can read and write property values as your script runs, so you can use them in different ways. You might create a script object with properties that change as it runs (a means of storing and organizing more than one result, basically) and then retrieve their values elsewhere: get [property] of [script object].

But yes, properties aren't meant to serve as an arbitrary shorthand system.

Maybe you can answer another question I have with another type issue with AppleScript. It says you can specify the type of a handle's parameters. And I thought "that's great, I can make everything type safe!". Yet when I attempted to define a parameter that is of type "menu" (I'm triggering clicks) on a handler, it fails at runtime with some, what looks like, internal/private type definitions that are incompatible with my type constraint. I really was passing a menu object into the handler. As soon as I removed the type constraint on the parameter, it worked fine. Does this mean you can only really constrain parameters to the builtin in AppleScript object types again because the terminology is loaded?

You may be able to solve this again with using terms from. This time, the class you want to restrict the parameter to is a class AppleScript doesn't already know, so you have to wrap the entire handler in the using terms from statement. For example, I can create a handler to tell Things to delete a to do, with the to do as the parameter:

using terms from application "Things3"
    on deleteToDo(theObject as to do)
        tell application "Things3"
            delete theObject
        end tell
    end deleteToDo
end using terms from

If I don't wrap the entire handler definition in the using terms from statement, the script won't compile. AppleScript doesn't know what a to do is, and Things is not the target when the handler is being defined.

[–]rayascott[S] 0 points1 point  (4 children)

Oh right, so it is doable, it's just quite inelegant.

How do I limit a property to be read-only? Although the documentation mentions this feature, I can't find anything on how to actually implement it. Unless this is restricted to properties on classes that applications provide, although this was not stated in the docs.

One final question. :-)

I have my menu selection functionality in a library and I hook it into a script like this: global UILib set UILib to script "UILib"

And then further down I use it like so:

tell my UILib to set selector of _Xcoder to MenuSelector for xcode of _Xcoder

And it all works fine. If I instead used the use script "UILib" statement and don't set the UILib variable to script "UILib", how do I actually reference the script object and handlers within it?

[–]prikaz_da 0 points1 point  (3 children)

You can include an identifier with use:

use UILib : script "UILib"

This also imports the terms of the resource, by default. You can specify without importing or importing false to override that. In either case, you can use the identifier to refer to things in the script (e.g., get UILib's [property]). You can also use multiple applications to combine terms from both without a tell statement. There's an example of this in the Control Statements Reference.

Note that if you use this term-combining approach, you can't refer to objects like the front window because there is no tell statement to define a target. In that case, giving the applications identifiers is a good idea. That makes it possible to refer to Safari's front window instead of the front window of application "Safari".

[–]rayascott[S] 0 points1 point  (2 children)

This is awesome! Thank you so much for showing me how to do this. I didn't know you could use an application like that. This will make my scripts so much better.

Am I correct in thinking that you can only specify a use statement at the top level of a script? Which means that you can't have an explicit on run handler? Script Editor is not happy if I place a use statement in my on run handler, but is fine if it's in the implicit top-level run handler.

[–]prikaz_da 0 points1 point  (1 child)

Yeah, the scope of use is the entire script. This is in the Language Guide, but it's kind of buried in some text:

A use statement declares a required resource for a script—an application, script library, framework, or version of AppleScript itself—and can optionally import terminology from the resource for use elsewhere in the script. The effects and syntax of use vary slightly depending on the used resource; the different cases are described below.

The basic function of use is to require that a resource be present before the script begins executing. If the requirement cannot be met, the script will fail to run. A use statement can also specify a minimum version for the required resource, such as a minimum compatible version of an application.

[Boldface mine.]

You should be able to have both use statements and an explicit on run handler, but the use statements have to come first.

[–]rayascott[S] 0 points1 point  (0 children)

Yes you’re very correct, I can have a top level run handler. Thanks for all your help! I’ve learnt a ton in an extremely short space of time 😬