Yes, gIntTodayYear
is a global variable and is set outside of the handler. Sorry, I should have mentioned this.
Yes, alone it runs just fine. It also runs fine from within a Tell
block as demonstrated in this stub code:
-- Declare required resouces
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
global gIntTodayYear
on run
--
-- Configuration
set dateToday to current date
log "dateToday = " & dateToday
set gIntTodayYear to (year of (dateToday))
log "gIntTodayYear = " & gIntTodayYear
--
--
tell application "Contacts"
--
-- Default time out is 2 minutes which may not be long enough for a large number of greetings.
set blnIsDead to false
set dateWedding to date "Friday, June 2, 2000 at 12:00:00 AM"
set blnSendAnniversaryGreeting to true
if not blnIsDead then
set blnHasAppropriateEmail to true
if blnHasAppropriateEmail then
set dateBirthday to date "Saturday, June 2, 1900 at 12:00:00 AM"
set blnSendBirthdayGreeting to true
if blnSendBirthdayGreeting or blnSendAnniversaryGreeting then
if blnSendBirthdayGreeting then
try
set intYearsOld to my intYearsSince(dateBirthday)
on error
log "birthday error"
end try
end if
if blnSendAnniversaryGreeting then
try
set intYearsSinceWedding to my intYearsSince(dateWedding)
on error
log "anniversary error"
end try
end if
end if
end if
end if
end tell
end run
on intYearsSince(theDate)
(*
Dates specified with just a month and day use the year 1604.
*)
log "Entered intYearsSince"
set intYear to year of theDate as integer
log "theDate = " & theDate
log "intYear = " & intYear
log "gIntTodayYear = " & gIntTodayYear
if intYear is less than 1605 then
set intReturnValue to 0
else
set intReturnValue to gIntTodayYear - intYear
end if
log "Exit intYearsSince"
return intReturnValue as integer
end intYearsSince
The stub script above is a stripped down version of the more complex script I’m having a problem with, which is shown at the end of this post.
This more-complex script compiles just fine but it generates this runtime error:
From what I’ve read, this Execution Error often is the result of referring to a handler within a tell
block and failing to preface the handler’s name with the keyword my
; failure to use my
implies that the handler’s name is a reference to an object in the tell
block’s application
, which does not exist so a runtime error results.
The bottom line is that for some reason, the tell
block in my complex script below doesn’t see the handler and so it’s looking for an application
object named intYearsSince
instead.
Is there a way to use Script Debugger to show an object model of the script at runtime?
Anyway, I can’t figure out why the script is mistaking intYearsSince
for an object instead of a handler.
What is it about my complex script that prevents seeing that intYearsSince
is a handler?
Sorry this script demonstrating the problem is so long. So far, my efforts at removing code incrementally to figure out what trips the problem have not been fruitful.
Thank you for your help.
--
-- Declare global variables
global gStrBodyMessage, gStrBlankLine, gStrNewline, gIntTodayYear
--
-- Declare required resouces
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
on intYearsSince(theDate)
(*
Dates specified with just a month and day use the year 1604.
*)
log "Entered intYearsSince"
set intYear to year of theDate as integer
log "theDate = " & theDate
log "intYear = " & intYear
log "gIntTodayYear = " & gIntTodayYear
if intYear is less than 1605 then
set intReturnValue to 0
else
set intReturnValue to gIntTodayYear - intYear
end if
log "Exit intYearsSince"
return intReturnValue as integer
end intYearsSince
on run
--
-- Configuration
set strSmartGroupForPeopleHavingBirthdayOrAnniversaryToday to "Greeting"
set strContactDateLabelAnniversary to "Anniversary"
set strContactEmailLabelHome to "home"
set strContactEmailLabelWork to "work"
set strContactEmailLabelSchool to "school"
set strContactDateLabelDeath to "death"
set gStrBodyMessage to "I hope that you have a special celebration planned for today."
set gStrBodySignature to "- nello"
set strOccasionBirthday to "Birthday"
set strOccasionAnniversary to "Anniversary"
set strOccasionBirthdayEmoji to "🎈"
set strOccasionAnniversaryEmoji to "🎂"
set intTimeoutSeconds to 500
set blnDebug to false
--
-- Constants
set intTimeoutSeconds to 500
set dateToday to (current date)
set strTodayMonthDay to strMonthDay(dateToday)
set gIntTodayYear to (year of (dateToday)) as integer
set strBodyMessage to "I hope that you have a special celebration planned for today."
set strLF to ASCII character 10
set strCR to ASCII character 13
set gStrNewline to strCR & strLF
set gStrBlankLine to gStrNewline & gStrNewline
--
-- variables
set blnIsDead to missing value
set dateWedding to missing value
set strDateLabel to missing value
set blnSendAnniversaryGreeting to missing value
set blnHasAppropriateEmail to missing value
set strEmailName to missing value
set blnSendBirthdayGreeting to missing value
set blnSendAnniversaryGreeting to missing value
set dateBirthday to missing value
set strEmailAddress to missing value
set intYearsSince to missing value
--
-- Begin test stub
set dateTest to date "Friday, June 3, 2022 at 12:00:00 AM"
set strTodayMonthDay to my strMonthDay(dateTest)
set gIntTodayYear to (year of (dateTest)) as integer
set blnDebug to true
-- End test stub
--
tell application "Contacts"
--
-- Default time out is 2 minutes which may not be long enough for a large number of greetings.
with timeout of intTimeoutSeconds seconds
--
-- Get list of people with birthdays or anniversaries recorded in Contacts
set peopleToCheck to people of group strSmartGroupForPeopleHavingBirthdayOrAnniversaryToday
repeat with thePerson in peopleToCheck
if blnDebug then
log "Name = " & name of thePerson
end if
-- Initialize variables for each person.
set blnIsDead to false
set dateWedding to missing value
set blnSendAnniversaryGreeting to false
set blnSendBirthdayGreeting to false
set blnHasAppropriateEmail to false
--
-- Check custom dates to: (1) see whether person is dead, and (2) get anniversary data
repeat with theDate in custom dates of thePerson
set strDateLabel to label of theDate
ignoring case
if strDateLabel contains strContactDateLabelDeath then
--
-- Assume that person is dead regardless of value of date
set blnIsDead to true
else if strDateLabel contains strContactDateLabelAnniversary then
set dateWedding to value of theDate
if dateWedding is not missing value then
set blnSendAnniversaryGreeting to my strMonthDay(dateWedding) is equal to strTodayMonthDay
end if
end if
end ignoring
end repeat
if not blnIsDead then
--
-- Check whether person's birthday is today
set dateBirthday to birth date of thePerson
if dateBirthday is missing value then
set blnSendBirthdayGreeting to false
else
set blnSendBirthdayGreeting to my strMonthDay(dateBirthday) is equal to strTodayMonthDay
end if
--
-- Check whether any greeting should be drafted.
if blnSendBirthdayGreeting or blnSendAnniversaryGreeting then
--
-- Check whether person has an appropriate email address
set strEmailHome to missing value
set strEmailWork to missing value
set strEmailSchool to missing value
ignoring case
repeat with theEmail in every email of thePerson
set strEmailLabel to label of theEmail
--
-- Check for a home email.
if strEmailLabel contains strContactEmailLabelHome then
set strEmailHome to value of theEmail
--
-- Found first home email address so quit looking at others
exit repeat
else if strEmailWork is equal to missing value then
--
-- Work email not found yet so check this one.
if strEmailLabel contains strContactEmailLabelWork then
set strEmailWork to value of theEmail
end if
else if strEmailSchool is equal to missing value then
--
-- School email not found yet so check this one.
if strEmailLabel contains strContactEmailLabelSchool then
set strEmailSchool to value of theEmail
end if
end if
end repeat
end ignoring
set blnHasAppropriateEmail to true
if strEmailHome is not equal to missing value then
set strEmailAddress to strEmailHome
else if strEmailWork is not equal to missing value then
set strEmailAddress to strEmailWork
else if strEmailSchool is not equal to missing value then
set strEmailAddress to strEmailSchool
else
set blnHasAppropriateEmail to false
end if
if blnDebug then
log "blnHasAppropriateEmail = " & blnHasAppropriateEmail
end if
if blnHasAppropriateEmail then
--
-- Extract preferred name for this person.
if nickname of thePerson is not missing value then
set strEmailName to nickname of thePerson
else
set strEmailName to first name of thePerson & last name of thePerson
end if
--
-- Draft birthday greeting, if any.
if blnSendBirthdayGreeting then
set intAge to my intYearsSince(dateBirthday)
my draftEmail(strEmailName, strEmailAddress, intAge, strOccasionBirthday, strOccasionBirthdayEmoji)
end if
--
-- Draft anniversary greeting, if any.
if blnSendAnniversaryGreeting then
try
set intYearsSinceWedding to my intYearsSince(dateWedding)
on error errMsg number errNum
log "errMsg = " & errMsg
log "errNum = " & errNum
-- your error handler code goes here
end try
my draftEmail(strEmailName, strEmailAddress, intYearsSinceWedding, strOccasionBirthday, strOccasionAnniversaryEmoji)
end if
end if
end if
end if
end repeat
end timeout
end tell
end run
on strMonthDay(theDate)
(*
Return theDate's month name and day number as string. (Ignores year and time.)
*)
set strReturnValue to (month of theDate as text) & " " & (day of theDate) as text
return strReturnValue
end strMonthDay
on draftEmail(theName, theEmail, theSubjectYears, theSubjectOccasion, theEmoji)
(*
Create draft email in default mailer.
*)
set theSubject to "Happy "
--
-- A year is NOT required in birth date and anniversary date.
-- A zero indicates that the year is not know and thus
-- the number of years since the occasion is NOT known.
if theSubjectYears is greater than 0 then
--
-- Include the number of years in the subject.
set theSubject to theSubject & theSubjectYears & strOrdinalNumber(theSubjectYears)
end if
set theSubject to theSubject & " " & theSubjectOccasion & " " & theEmoji
set theBody to first word of theName & ":" & gStrBlankLine & gStrBodyMessage & gStrBlankLine & gStrBodySignature
set theURL to "mailto:" & theName & "<" & theEmail & ">?&subject=" & theSubject & "&body=" & theBody
log theURL
open location theURL
end draftEmail
on strOrdinalNumber(theCardinalNumber)
(*
Append an English ordinal suffix to a number and return the result as string.
Author: Nigel Garvey
Source: https://macscripter.net/viewtopic.php?id=20878
*)
set units to theCardinalNumber mod 10
if (units > 3) or ((theCardinalNumber - units) mod 100 is 10) or (units < 1) or (units mod 1 > 0) then
set strOrdinalSuffix to "th"
else
set strOrdinalSuffix to item units of {"st", "nd", "rd"}
end if
set strReturnValue to (theCardinalNumber as string) & strOrdinalSuffix
return strReturnValue
end strOrdinalNumber