New AppleScript projects


(Jim Underwood) #21

So that we can have a true apples-to-apples comparison, could someone post a link to a test file that we all could use to test against?

I am very curious how well the JXA JavaScript RegEx engine will perform against the same test file. So far I have found it to both very fast, and very easy to use.

(Shane Stanley) #22

We’re not really comparing regex engines, though – it’s a question of how fast it can be done in a call from an AppleScript. I suspect the overhead of calling JXA from AppleScript will swamp the time actually taken to do the search and replace.

(Jim Underwood) #23

Interesting perspective.

I would NOT call JXA from AppleScript.
I would use JXA directly.

For a fair, complete test, it would need to include reading the file, making the changes, and writing to a new file.

(Shane Stanley) #24

Well the topic is “New AppleScript projects”, so it seems a reasonable perspective :slight_smile:

If JXA is your preference, and there’s no AppleScript involved, I’m not sure why you’d use anything else.

But if you want to post code equivalent to mine, I’ll be glad to test it on the same file and Mac. However, I don’t expect much difference simply because I suspect the read/write is what takes more of the time. (And it would need timing code.)

(Ed Stockly) #25

You guys are great! Thanks so much for all the responses. I’ll be pounding away at these for the next few weeks (something to keep my mind off the hand basket we’re all heading to hell in these days).

As I develop each project I’ll post the scripts and sample files here, or in a public place.


(Stan Cleveland) #26

Hi Shane,

Okay, that’s impressive! You win that challenge.

My test machine is a bit slower: Mac Mini Server (Late 2012), 2.3 GHz Core i7. If run on your iMac, I’d project my ‘sed’ script would take about 2.8 seconds, but that’s still glacial compared to your 0.28 seconds.

My testing led to an observation about SD that surprised me. I ran my script several times with debug mode on and several times with it off. Debug mode execution times ranged 3.92-3.95 seconds, while non-debug mode ranged 4.01 to 4.04 seconds. It’s not much of a difference, but I’d expect debug mode to be slower, not faster. What’s going on?

Stan C.

(Shane Stanley) #27

Script Debugger does try to take the debugging overhead into account. Unfortunately there are complications that mean any values are more indicative than totally accurate. In the real world, timings can differ considerably depending on the host.

(Stan Cleveland) #28

Yes, that makes sense, Shane. Within a particular environment, SD’s timer can show relative speed differences. But it’s a bit like capturing a timestamp to the millisecond—you will get a number, but don’t expect a high degree of precision.

Stan C.

(Shane Stanley) #29

That’s right. I did some further timings, rewriting the code directly in Objective-C. Even putting the search in a loop to perform it 100 times, the results varied between runs by more than 10%. Putting in a search string that isn’t found in the text gives much more consistent times.

Anyway, my conclusion is that calling just the search via AS rather than directly in Objective-C adds maybe a few milliseconds per iteration. That doesn’t strike me as much overhead in the scheme of things.

(Ed Stockly) #30

Is there a recommended file extension for writing lists to files? It just dawned on me that I’m not using any extension. I know they are text files, but they can’t be edited as text files.

Is there a best practice for this?

Would it be possible to set it up so they’ll open in my applet (or in SD as a list) when double clicked?

(Shane Stanley) #31

No, they’re not text files – they’re a kind of binary file. There’s no prescribed extension, but it might be helpful to use something like .data.

(Ed Stockly) #32

I have a syncing question. I had planned to compare script modification dates and if the script on the server was changed after the script on the client mac the server script would replace the client script.

The problem is that with AppleScript any time you run a script that has globals or properties (and most of mine do) that can change the modification date. So it’s very possible that the user could end up missing updates.

Any suggestions?

(Shane Stanley) #33

Use version numbers. If they’re not applets, use .scptd files.


Shane’s suggestion is a very good but if for some reason if that causes a problem I have sometimes used the spotlight comments field. It can be easily set with a script and can be read from a script and from finder. But unless Shane’s suggestion causes some kind of a problem I’d use his suggestion. It is reliable and pretty tamper proof by someone in Finder. I’ve never seen any other type of version control used in AppleScript except the version is put in the name, using the comments field or version numbers.


(Jim Underwood) #35

Also works with just plain .scpt files:

property version : "1.0"



How does this work? I tried the script:

set ThePath to "Bills second iMac HD:Users:bill:Desktop:untitled folder 30:Untitled.scpt"
tell application "Finder"
	set version of (item ThePath) to 1.0
end tell
I just got the error, "Finder got an error: Can’t set version of item "Bills second iMac HD:Users:bill:Desktop:untitled folder 30:Untitled.scpt" to 1.0."  I'm curious what did you use for to script to change it.

However using the version control built into script debugger seems pretty convent.


(Shane Stanley) #37

That’s true, but they then don’t show up in Get Info windows. The only access is to load the scripts.

Mind you, the Finder and System Events seem brain dead scripting the property with bundles too.

(Ed Stockly) #38

Well nothing is ever easy, is it?

I downloaded a third party syncing app, but it has the same issue with modification dates changing due to AppleScript’s saving when run.

I was going to try changing the creation date when I update files, but you can’t do that in Finder or System Events. Is there a shell that does that? (I’m also going to look at the rsync shell)

Meantime I’m going to try two options: Version; and if that’s not fast reliable I’ll build data files that track the changes made to the source scripts on the server and the local scripts locally. (The advantage of that is that the client mac can simply compare the network file to the local file to know if there are any updates and which scripts need updates.) The file will simply indicate the last time any specific file was updated, and if the last update on the server is newer than the client it will change it.

