Related
I am trying to export reminders data from the Reminders application. The script below will do so, but it takes a very long time (first iteration took 100 minutes, the second iteration is still running).
I have read that sending AppleEvents (in this case around 1000 of them) is what kills performance, but fixes are sparse (I have read about encapsulating the script inside script, end script, and run script but that did not seem to do anything).
A promising but tedious avenue I have not tried is to grab all ten columns separately and unix paste them together.
The real issue is of course looking up every cell of my table one-by-one. How can I just grab all objects (reminders) in rs with all of their detail, by value, and not just a list of references? Then I can parse it how I please.
#!/usr/bin/osascript
set output to "Title,Notes,Completed,Completion Date,List,Creation Date,Due Date,Modification Date,Remind Me Date,Priority\n"
tell application "Reminders"
set rs to reminders in application "Reminders"
repeat with r in rs
set output to output & "\"" & name of r & "\",\"" & body of r & "\",\"" & completed of r & "\",\"" & completion date of r & "\",\"" & name of container of r & "\",\"" & creation date of r & "\",\"" & due date of r & "\",\"" & modification date of r & "\",\"" & remind me date of r & "\",\"" & priority of r & "\"\n"
end repeat
end tell
return output
I'm about a year late, but perhaps someone else will find this solution useful. The trick is to store a reference to the reminders in the variable rs. That way, AppleScript is only having to go through every reminder once to retrieve its properties in the repeat loop.
use application "Reminders"
set text item delimiters of AppleScript to "|"
set output to {{"Title", "Notes", "Completed", "Completion Date", ¬
"List", "Creation Date", "Due Date", "Modification Date", ¬
"Remind Me Date", "Priority"} as text}
set rs to a reference to reminders
repeat with r in (a reference to reminders)
get {name, body, completed, completion date, ¬
name of container, creation date, due date, ¬
modification date, remind me date, priority} ¬
of r
set end of output to the result as text
end repeat
set text item delimiters of AppleScript to "\n"
return output as text
Alternatively, after defining the variable rs, one could get all the properties of all the reminders in one go like this:
set everything to the properties of rs
Then loop through this list instead:
repeat with r in everything
(* same as above *)
.
.
.
I am just trying to log the state of objects throughout the life of my applescript. In other languages, object's toString() methods will render the text equivalent and I can use those. In AppleScript, this does not seem to be the case.
convert applescript object to string (similar to toString)
Will output the finder object (and its properties) to the "Results" window of AppleScript Editor, but only if it is the last statement which gets executed.
If I have a trace() statement (which takes a message for logging purposes):
on trace(message)
do shell script "cat >>~/log/applescript.txt <<END_OF_THE_LOG
" & (message as text) & "
END_OF_THE_LOG"
end trace
and try to log the same object, I get
Can’t make properties of application "Finder" into type text.
I'm open to better ways of logging to a console, but would like to find out how to write an object's properties (like AppleScript Editor does) in the middle of a script for testing either way.
AppleScript doesn't make it easy:
log only logs while running in AppleScript Editor or when running via osascript (to stderr in that case) - the output will be lost in other cases, such as when applications run a script with the NSAppleScript Cocoa class.
log only accepts one argument; while it does accept any object type, it doesn't make it easy to get a meaningful representation of non-built-in types: try log me to get information about the script itself, for instance; frequently, log (get properties of <someObj>) must be used to get meaningful information; note the cumbersome syntax, which is required, because just using log properties of <someObj> typically merely prints the name of the reference form instead of the properties it points to (e.g, log properties of me uselessly outputs just (*properties*)).
In general, AppleScript makes it very hard to get meaningful text representations of objects of non-built-in types: <someObj> as text (same as: <someObj> as string) annoyingly breaks - throws a runtime error - for such objects; try me as text.
Below are helper subroutines that address these issues:
dlog() is a subroutine that combines deriving meaningful text representations of any objects with the ability to write to multiple log targets (including syslog and files) based on a global config variable.
toString() (effectively embedded in dlog()) is a subroutine that takes a single object of any type and derives a meaningful text representation from it.
Tip of the hat to #1.61803; his answer provided pointers for implementing the various logging targets.
Examples:
# Setup: Log to syslog and a file in the home dir.
# Other targets supported: "log", "alert"
# Set to {} to suppress logging.
set DLOG_TARGETS to { "syslog", "~/as.log" }
# Log properties of the front window of frontmost application.
dlog(front window of application (path to frontmost application as text))
# Log properties of own front window; note the *list* syntax for multiple args.
dlog({"my front window: ", front window})
# Get properties of the running script as string.
toString(me) # ->, e.g.: [script name="sandbox"] {selection:insertion point after character 2475 of text of document "sandbox2.scpt", frontmost:true, class:application, name:"AppleScript Editor", version:"2.6"}
See the source-code comments above each subroutine for details.
dlog() source code
# Logs a text representation of the specified object or objects, which may be of any type, typically for debugging.
# Works hard to find a meaningful text representation of each object.
# SYNOPSIS
# dlog(anyObjOrListOfObjects)
# USE EXAMPLES
# dlog("before") # single object
# dlog({ "front window: ", front window }) # list of objects
# SETUP
# At the top of your script, define global variable DLOG_TARGETS and set it to a *list* of targets (even if you only have 1 target).
# set DLOG_TARGETS to {} # must be a list with any combination of: "log", "syslog", "alert", <posixFilePath>
# An *empty* list means that logging should be *disabled*.
# If you specify a POSIX file path, the file will be *appended* to; variable references in the path
# are allowed, and as a courtesy the path may start with "~" to refer to your home dir.
# Caveat: while you can *remove* the variable definition to disable logging, you'll take an additional performance hit.
# SETUP EXAMPLES
# For instance, to use both AppleScript's log command *and* display a GUI alert, use:
# set DLOG_TARGETS to { "log", "alert" }
# Note:
# - Since the subroutine is still called even when DLOG_TARGETS is an empty list,
# you pay a performancy penalty for leaving dlog() calls in your code.
# - Unlike with the built-in log() method, you MUST use parentheses around the parameter.
# - To specify more than one object, pass a *list*. Note that while you could try to synthesize a single
# output string by concatenation yourself, you'd lose the benefit of this subroutine's ability to derive
# readable text representations even of objects that can't simply be converted with `as text`.
on dlog(anyObjOrListOfObjects)
global DLOG_TARGETS
try
if length of DLOG_TARGETS is 0 then return
on error
return
end try
# The following tries hard to derive a readable representation from the input object(s).
if class of anyObjOrListOfObjects is not list then set anyObjOrListOfObjects to {anyObjOrListOfObjects}
local lst, i, txt, errMsg, orgTids, oName, oId, prefix, logTarget, txtCombined, prefixTime, prefixDateTime
set lst to {}
repeat with anyObj in anyObjOrListOfObjects
set txt to ""
repeat with i from 1 to 2
try
if i is 1 then
if class of anyObj is list then
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}} # '
set txt to ("{" & anyObj as string) & "}"
set AppleScript's text item delimiters to orgTids # '
else
set txt to anyObj as string
end if
else
set txt to properties of anyObj as string
end if
on error errMsg
# Trick for records and record-*like* objects:
# We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
try
set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
end try
end try
if txt is not "" then exit repeat
end repeat
set prefix to ""
if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
set prefix to "[" & class of anyObj
set oName to ""
set oId to ""
try
set oName to name of anyObj
if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
end try
try
set oId to id of anyObj
if oId is not missing value then set prefix to prefix & " id=" & oId
end try
set prefix to prefix & "] "
set txt to prefix & txt
end if
set lst to lst & txt
end repeat
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {" "}} # '
set txtCombined to lst as string
set prefixTime to "[" & time string of (current date) & "] "
set prefixDateTime to "[" & short date string of (current date) & " " & text 2 thru -1 of prefixTime
set AppleScript's text item delimiters to orgTids # '
# Log the result to every target specified.
repeat with logTarget in DLOG_TARGETS
if contents of logTarget is "log" then
log prefixTime & txtCombined
else if contents of logTarget is "alert" then
display alert prefixTime & txtCombined
else if contents of logTarget is "syslog" then
do shell script "logger -t " & quoted form of ("AS: " & (name of me)) & " " & quoted form of txtCombined
else # assumed to be a POSIX file path to *append* to.
set fpath to contents of logTarget
if fpath starts with "~/" then set fpath to "$HOME/" & text 3 thru -1 of fpath
do shell script "printf '%s\\n' " & quoted form of (prefixDateTime & txtCombined) & " >> \"" & fpath & "\""
end if
end repeat
end dlog
toString() source code
# Converts the specified object - which may be of any type - into a string representation for logging/debugging.
# Tries hard to find a readable representation - sadly, simple conversion with `as text` mostly doesn't work with non-primitive types.
# An attempt is made to list the properties of non-primitive types (does not always work), and the result is prefixed with the type (class) name
# and, if present, the object's name and ID.
# EXAMPLE
# toString(path to desktop) # -> "[alias] Macintosh HD:Users:mklement:Desktop:"
# To test this subroutine and see the various representations, use the following:
# repeat with elem in {42, 3.14, "two", true, (current date), {"one", "two", "three"}, {one:1, two:"deux", three:false}, missing value, me, path to desktop, front window of application (path to frontmost application as text)}
# log my toString(contents of elem)
# end repeat
on toString(anyObj)
local i, txt, errMsg, orgTids, oName, oId, prefix
set txt to ""
repeat with i from 1 to 2
try
if i is 1 then
if class of anyObj is list then
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}}
set txt to ("{" & anyObj as string) & "}"
set AppleScript's text item delimiters to orgTids # '
else
set txt to anyObj as string
end if
else
set txt to properties of anyObj as string
end if
on error errMsg
# Trick for records and record-*like* objects:
# We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
try
set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
end try
end try
if txt is not "" then exit repeat
end repeat
set prefix to ""
if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
set prefix to "[" & class of anyObj
set oName to ""
set oId to ""
try
set oName to name of anyObj
if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
end try
try
set oId to id of anyObj
if oId is not missing value then set prefix to prefix & " id=" & oId
end try
set prefix to prefix & "] "
end if
return prefix & txt
end toString
Just use the log statement in AppleScript Editor. When you view the results in Applescript Editor, at the bottom of the window press the "Events" button. Normally the "Results" button is pressed and then you only see the result of the last statement as you mention. So change the button to "Events". This will show you everything that is happening as the script runs, and additionally all of the log statements that you put throughout the code too. Note that the log statements do not have to be text. You can log any object.
This is the best way to debug your script and see what is happening. As an example try this and look at the "Events". Realistically thought you don't need a lot of log statements if you view the Events because everything is already logged!
set someFolder to path to desktop
log someFolder
tell application "Finder"
set someItem to first item of someFolder
log someItem
set itemProps to properties of someItem
log itemProps
end tell
Try any of the following:
# echo to file
do shell script "echo " & quoted form of (myObj as string) & ¬
" > ~/Desktop/as_debug.txt"
# write to file
set myFile to open for access (path to desktop as text) & ¬
"as_debug2.txt" with write permission
write myObj to myFile
close access myFile
# log to syslog
do shell script "logger -t 'AS DEBUG' " & myObj
# show dialog
display dialog "ERROR: " & myObj
If what you're trying to log is not text, you might try:
quoted form of (myObj as string)
Here are examples of console log:
set my_int to 9945
log my_int
set my_srt to "Hamza"
log my_srt
set my_array ["Apple","Mango","Banana","Gava"]
log my_array
set my_obj to {"Ali"} as string
log my_obj
do shell script "echo '" & (current date) & ": Found " & Thisfilename & "' >> ~/logs/MyGreatAppleScript.log"
Similar to toString()...
on TextOf(aVariable)
try
return "" & aVariable
on error errm
if errm begins with "Can’t make " ¬
and errm ends with " into type Unicode text." then ¬
return text 12 through -25 of errm
return "item of class " & (class of aVariable) & return & errm
end try
end TextOf
Easiest way to know your values-
display dialog "my variable: " & myVariableName
For scripts that run long and I’m not looking at the screen, I like to have applescript say out loud what it’s doing.
Ie.
say “This is a log statement.”
If inside a tell statement:
tell me to say “This is a log statement.”
I'll try to keep it short and precise.
I really hope you can help me.
I am facing the following problem:
Background:
Workbook with a lot of formulas -> Calculation set to manual
Recalculation takes 5-10 minutes each time
What I want to do:
Generate ranges of data individually for multiple people
then select those ranges, and paste them into the body of an e-mail
send those e-mails one by one
What is the problem?
If I use the "Envelope" method to prepare the e-mails everything is fine until I press send. However, every time I press send excel automatically recalculates the entire Workbook. Obviously I do not want to wait 5-10 minutes to send out each e-mail (always between 10 and 20)
Since I thought it might have to do with the "Envelope" method I decided to switch to creating an e-mail directly via Outlook (outlook object). It worked fine as far as opening the e-mail and sending it without recalculation. However, after the e-mail is opened by Outlook, all(!) formulas in the entire Workbook are set to #Value. This obviously also forces me to recalculate as I cannot create the table for the next person's e-mail.
Does anyone know what is causing the recalculation/error values and what I can do to stop it? I'd be really glad about any suggested solutions.
I am also attaching my code, though I doubt it will help in clearing up the issue
`'DESCRIPTION:
'This routine prepares an e-mail for requesting the progress estimates from the deliverable owners
'1. set all the values based on named ranges in PI and Config sheets
'2. Concatenate all relevant strings to full e-mail text
'3. select PI table
'4. Create e-mail and display
Sub PrepareEmail()
Dim s_EmailAddress As String, s_FirstName As String
Dim s_Email_Greeting As String, s_Email_MainText1 As String, s_Email_MainText2 As String, s_Email_DeadlineRequest As String
Dim s_Email_Deadline As String, s_Email_Subject As String, s_Email_ClosingStatement As String, s_Email_SenderName As String, s_Email_CC As String
Dim s_Email_Full As String
Dim rng_PI_TableValues As Range, rng_PI_TableFull As Range
Dim s_Email_FullText As String
Dim obj_OutApp As Object
Dim obj_OutMail As Object
s_EmailAddress = [ptr_PI_Email]
s_FirstName = [ptr_PI_FirstName]
s_Email_Subject = [ptr_Config_PIEmail_Subject]
s_Email_Greeting = [ptr_Config_PIEmail_Greeting]
s_Email_MainText1 = [ptr_Config_PIEmail_MainText1]
s_Email_MainText2 = [ptr_Config_PIEmail_MainText2]
s_Email_DeadlineRequest = [ptr_Config_PIEmail_DeadlineRequest]
s_Email_Deadline = [ptr_Config_PIEmail_Deadline]
s_Email_ClosingStatement = [ptr_Config_PIEmail_ClosingStatement]
s_Email_SenderName = [ptr_Config_PIEmail_SenderName]
s_Email_CC = [ptr_Config_PIEmail_CC]
'Concatenate full e-mail (using HTML):
s_Email_Full = _
"<basefont face=""Calibri"">" _
& s_Email_Greeting & " " _
& s_FirstName & ", " & "<br> <br>" _
& s_Email_MainText1 & "<br>" _
& s_Email_MainText2 & "<br> <br>" _
& "<b>" & s_Email_DeadlineRequest & " " _
& s_Email_Deadline & "</b>" & "<br> <br>" _
& s_Email_ClosingStatement & "," & "<br>" _
& s_Email_SenderName _
& "<br><br><br>"
'-------------------------------------------------------
Set rng_PI_TableValues = Range("tbl_PI_ProgressInput")
Set rng_PI_TableFull = Union(rng_PI_TableValues, Range("tbl_PI_ProgressInput[#Headers]"))
Application.EnableEvents = False
Application.ScreenUpdating = False
Set obj_OutApp = CreateObject("Outlook.Application")
Set obj_OutMail = obj_OutApp.CreateItem(0)
With obj_OutMail
.To = s_EmailAddress
.CC = s_Email_CC
.Subject = s_Email_Subject
.HTMLBody = s_Email_Full & RangetoHTML(rng_PI_TableFull)
.Display
End With
Application.EnableEvents = True
Application.ScreenUpdating = True
Call update_Status
End Sub
`
If you're using RangeToHTML from Ron de Bruin's website, that's what's causing your problem. That utility is fine if you need perfect fidelity and have a heavily formatted bu otherwise fairly simple range. But if your range has a bunch of dependencies, you'll have problems. It's putting the range into its own workbook, so any formulas that refer to data outside the range get funky.
If you need perfect fidelity, then you're stuck because the only way it will be perfect is by saving the range as HTML and reading that back. But if you don't have a bunch of heavy formatting or you just need a nice looking table, then I suggest you write your own RangeToHTML function that produces the HTML strings.
David McRitchie has some functions that do a pretty good job if you don't want to roll your own. http://dmcritchie.mvps.org/excel/xl2html.htm
Also, I don't know what update_Status does, but if it's causing a recalc, then you have two problems. If that's the case, figure out how to store up all the stuff that update_status does and do it once at the end rather than in the loop.
I am just trying to log the state of objects throughout the life of my applescript. In other languages, object's toString() methods will render the text equivalent and I can use those. In AppleScript, this does not seem to be the case.
convert applescript object to string (similar to toString)
Will output the finder object (and its properties) to the "Results" window of AppleScript Editor, but only if it is the last statement which gets executed.
If I have a trace() statement (which takes a message for logging purposes):
on trace(message)
do shell script "cat >>~/log/applescript.txt <<END_OF_THE_LOG
" & (message as text) & "
END_OF_THE_LOG"
end trace
and try to log the same object, I get
Can’t make properties of application "Finder" into type text.
I'm open to better ways of logging to a console, but would like to find out how to write an object's properties (like AppleScript Editor does) in the middle of a script for testing either way.
AppleScript doesn't make it easy:
log only logs while running in AppleScript Editor or when running via osascript (to stderr in that case) - the output will be lost in other cases, such as when applications run a script with the NSAppleScript Cocoa class.
log only accepts one argument; while it does accept any object type, it doesn't make it easy to get a meaningful representation of non-built-in types: try log me to get information about the script itself, for instance; frequently, log (get properties of <someObj>) must be used to get meaningful information; note the cumbersome syntax, which is required, because just using log properties of <someObj> typically merely prints the name of the reference form instead of the properties it points to (e.g, log properties of me uselessly outputs just (*properties*)).
In general, AppleScript makes it very hard to get meaningful text representations of objects of non-built-in types: <someObj> as text (same as: <someObj> as string) annoyingly breaks - throws a runtime error - for such objects; try me as text.
Below are helper subroutines that address these issues:
dlog() is a subroutine that combines deriving meaningful text representations of any objects with the ability to write to multiple log targets (including syslog and files) based on a global config variable.
toString() (effectively embedded in dlog()) is a subroutine that takes a single object of any type and derives a meaningful text representation from it.
Tip of the hat to #1.61803; his answer provided pointers for implementing the various logging targets.
Examples:
# Setup: Log to syslog and a file in the home dir.
# Other targets supported: "log", "alert"
# Set to {} to suppress logging.
set DLOG_TARGETS to { "syslog", "~/as.log" }
# Log properties of the front window of frontmost application.
dlog(front window of application (path to frontmost application as text))
# Log properties of own front window; note the *list* syntax for multiple args.
dlog({"my front window: ", front window})
# Get properties of the running script as string.
toString(me) # ->, e.g.: [script name="sandbox"] {selection:insertion point after character 2475 of text of document "sandbox2.scpt", frontmost:true, class:application, name:"AppleScript Editor", version:"2.6"}
See the source-code comments above each subroutine for details.
dlog() source code
# Logs a text representation of the specified object or objects, which may be of any type, typically for debugging.
# Works hard to find a meaningful text representation of each object.
# SYNOPSIS
# dlog(anyObjOrListOfObjects)
# USE EXAMPLES
# dlog("before") # single object
# dlog({ "front window: ", front window }) # list of objects
# SETUP
# At the top of your script, define global variable DLOG_TARGETS and set it to a *list* of targets (even if you only have 1 target).
# set DLOG_TARGETS to {} # must be a list with any combination of: "log", "syslog", "alert", <posixFilePath>
# An *empty* list means that logging should be *disabled*.
# If you specify a POSIX file path, the file will be *appended* to; variable references in the path
# are allowed, and as a courtesy the path may start with "~" to refer to your home dir.
# Caveat: while you can *remove* the variable definition to disable logging, you'll take an additional performance hit.
# SETUP EXAMPLES
# For instance, to use both AppleScript's log command *and* display a GUI alert, use:
# set DLOG_TARGETS to { "log", "alert" }
# Note:
# - Since the subroutine is still called even when DLOG_TARGETS is an empty list,
# you pay a performancy penalty for leaving dlog() calls in your code.
# - Unlike with the built-in log() method, you MUST use parentheses around the parameter.
# - To specify more than one object, pass a *list*. Note that while you could try to synthesize a single
# output string by concatenation yourself, you'd lose the benefit of this subroutine's ability to derive
# readable text representations even of objects that can't simply be converted with `as text`.
on dlog(anyObjOrListOfObjects)
global DLOG_TARGETS
try
if length of DLOG_TARGETS is 0 then return
on error
return
end try
# The following tries hard to derive a readable representation from the input object(s).
if class of anyObjOrListOfObjects is not list then set anyObjOrListOfObjects to {anyObjOrListOfObjects}
local lst, i, txt, errMsg, orgTids, oName, oId, prefix, logTarget, txtCombined, prefixTime, prefixDateTime
set lst to {}
repeat with anyObj in anyObjOrListOfObjects
set txt to ""
repeat with i from 1 to 2
try
if i is 1 then
if class of anyObj is list then
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}} # '
set txt to ("{" & anyObj as string) & "}"
set AppleScript's text item delimiters to orgTids # '
else
set txt to anyObj as string
end if
else
set txt to properties of anyObj as string
end if
on error errMsg
# Trick for records and record-*like* objects:
# We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
try
set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
end try
end try
if txt is not "" then exit repeat
end repeat
set prefix to ""
if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
set prefix to "[" & class of anyObj
set oName to ""
set oId to ""
try
set oName to name of anyObj
if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
end try
try
set oId to id of anyObj
if oId is not missing value then set prefix to prefix & " id=" & oId
end try
set prefix to prefix & "] "
set txt to prefix & txt
end if
set lst to lst & txt
end repeat
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {" "}} # '
set txtCombined to lst as string
set prefixTime to "[" & time string of (current date) & "] "
set prefixDateTime to "[" & short date string of (current date) & " " & text 2 thru -1 of prefixTime
set AppleScript's text item delimiters to orgTids # '
# Log the result to every target specified.
repeat with logTarget in DLOG_TARGETS
if contents of logTarget is "log" then
log prefixTime & txtCombined
else if contents of logTarget is "alert" then
display alert prefixTime & txtCombined
else if contents of logTarget is "syslog" then
do shell script "logger -t " & quoted form of ("AS: " & (name of me)) & " " & quoted form of txtCombined
else # assumed to be a POSIX file path to *append* to.
set fpath to contents of logTarget
if fpath starts with "~/" then set fpath to "$HOME/" & text 3 thru -1 of fpath
do shell script "printf '%s\\n' " & quoted form of (prefixDateTime & txtCombined) & " >> \"" & fpath & "\""
end if
end repeat
end dlog
toString() source code
# Converts the specified object - which may be of any type - into a string representation for logging/debugging.
# Tries hard to find a readable representation - sadly, simple conversion with `as text` mostly doesn't work with non-primitive types.
# An attempt is made to list the properties of non-primitive types (does not always work), and the result is prefixed with the type (class) name
# and, if present, the object's name and ID.
# EXAMPLE
# toString(path to desktop) # -> "[alias] Macintosh HD:Users:mklement:Desktop:"
# To test this subroutine and see the various representations, use the following:
# repeat with elem in {42, 3.14, "two", true, (current date), {"one", "two", "three"}, {one:1, two:"deux", three:false}, missing value, me, path to desktop, front window of application (path to frontmost application as text)}
# log my toString(contents of elem)
# end repeat
on toString(anyObj)
local i, txt, errMsg, orgTids, oName, oId, prefix
set txt to ""
repeat with i from 1 to 2
try
if i is 1 then
if class of anyObj is list then
set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}}
set txt to ("{" & anyObj as string) & "}"
set AppleScript's text item delimiters to orgTids # '
else
set txt to anyObj as string
end if
else
set txt to properties of anyObj as string
end if
on error errMsg
# Trick for records and record-*like* objects:
# We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
try
set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
end try
end try
if txt is not "" then exit repeat
end repeat
set prefix to ""
if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
set prefix to "[" & class of anyObj
set oName to ""
set oId to ""
try
set oName to name of anyObj
if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
end try
try
set oId to id of anyObj
if oId is not missing value then set prefix to prefix & " id=" & oId
end try
set prefix to prefix & "] "
end if
return prefix & txt
end toString
Just use the log statement in AppleScript Editor. When you view the results in Applescript Editor, at the bottom of the window press the "Events" button. Normally the "Results" button is pressed and then you only see the result of the last statement as you mention. So change the button to "Events". This will show you everything that is happening as the script runs, and additionally all of the log statements that you put throughout the code too. Note that the log statements do not have to be text. You can log any object.
This is the best way to debug your script and see what is happening. As an example try this and look at the "Events". Realistically thought you don't need a lot of log statements if you view the Events because everything is already logged!
set someFolder to path to desktop
log someFolder
tell application "Finder"
set someItem to first item of someFolder
log someItem
set itemProps to properties of someItem
log itemProps
end tell
Try any of the following:
# echo to file
do shell script "echo " & quoted form of (myObj as string) & ¬
" > ~/Desktop/as_debug.txt"
# write to file
set myFile to open for access (path to desktop as text) & ¬
"as_debug2.txt" with write permission
write myObj to myFile
close access myFile
# log to syslog
do shell script "logger -t 'AS DEBUG' " & myObj
# show dialog
display dialog "ERROR: " & myObj
If what you're trying to log is not text, you might try:
quoted form of (myObj as string)
Here are examples of console log:
set my_int to 9945
log my_int
set my_srt to "Hamza"
log my_srt
set my_array ["Apple","Mango","Banana","Gava"]
log my_array
set my_obj to {"Ali"} as string
log my_obj
do shell script "echo '" & (current date) & ": Found " & Thisfilename & "' >> ~/logs/MyGreatAppleScript.log"
Similar to toString()...
on TextOf(aVariable)
try
return "" & aVariable
on error errm
if errm begins with "Can’t make " ¬
and errm ends with " into type Unicode text." then ¬
return text 12 through -25 of errm
return "item of class " & (class of aVariable) & return & errm
end try
end TextOf
Easiest way to know your values-
display dialog "my variable: " & myVariableName
For scripts that run long and I’m not looking at the screen, I like to have applescript say out loud what it’s doing.
Ie.
say “This is a log statement.”
If inside a tell statement:
tell me to say “This is a log statement.”
What I mean, is if I have this in my clipboard for instance:
"http://farm6.static.flickr.com/5290/5377008438_8e3658d75f_m.jpg"
can I use applescript to change that to
"http://farm6.static.flickr.com/5290/5377008438_8e3658d75f_b.jpg"
(changing the "m" to a "b")
?
This would be handy because then I could just right click/copy the photo url from the thumbnails page without having to drill down. Yes, it's only a few clicks to get from the thumbnails page to the large size, but any I can save would be nice.
Also, could I copy out the photo id so that I can link to the main photo page?
ex:
copy the "5377008438" and paste into a main link "http://www.flickr.com/photos/dbooster/5377008438"
I only say applescript because that comes to mind, but anything that I could call from text expander would work.
Manipulating the URL can be done like this:
set baseURL to "http://farm6.static.flickr.com/5290/5377008438_8e3658d75f_m.jpg"
set modURL to (characters 1 through -6 of baseURL as text) & "b.jpg"
set fileName to last item of (tokens of baseURL between "/")
set photoID to first item of (tokens of fileName between "_")
set mainPhotoPage to "http://www.flickr.com/photos/dbooster/" & photoID
{modURL, fileName, photoID, mainPhotoPage}
on tokens of str between delimiters
set oldTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to delimiters
set strtoks to text items of str
set text item delimiters of AppleScript to oldTIDs
return strtoks
end tokens
When I run that script, I get
{"http://farm6.static.flickr.com/5290/5377008438_8e3658d75f_b.jpg", "5377008438_8e3658d75f_m.jpg", "5377008438", "http://www.flickr.com/photos/dbooster/5377008438"}
I'm not really clear whether you need help with interacting with the clipboard. But it's easy at any rate, you can just use get and set:
get the clipboard
set the clipboard to "example"
I think this should be your starting point:
changeUrl("http://farm6.static.flickr.com/5290/5377008438_8e3658d75f_m.jpg")
on changeUrl(theUrl)
set theNewUrl to do shell script "echo " & theUrl & "| tr '_m.jpg' '_b.jpg' "
end changeUrl
...though I´m not exactly sure, what you´re trying to achieve in the end - do you want to generate a link ending in "_b.jpg" from "5377008438" being read from your clipboard?
Thanks for the replies everyone!
I apologize for not giving more details. This morning I used the code Michael gives, modifying it to take two vars (the direct photo url and the photo title) and spit out the reference end of some markdown code for displaying the photo and link, prompting me for photo dimensions and border.
It seems to work pretty well. Here is what I wrote.
copy (the clipboard) to URL_TITLE
set baseURL to first text item of (tokens of URL_TITLE between " ")
set baseTitle to ("\"" & second text item of (tokens of URL_TITLE between "\"") & "\"")
set modURL to (characters 1 through -6 of baseURL as text) & "b.jpg"
set fileName to last item of (tokens of baseURL between "/")
set photoID to first item of (tokens of fileName between "_")
set mainPhotoPage to "http://www.flickr.com/photos/dbooster/" & photoID
set photoWidth to the text returned of (display dialog "Photo Width?" default answer "980")
set photoHeight to the text returned of (display dialog "Photo Height?" default answer "605")
set photoBorder to the text returned of (display dialog "Border Size?" default answer "10")
set var6 to ("[photo]: " & modURL & " " & baseTitle & " width=" & photoWidth & "px" & " height=" & photoHeight & "px" & " style=\"border: " & photoBorder & "px solid black\" class=\"aligncenter shadow\" & "\n" & [photopage]: " & mainPhotoPage & " target=\"_blank\" rel=\"nofollow\"")
set the clipboard to var6
on tokens of str between delimiters
set oldTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to delimiters
set strtoks to text items of str
set text item delimiters of AppleScript to oldTIDs
return strtoks
end tokens
Like I said, all works great. I have a firefox plugin that copies the direct photo link and photo title (URL "TITLE") into the clipboard. I then assigned this script a hotkey with Fastscripts and it returns the result to the clipboard. Then I can paste the result to my post template file.
I couldn't get it to work with text expander, but Fastscripts calls it quickly enough so there is no problem.
To be honest... I have very little idea what I did. I don't know AppleScript at all. I only suggested it for my question because text expander supports it and it seemed easy enough. So even tho the script I wrote seems to work, it is nothing but me fiddling around with the code Michael gave.
So this is to say, if you see a much more efficient way to do what I did, I am all ears.
Thanks again for the help, guys!