Parameter Parsing in AppleScript?

Hello.

I’m the coder of a script that runs inside an IRC Client. That said script accepts parameters which in turn toggle Boolean variables on if they’re included and consequently alter the output of said script.

I currently have a solution working by extensive use of if…then…else clauses and I was trying to find out if there was a simpler way of doing it without having to use said clauses.

Example code follows:


set cmd to "mac cpu ram"
set msg to ""

if cmd contains "mac" then
	set ViewMac to true
end if
if cmd contains "cpu" then
	set ViewCPU to true
end if
if cmd contains "ram" then
	set ViewRam to true
end if

if ViewMac is true then
	set machineName to do shell script "sysctl -n hw.model"
	
	if machineName is "iMac4,1" then
		set MacModel to "iMac (Early 2006)"
	else if machineName is "iMac4,2" then
		set MacModel to "iMac (Mid 2006)"
	else if machineName is "iMac5,2" then
		set MacModel to "iMac (Late 2006 CD)"
	else if machineName is "iMac5,1" then
		set MacModel to "iMac (Late 2006)"
	else if machineName is "iMac6,1" then
		set MacModel to "iMac (24-inch Late 2006)"
	else
		set MacModel to machineName
	end if
	set msg to msg & "Mac: " & MacModel & " - "
end if

if ViewCPU is true then
	set cputype to do shell script "sysctl machdep.cpu.brand_string | awk '{ print $2,$3,$4,$5,$6,$7,$8,$9 }'"
	set msg to msg & "CPU: " & cputype & " - "
end if

if ViewRam is true then
	set memtotal to do shell script "sysctl hw.memsize"
	set AppleScript's text item delimiters to ": "
	set memtotal to text item 2 of memtotal
	set memtotal to memtotal / 1024 / 1024 as integer
	set topresult to do shell script "top -l 1 | head -n 7 | tail -n 1"
	set AppleScript's text item delimiters to ", "
	set memitems to text items of topresult
	set AppleScript's text item delimiters to ""
	set usedmem to text item 4 of memitems
	set AppleScript's text item delimiters to "M"
	set usedmem to text item 1 of usedmem
	
	set mempercent to (usedmem / memtotal) * 100 as integer
	set mempercent to mempercent as text
	set activebar to round (mempercent / 10) rounding to nearest
	set activebar to activebar
	if memtotal ≥ 1024 then
		set memtotal to (memtotal round) / 1024
		set memmeasure to "GiB"
	else
		set memmeasure to "MiB"
	end if
	if usedmem ≥ 1024 then
		set usedmem to usedmem / 1024
		set usedmem to (round (usedmem * 100)) / 100
		set usedmeasure to "GiB"
	else
		set usedmem to (round (usedmem * 100)) / 100
		set usedmeasure to "MiB"
	end if
	set memspeed to do shell script "system_profiler SPMemoryDataType | grep 'Speed:' | awk '{ print $2,$3 }'"
	set AppleScript's text item delimiters to " MHz"
	set memspeed to text item 1 of memspeed
	if memspeed contains "Empty" then
		set AppleScript's text item delimiters to " "
		set memspeed to last text item of memspeed
	end if
	set msg to msg & "RAM: " & usedmem & usedmeasure & "/" & memtotal & memmeasure & " @ " & memspeed & "MHz"
end if

return msg

Example output:
“Mac: MacBookPro7,1 - CPU: Intel(R) Core™2 Duo CPU P8800 @ 2.66GHz - RAM: 1.98GiB/6.0GiB @ 1067MHz”

Model: MacBook Pro
AppleScript: AppleScript 2.2
Browser: Firefox 5.0.1
Operating System: Mac OS X (10.6)

Help? :smiley:

There’s nothing wrong with ‘if.then.else’ clauses and nothing particularly ojectionable about yours. However, the first three ‘if’ statements in your script could be reduced to .

set ViewMac to (cmd contains "mac")
set ViewCPU to (cmd contains "cpu")
set ViewRam to (cmd contains "ram")

. which besides being shorter, sets the variables to ‘false’ if the conditions aren’t met instead of leaving them undefined.

If you know that a variable has a boolean value, you can hinge a condition directly on that boolean instead of testing to see if it’s ‘true’ and hinging the condition on the identical boolean generated. In other words .

if ViewMac is true then

. could simply be:

if ViewMac then

Of course, you could dispense with the first three ‘if’ statements altogether and use their test conditions for the others:

if cmd contains "mac" then
	set machineName to do shell script "sysctl -n hw.model"

	. etc.

You could reduced the size of the long ‘if’ statements by putting their contents into handlers. The ‘if’ statements themselves would then contain just the handler calls. It would look professional, but it would be up to you whether you thought it was worth doing.


set cmd to "mac cpu ram"
set msg to {}

set astid to AppleScript's text item delimiters
if cmd contains "mac" then set end of msg to MacView()
if cmd contains "cpu" then set end of msg to CPUView()
if cmd contains "ram" then set end of msg to RAMView()
set AppleScript's text item delimiters to " - "
set msg to msg as text
set AppleScript's text item delimiters to astid

