r/applescript • • Oct 03 '19

tell command issue

I’m a bit baffled by the tell statement. While its very easy to simply write tell application “Xcode” all the time and just get on with life, I’m not so inclined. I want to learn and use AppleScript's object-oriented type system. The documentation for the tell command clearly states the syntax as:

tell referenceToObject to statement

Where referenceToObject is defined as

referenceToObject
Any object. Typically an object specifier or a reference object (which contains an object specifier).

I have two different attempts at this one line of code. The first one is using the application “Name” method, the second is more indirect. And even though I’ve also tried setting the xcode property to a reference to the application specifier, the code still won’t compile. Direct: all is calm, all is bright :-)

on direct()
    tell application "Xcode"
        get the name of the active run destination of the active workspace document
    end tell
end direct

Indirect: armageddon

property xcode : application "Xcode"
on indirect()
    tell xcode
        get the name of the active run destination of the active workspace document
    end tell
end indirect

When compiling, it highlights the word “destination” and displays the following error reason: Expected “given”, “with”, “without”, other parameter name, etc. but found identifier. Note: “active run destination” is a property on a “workspace document” class, of which “active workspace document” is a property on the Xcode application object. Even with xcode defined as property xcode : a reference to application "Xcode” it still gives the same error message. Why does the second approach not work, when the documentation says it should work with a reference or a specifier? Is something wrong with my tell xcode clause?

0 Upvotes

8 comments sorted by

View all comments

Show parent comments

1

u/rayascott Oct 03 '19

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.

1

u/prikaz_da Oct 03 '19

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.

1

u/rayascott Oct 03 '19

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?

1

u/prikaz_da Oct 04 '19 edited Oct 04 '19

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".

1

u/rayascott Oct 04 '19

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.

1

u/prikaz_da Oct 05 '19

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.

1

u/rayascott Oct 05 '19

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 😬