coding challenge: accessing a slot of an object using a variable

Anyone know how to code this in Applescript?

I want to set a slot of an iTunes track (e.g., name, date, genre, year) to a particular value. I want the value specified as a variable; this part’s easy. Something like this would work:
set slotVal to “The Pretty Impressives”
set name of cTrack to slotVal

However, I also want the slot that I’m accessing in the iTunes track to be a variable. Specifically, I was hoping code like this would work:
set slotName to “name”
set slotVal to “The Pretty Impressives”
set slotName of cTrack to slotVal

But it breaks. It looks like I need to do some kind of type casting for ‘slotName’ (it shouldn’t be a string). Sorry, I’m used to coding in Lisp and Matlab, which have easy ways of doing stuff like this… and I would hate to have to have a bunch of clunky case statements like:

if slotName=“name”
set name of cTrack to slotVal
elseif slotName=“date”

end if

I’d like to do it all in one line: set slotName of cTrack to slotVal…

Any ideas???

Thanks,
-Clayton

Hi,

indirect addressing is not possible directly in AppleScript.
The only way is to use second level evaluating, here a simple example


property pList : {"name", "album", "genre", "year"}

set theTrack to "file track 1 of library playlist 1"
repeat with theProperty in pList
	display dialog (getValue(theTrack, theProperty))
end repeat

on getValue(t, p)
	return run script "tell application \"iTunes\" to get " & p & " of " & t
end getValue

So, I could do:
set slotName to “name”
set slotVal to “The Pretty Impressives”
run script "tell appliction "iTunes" to set " & slotName " of " & cTrack & " to " & slotVal

It seems that the trick here is to place the command: set slotName of cTrack to slotVal inside a ‘run script’ command. I’m not on a mac now, or I’d try it, but this looks promising!

Nice hack; This ‘run script’ solution is essentially equivalent to using an ‘eval’ command in Lisp. And with an ‘eval’-like command, you’re free to do all sorts of other cool stuff during run time…

Any other ideas? How bout’ a direct typecast solution?

If cTrack is a string, yes.

Which part of “indirect addressing is not possible” is unclear? :wink:
You can not put keywords into a variable, because AppleScript can’t recompile at runtime (exception 2nd level evaluation)

By 2nd level evaluation, you mean the ‘run script’ command, right? Yeah, this is just like an ‘eval’ command in lisp.

A bit of an issue still though, as my ‘cTrack’ has already been evaluated (i.e., it’s a variable that references a track object in iTunes).

Am I stuck? Is there a way to remap the ‘cTrack’ object back to a string that, when evaluated, accesses that same object? This would be really cool btw if AppleScript could do this.

I’m guessing AppleScript can’t do this remapping though, so I’ll have to rewrite a bit of my code to get an unevaluated string version of ‘cTrack’…

Unless you’ve got any more clever ideas…

-Clayton

every track has an unique database ID.
You can reference a track by this ID


tell application "iTunes" to set UID to database ID of some track of library playlist 1
run script "tell application \"iTunes\" to get name of 1st track of library playlist 1 whose database ID is " & UID

Actually you can also use something like this, it’s much faster (and more reliable) than the run script command


set variableList to {"The Pretty Impressives", "The famous Album", 2009, "Rock"}
tell application "iTunes"
	tell cTrack to set {its name, its album, its year, its genre} to variableList
end tell

I can’t do this b/c the ‘variableList’ that’s being passed to this function doesn’t always contain all the same tags (some have only year and genre, some have artist, name, genre, etc…). So I’m once again in the same boat since I can’t write ‘its name, its album, its year, its genre’ ahead of time…

But I like this approach:

So, I could do something like this:
set slotName to “name”
set slotVal to “The Pretty Impressives”
set cTrackUID to database ID of cTrack
run script "tell appliction "iTunes" to set " & slotName " of " & “(” & "1st track of library whose database ID is " & cTrackUID & “)” & " to " & slotVal

Or, can I even do this:

run script “tell application "iTunes" to set” & slotName " of " & “(” & “1st track of library whose database ID is (database ID of cTrack)” & “)” & " to " & slotVal

If it can do the latter one as well, this would imply that, when doing a second-level eval, Applescript has access to the current variable state (i.e., it can see the object cTrack, defined in the root Applescript, but not in the second-level eval).

If it can’t ‘see’ cTrack, can I just pass cTrack in as a variable in the run script command?

-Clayton

Yes

Yes, the result if the variable expresssion must be something which can be coerced to string

no, an iTunes track is an element, it contains properties and other elements.
The run script command can only handle text

Just to be clear, when a 2nd level run script command evaluates it’s string expression, it can see all variables defined in the 1st level run script command (e.g., cTrack)?

If this is the case, then ‘run script’ behaves exactly like an eval command in lisp; and if that’s the case, I’m really starting to like Applescript :slight_smile:

As mentioned above, the run script command can handle only text.
This does NOT work


tell application "iTunes" to set cTrack to some track of library playlist 1
run script "tell application \"iTunes\" to get name of " & cTrack

Ahh… so the easy way to do this came to me.

I have this:

tell application “iTunes” to set cTrack to some track of library playlist 1
set slotName to “name”
set slotVal to “The Pretty Impressives”

And I can’t do this:

run script "tell application "iTunes" to set " & slotName & " of " & cTrack & " to " & slotVal

But I can do this:

run script "tell application "iTunes" to set " & slotName & " of cTrack to " & slotVal

No need to do the UID thing if I this run script command coerces the ‘cTrack’ piece of the string to the object cTrack

Seems to be a very readable and direct solution…

Thanks for your help on this one!

-Clayton

This line doesn’t work either, because a second level applescript CANNOT see variables defined in the first level:
run script "tell application "iTunes" to set " & slotName & " of cTrack to " & slotVal

So, to get this run script program to see the ‘cTrack’ object, you have to pass it in as a parameter. This code works (tested on PPC running Leopard):
run script (“on run{cTrack}
set " & slotName & " of cTrack to "” & slotVal & “"
end”) with parameters {cTrack}

The carriage returns matter, so be careful if you’re going to do something like this.

Thanks to the following tread: http://macscripter.net/viewtopic.php?id=10445 for helping me put this all together.

The solution above is a way to write a lispy-style eval command in Applescript. Although the other macscripter thread advised against doing this, I think quite the alternative; since Applescript is cool enough to provide this functionality, and using eval-style commands gives you great power, I say go for it, as long as you know what you’re doing.

-Clayton