return msg

on MacView()
	set machineName to do shell script "sysctl -n hw.model"
	
	if machineName is "iMac4,1" then
		set MacModel to "iMac (Early 2006)"
	else if machineName is "iMac4,2" then
		set MacModel to "iMac (Mid 2006)"
	else if machineName is "iMac5,2" then
		set MacModel to "iMac (Late 2006 CD)"
	else if machineName is "iMac5,1" then
		set MacModel to "iMac (Late 2006)"
	else if machineName is "iMac6,1" then
		set MacModel to "iMac (24-inch Late 2006)"
	else
		set MacModel to machineName
	end if
	
	return "Mac: " & MacModel
end MacView

on CPUView()
	set cputype to do shell script "sysctl machdep.cpu.brand_string | awk '{ print $2,$3,$4,$5,$6,$7,$8,$9 }'"
	
	return "CPU: " & cputype
end CPUView

on RAMView()
	set memtotal to do shell script "sysctl hw.memsize"
	set AppleScript's text item delimiters to ": "
	set memtotal to text item 2 of memtotal
	set memtotal to memtotal / 1024 / 1024 as integer
	set topresult to do shell script "top -l 1 | head -n 7 | tail -n 1"
	set AppleScript's text item delimiters to ", "
	set memitems to text items of topresult
	set AppleScript's text item delimiters to ""
	set usedmem to text item 4 of memitems
	set AppleScript's text item delimiters to "M"
	set usedmem to text item 1 of usedmem
	
	set mempercent to (usedmem / memtotal) * 100 as integer
	set mempercent to mempercent as text
	set activebar to round (mempercent / 10) rounding to nearest
	set activebar to activebar
	if memtotal ≥ 1024 then
		set memtotal to (memtotal round) / 1024
		set memmeasure to "GiB"
	else
		set memmeasure to "MiB"
	end if
	if usedmem ≥ 1024 then
		set usedmem to usedmem / 1024
		set usedmem to (round (usedmem * 100)) / 100
		set usedmeasure to "GiB"
	else
		set usedmem to (round (usedmem * 100)) / 100
		set usedmeasure to "MiB"
	end if
	set memspeed to do shell script "system_profiler SPMemoryDataType | grep 'Speed:' | awk '{ print $2,$3 }'"
	set AppleScript's text item delimiters to " MHz"
	set memspeed to text item 1 of memspeed
	if memspeed contains "Empty" then
		set AppleScript's text item delimiters to " "
		set memspeed to last text item of memspeed
	end if
	
	return "RAM: " & usedmem & usedmeasure & "/" & memtotal & memmeasure & " @ " & memspeed & "MHz"
end RAMView

I’m inclined to replace the block which sets the model name with a search of a lookup table.
Any pro’s or cons? For me, that just looks neater, but I don’t know whether there’s any actual gain.
Well, just one: a lookup table is easier to change, with less opportunity for errors (I think).

property machineToModelTable : {{"iMac4,1", "iMac (Early 2006)"}, {"machineName", "macModel"}, {"more key-value pairs"}}

set machineName to "iMac4,1"

set macModel to getValueForKey(machineToModelTable, machineName) --> "iMac (Early 2006)"

on getValueForKey(theTable, keyToFind)
	try
		repeat with aPair in theTable
			set {thisKey, thisValue} to aPair
			if thisKey = keyToFind then return thisValue
		end repeat
	on error
		-- return "unknown", or anything suitable
	end try
end getValueForKey

To compact further:

set macModel to getValueForKey(machineToModelTable, do shell script "sysctl -n hw.model")

Nigel and alastor, many thanks for your replies.

Sadly, I should’ve opened up all “the game” beforehand. Even tho I’ve learned quite some stuff in your post (and the one below it), not all of it is usable (at least not as easily as you put it) because the script I posted was a bit edited so it’d work and run on the script editor. There was a huge chunk of it removed as well since at the moment I thought it would only complicate.

Where in the script I wrote above the cmd variable is defined on the script, in real usage the cmd variable is defined at runtime and if no arguments are passed to the script, then a predefined set of boolean variables are defined and the corresponding output is added to the msg variable and said variable is returned.

The script in it’s entirety is huge, so I don’t know if I can post it here, but I’ll link to a Syntax Highlited version of it on Pastebin.

I’ve added some of the changes I’ve learned from the above two posts, but I’m sure it can be improved further. Don’t know if I should open up another topic so that people can throw their ideas (or contributions with the appropriate mentions of course) and if so, in which section I should open them.

Note that for the script to work as intended, it has certain requirements: Intel Mac, Mac OS X 10.6 or newer, Textual IRC client.

If you pretend to run it on your editor of choice, comment the following bits:
on textualcmd()
end textualcmd

and uncomment the following bit:
set cmd to “”

The output will be a bit messed up due to IRC Specific formatting but it’ll run.

Pastebin link is: Here. Clicky Clicky