Reputation: 711
In AppleScript I access an object in an application, e.g.:
tell application id "DNtp"
repeat with g in (children of root of (think window 1))
set theAnnotation to annotation of g
end
end tell
I know that depending on the child accessed, g
sometimes has no annotation
property.
N.B. This is not the same as having a missing value
or something like that.
When running the code, AppleScript simply complains that the variable theAnnotation
is not defined.
Other than trapping the error with a try ... on error
statement, how do I check if g
has the property annotation
?
Upvotes: 3
Views: 2066
Reputation: 6092
I don't use DEVON-related software, but in ordinary1 situations when dealing with AppleScript records, CRGreen
's suggestions won't apply: exists
is not a command that properties understand, especially non-existent properties; and referencing a property that does not exist will throw an error.
I'm glad you're looking for an alternative to try...end try
. I've seen your previous code samples that are drowning in them, and they are expensive operations when an error is caught, so not ideal for what you're attempting. try
really has no place in AppleScript at all.
Rather than testing for the existence of a property within a record
, the way to approach this in a general context is to create a record
object that contains all the property values that would ever be needed, and to assign default values to each of them.
In AppleScript, a record
is observed to follow the following behaviour:
A single record
object can only contain one property with a given identifier. Should you attempt to insert two properties both of which are identified the same, the compiler will keep the first property and its associated value, and scrub the rest:
{a:1, b:2, a:3} # will resolve on compilation immediately to {a:1, b:2}
Two record
objects can contain properties with shared identifiers, like so:
set L to {a:1, b:2, c:3}
set R to {d:missing value, c:L}
Similarly to list
objects, two record
objects can be merged into a single record
, and the properties will be amalgamated: properties with identifiers unique to each record
will simply be inserted without any change into the resulting data structure. Where an identifier occurs in both record
objects before the merge, again, precedence is given in a left-to-right reading order, so the properties in the prefixed record
(on the left) will prevail and the suffixed record
(on the right) will have its non-unique property identifiers (and their values) scrubbed:
L & R --> {a:1, b:2, c:3, d:missing value}
R & L --> {d:missing value, c:{a:1, b:2, c:3}, a:1, b:2}
Your code snippet contains this:
repeat with g in (children of root of (think window 1))
set theAnnotation to annotation of g
end
Therefore, g
is an item contained within children
(a list
object), and the type class of g
is a record
. Depending on which item of children
is being examined, I'm assuming that some of those items are records that do contain a property identified by annotation
, and some of those items are records that do not contain such a property.
However, consider the following record
that results from this merge:
g & {annotation:missing value}
Here are the two possible scenarios:
g
is a record
that already contains a property identified as annotation
, e.g.:
set g to {cannotation:"doe", bannotation:"ray", annotation:me}
g & {annotation:missing value} --> {cannotation:"doe", bannotation:"ray", annotation:«script»}
set theAnnotation to annotation of (g & {annotation:missing value})
--> «script» (i.e. me)
OR:
g
is a record
that in which the property identifier annotation
does not exist, e.g.:
set g to {doe:"a deer", ray:"a drop of golden sun"}
g & {annotation:missing value} --> {doe:"a deer", ray:"a drop of golden sun", annotation:missing value}
set theAnnotation to annotation of (g & {annotation:missing value})
--> missing value
Therefore, for every place in your scripts where try...end try
has been used to catch non-occurrences of properties inside a record
data structure, simply delete the try
blocks, and wherever you are assign values read from speculative property values, artificially insert default values you can then test for and will know whether or not the value came from your DEVONthink source or from your brain:
tell application id "DNtp"
repeat with g in (children of root of (think window 1))
set theAnnotation to annotation of (g & {annotation:false})
if theAnnotation ≠ false then exit repeat
end
end tell
1This isn't in any way meant to suggest his solution isn't viable. If DEVON returns collections that are not de-referenced--and it very well may do--these can be operated upon as a whole, without looping through individual items, and he, of course, uses DEVON. But the situation I hopefully address above is one that arises much more commonly, and will also work here.
Upvotes: 1
Reputation: 3444
If you do
tell application id "DNtp"
annotation of children of root of (think window 1)
end tell
You'll get a list containing annotations and if those are missing, missing value
s, like:
--{missing value, missing value, missing value, «class DTcn» id 49 of «class DTkb» id 1, missing value}
The problem you describe in DEVONthink (of AS ignoring a declared variable during compile time) is a problem I've seen in other apps, too (but it's fairly rare).
If you want to check for the existence of a property, what usually works (and I've tested this with DEVONthink3) is to use exists
, like:
if (exists annotation of g) then
Which will return true or false as you would expect. Not sure how you'd use that in the way you first posted, but I don't really know all the steps you're taking, so ....
I hope this helps
Upvotes: 4