(Shane Stanley) #39

For apps, getting the version is dead simple:

set myVersion to version of application (path to me as text)
set masterPath to "Macintosh HD:Users:shane:Desktop:With version bundle"
set currentVersion to version of application masterPath
considering numeric strings
	if myVersion < currentVersion then
	end if
end considering

For script bundles, you do exactly the same – just pretend they’re apps.


Yes you can change both modification and creation dates with a shell script. I through together a quicky script for this. It’s no eloquent but it shows how to do it. It’s a single SetFile command in terminal so the shell script is very simple.

Well here’s the script:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on SecondsToTime(TheSeconds, DesiredDecimalPlaces)
	if (TheSeconds > 86400) then -- 86400 seconds in a day
		set TheTime to MakeFixedDecimalPlaces((TheSeconds / 86400), 2) & " days"
	else if (TheSeconds > 3600) then -- 3600 seconds in an hour
		set TheTime to MakeFixedDecimalPlaces((TheSeconds / 3600), 2) & " hours"
	else if (TheSeconds > 60) then -- 60 seconds in an hour
		set TheTime to MakeFixedDecimalPlaces((TheSeconds / 60), 2) & " minutes"
		set TheTime to MakeFixedDecimalPlaces(TheSeconds, 2) & " seconds"
	end if
	return TheTime
end SecondsToTime

on MakeFixedDecimalPlaces(TheNum, DesiredDecimalPlaces)
	local TheNumStr
	local ReverseStr
	local TheOffest
	local PadStr
	local ZeroString
		if (DesiredDecimalPlaces = 0) then
			-- Just return integer part of number
			return (TheNum div 1) as string
		else if (TheNum < 0) then
			display dialog "TheNum in MakeFixedDecimalPlaces was a negative number." buttons {"OK"} default button "OK" giving up after 3 with title "Error"
			-- Signal error
			return "?"
		else if (DesiredDecimalPlaces < 0) then
			display dialog "DesiredDecimalPlaces was a negative number." buttons {"OK"} default button "OK" giving up after 3 with title "Error"
			-- Signal error
			return "?"
		end if
		set TheNumStr to TheNum as string
		if ((offset of "." in TheNumStr) = 0) then
			set ZeroString to strings 1 thru DesiredDecimalPlaces of "000000000000000"
			return TheNumStr & "." & ZeroString
		end if
		set ReverseStr to ((reverse of characters of TheNumStr) as string)
		-- Find the offset of the period character
		set TheOffest to offset of "." in ReverseStr -- Only returns positive numbers or zero
		if (TheOffest = 0) then
			set ActualDecimalPlaces to 0
			-- Subtract 1 because when no descimal places then have to suctract the space the "." usualy takes up
			set ActualDecimalPlaces to TheOffest - 1
		end if
		if (ActualDecimalPlaces = DesiredDecimalPlaces) then
			return TheNumStr
		else if (ActualDecimalPlaces < DesiredDecimalPlaces) then
			-- Pad end of TheNumStr with "0"
			set NumOfZerosToAppend to DesiredDecimalPlaces - ActualDecimalPlaces
			set ZeroString to strings 1 thru NumOfZerosToAppend of "000000000000000"
			return TheNumStr & ZeroString
			-- ActualDecimalPlaces > DesiredDecimalPlaces
			-- Cut characters off end of string
			set NumOfCharsToCutOff to ActualDecimalPlaces - DesiredDecimalPlaces
			return strings 1 thru (-1 * NumOfCharsToCutOff - 1) of TheNumStr
		end if
	on error errMsg number errNum
		display dialog "Error " & (errNum as string) & " occured." & return & return & errMsg ¬
			with title "Error"
		-- Signal error
		return "?"
	end try
end MakeFixedDecimalPlaces

on TwoDigitNum(TheNum)
	if (length of (TheNum as string) = 1) then
		set TheNum to " " & TheNum
	end if
	return TheNum
end TwoDigitNum

on FormatedDateString(TheDate)
	set DateString to "'" & TwoDigitNum(((month of TheDate as number) as string)) & "/"
	set DateString to DateString & TwoDigitNum(((day of TheDate as number) as string)) & "/"
	set DateString to DateString & TwoDigitNum(((year of TheDate as number) as string)) & " "
	set DateString to DateString & time string of TheDate & "'"
	return DateString
end FormatedDateString

tell application "Finder"
	set TheSelection to selection
	set NumberSelected to count TheSelection
	if (NumberSelected ≠ 1) then
		display dialog "Exactly 1 file must be selected in Finder." buttons {"Cancel", "OK"} default button "OK" with title "error"
		return false
	end if
	set TheItem to item 1 of TheSelection
	if ((class of TheItem) = folder) then
		display dialog "A Folder can not be selected in Finder." buttons {"Cancel", "OK"} default button "OK" with title "error"
		return false
	end if
	set PosixFilePath to POSIX path of (TheItem as string)
end tell

set CreationDateStr to FormatedDateString(current date)
set ModDateStr to FormatedDateString(current date)

do shell script "SetFile -d " & CreationDateStr & " \"" & PosixFilePath & "\"" --change the creation date of the file to the current date
do shell script "SetFile -m " & ModDateStr & " \"" & PosixFilePath & "\"" --change the modification date of the file to the current date

Sorry, I didn’t have time to clean it up before sending but I have to get back to what I was doing. You can change modification or creation date or both.