###Making AppleScript Records Dynamic using ASObjc
NOTE: This post started out as a response to this script posted by @ComplexPoint (Rob):
Listing record keys in “Execute an AppleScript” actions
Since it evolved into a complete solution, and a reusable method, it has been moved to a new topic.
[quote="JMichaelTX, post:2, topic:4080"]
Can you help us with the next step: Getting the value from the record when the key is in a variable:
[/quote]
[quote="ComplexPoint, post:3, topic:4080"]
The next step is probably to switch to JavaScript, in which querying a dictionary is rather simpler:
[/quote]
JavaScript does offer a number of advantages in using "records" (JS objects) and arrays.
But if one needs to stay in AppleScript, then here's a solution that is not all that complex, if you understand ASObjC (which I barely do).
But thanks to Shane Stanley's great book:
[Everyday AppleScriptObjC, Third Edition](http://www.macosxautomation.com/applescript/apps/everyday_book.html)
I have been able to cobble together a decent solution, building on @ComplexPoint's original script.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
####Background
Using native AppleScript, you cannot dynamically address records, using a variable for the key. For example, this does NOT work:
```applescript
set keyName to "City"
set somevalue to keyName of myRec ## FAILS
--- Instead your must:
set somevalue to City of myRec ## Works
```
The below script solves this issue.
###Script to Make AppleScript Records Dynamic
Ver 1.1.2 (updated 2016-06-13 13:14 CT)
<img src="/uploads/default/original/2X/9/9fa034801953dfe7d1745afcb7087c7530a06e23.gif" width="70" height="17">
I just got feedback from Shane on a better method for dealing with conversion of types between ASObjC and AppleScript. See comments at bottom of script.
```applescript
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
set myRec to {SomeNumber:3.14, |name|:"nemo", address:"Tokyo", language:"Latin", vehicle:"tandem", SomeList:{"item1", "item2", "item3"}}
set myNumber to my getRecValue("SomeNumber", myRec)
--> 3.14
set myList to my getRecValue("SomeList", myRec)
--> {"item1", "item2", "item3"}
--- GET ALL KEYS IN RECORD ---
set keyList to my getRecKeyList(myRec)
--- GET VALUES FOR ALL KEYS IN RECORD ---
set AppleScript's text item delimiters to ", "
repeat with oKey in keyList
set keyStr to text of oKey
set valueOfKey to my getRecValue(keyStr, myRec)
log (keyStr & ": Class: " & (class of valueOfKey) & " Value: " & valueOfKey)
end repeat
--~~~~~~~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on getRecKeyList(pRecord)
------------------------------------------------------------
(*
PARAMETER: pRecord -- AppleScript Record
RETURNS: List of text items of Keys in Record
------------------------------------------------------------
*)
return ¬
(current application's NSDictionary's ¬
dictionaryWithDictionary:pRecord)'s allKeys() as list
end getRecKeyList
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on getRecValue(pKeyStr, pRecord)
------------------------------------------------------------
(*
VER: 1.1.2 2016-06-13
PARAMETERS:
• pKeyStr : Record Key (string)
• pRecord : Record to be searched
RETURNS: Value for Specified Key (in class of that value)
• This can be text, number, list, record, whatever
------------------------------------------------------------
*)
local theDict, theResult, tempArray
set theDict to current application's NSDictionary's dictionaryWithDictionary:pRecord
set theResult to theDict's objectForKey:pKeyStr
--- Convert ASObjC Class of theResult to AppleScript Class ---
-- This covers text, numbers, lists, records, whatever,
-- including missing value
-- (per Shane Stanley 2016-06-13)
set tempArray to current application's NSArray's arrayWithArray:{theResult}
return item 1 of (tempArray as list)
end getRecValue
(*
NOTE FROM SHANE STANLEY (2016-06-13) (paraphrased)
Instead of checking for class, use this, which also handles missing value:
set theResult to theDict’s objectForKey:pKeyStr
set someArray to current application’s NSArray’s arrayWithArray:{theResult}
return item 1 of (someArray as list)
What this does is makes a single-item array containing theResult.
When that’s converted to an AppleScript list, the item within it
will also be converted to an AppleScript item if it can.
So this covers all the bridgeable AS classes
– text, numbers, lists, records, whatever [including missing value]
You then extract the item from the list.
*)
```
###Results:
```applescript
(*language: Class: text Value: Latin*)
(*SomeNumber: Class: real Value: 3.14*)
(*vehicle: Class: text Value: tandem*)
(*SomeList: Class: list Value: item1, item2, item3*)
(*name: Class: text Value: nemo*)
(*address: Class: text Value: Tokyo*)
```
Rob, thanks for getting this topic started.