23
\$\begingroup\$

For the sake of full disclosure, this was written with bananas, not apples. The doctor may not be kept away.

With AppleScript highlighting:

Cropped screenshot of the code in an IDE

For Copy&Pasting:

activate application "TextEdit"
tell application "System Events"
    repeat until first window of application "TextEdit" exists
        tell application "TextEdit" to make new document at the front
        delay 1.0E-3
    end repeat
    repeat until process "TextEdit" is frontmost
        set frontmost of process "TextEdit" to true
        delay 1.0E-3
    end repeat
    set focused of first window of process "TextEdit" to true

    repeat with i from 1 to 100
        if i mod 15 is 0 then
            keystroke "FizzBuzz"
            keystroke return
        else if i mod 3 is 0 then
            keystroke "Fizz"
            keystroke return
        else if i mod 5 is 0 then
            keystroke "Buzz"
            keystroke return
        else
            keystroke i
            keystroke return
        end if
    end repeat
end tell

I borrowed the logic for appropriately waiting for "TextEdit" to be ready to receive text from this excellent Code Review answer.

I feel like I want to write functions... but I don't know what's available in AppleScript for modularizing code... err script... I'm just getting my toes wet here.

\$\endgroup\$
17
\$\begingroup\$

It may be fun watching it type out FizzBuzz, but interacting with the UI directly has its pitfalls. For example, if the user focuses a different application while your script is running, you will now be typing in the wrong place; and if you refocus the application, that could be annoying.

Fortunately, there is a better way. Rather than activating the application, waiting until a window appears, and making the window frontmost, you could just…

tell application "TextEdit" to set text of first document to "Hello, world!"

This is much less problematic. The only issue is if TextEdit is already open, in which case it will overwrite the existing document. In that case, you could use

tell application "TextEdit" to set text of (make new document) to "Hello, world!"

Either way, you’re not interacting directly with the UI any more, which eliminates a lot of potential problems.

The actual meat of the FizzBuzz implementation (barring the use of keystroke) looks fine, although you might consider something like keystroke "FizzBuzz" & return rather than keystroke "FizzBuzz" and separately keystroke return.

| improve this answer | |
\$\endgroup\$
11
\$\begingroup\$

The main problem that I see is the lack of separation of concerns. The FizzBuzz code has no business being run in the System Events context, and it ought to reside in its own handler.

to fizzbuzz from low to high
    repeat with i from low to high
        if i mod 15 is 0 then
            output("FizzBuzz")
        else if i mod 3 is 0 then
            output("Fizz")
        else if i mod 5 is 0 then
            output("Buzz")
        else
            output(i)
        end if
    end repeat
end fizzbuzz

I've factored out the keystroke calls as well, since they looked repetitive. Since you opted to use the simulated keystroke option to output the text instead of just telling application "TextEdit" to set the text of the first document to the fizzBuzzOutput, you really ought to go all the way and make it type out slowly, like in the movies.

on output(something)
    tell application "System Events"
        repeat with c in (something as string)
            keystroke c
            delay 0.05
        end repeat
        keystroke return
    end tell
end output

With those two handlers in place, you would call

tell application "System Events"
    repeat until first window of application "TextEdit" exists
        tell application "TextEdit" to make new document at the front
        delay 1.0E-3
    end repeat
    repeat until process "TextEdit" is frontmost
        set frontmost of process "TextEdit" to true
        delay 1.0E-3
    end repeat
    set focused of first window of process "TextEdit" to true
end tell
fizzbuzz from 1 to 100

Note that there doesn't seem to be any need to tell application "TextEdit" to activate.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.