Create an applescript subroutine in a try block - macos

I am trying to create a subroutine in an Applescript. However, I get a syntax error saying "expected 'error' but found identifier". I believe its because Im doing this inside of a try block. Is there a way around this?
try
on prompt()
-- Do Something
end prompt
on error errTxt number errNum -- errTxt and errNum are returned from system
display dialog errTxt & return & errNum

Your "try" block must be within the function, or around the code that calls the function.
Within the function:
on prompt()
try
#do something
on error errMsg number errNum
#do something with the error
end try
end prompt()
Around the function call:
try
my prompt()
on error errMsg number errNum
#do something with the error
end try
Both options will catch any errors generated within the function. The second option has the added feature that, should the function not exist, you will catch that error as well.

Related

Applescript subroutine

I have a helperScript which has a few basic functions that I frequently use.
My Current script’s flow goes like this:
on SubA()
Set HelperScript to load…..
tell HelperScript
: :
: :
end tell
end SubA
on SubB()
Set HelperScript to load…..
tell HelperScript
::
::
end tell
end SubB
on run paravlist
Set HelperScript to load…..
tell HelperScript
SubA()
SubB()
end tell
end run
I am unable to call SubA() and SubB() as the helper script is being set and used from each of subroutines. If I comment out the usage of helperScript. I am able to call subroutines from one another. What is the best way to deal with a problem like this? I want to use the helperScript in every subroutine.
After reading your question a few more times, I think I've figured out what you're asking. You're trying to load a script within your method and then you want to call a method that is within that script?
If that is the case, I think what you're looking for is this...
set HelperScript to load script...
set theResult to someMethod() of HelperScript
EDIT :
I'm still not clear if you have two scripts or one, so i've updated the answer to reflect both cases.
Dual script example...
property HelperScript : null
on run
try
if not loadScript() then error "Unable to load script"
set rslt1 to SubA() of HelperScript -- This approach assumes HelperScript.scpt is a different script and it contains a method called SubA
set rslt2 to SubB() of HelperScript -- This approach assumes HelperScript.scpt is a different script and it contains a method called SubB
on error errMsg
activate
display dialog "Error: " & errMsg buttons {"OK"} default button 1 giving up after 10
end try
end run
on loadScript()
try
set HelperScript to load script (POSIX file "/Path/To/HelperScript.scpt")
return true
on error
return false
end try
end loadScript
Single script example...
on run
try
set rslt1 to SubA() -- This approach assumes your HelperScript is THIS script
set rslt2 to SubB() -- This approach assumes your HelperScript is THIS script
on error errMsg
activate
display dialog "Error: " & errMsg buttons {"OK"} default button 1 giving up after 10
end try
end run
on SubA()
try
-- Do something here
return true -- or some other value
on error
return false -- or some other value
end try
end SubA
on SubB()
try
-- Do something here
return true -- or some other value
on error
return false -- or some other value
end try
end SubB
AppleScript has included a library loading system since 10.9. It's not great (e.g. avoid the SDEF garbage as it's 1. make-work and 2. bug-injector) but it generally does the job. I recommend you adopt that.

What is the code to exit/ stop VBscript from running in the event of a condition not being met?

I have looked on Google and the answer is not there!
First things first. WScript.Quit DOES NOT WORK! I have no idea what "WScript" is but it clearly has nothing to do with client side scripting for a web page. I have seen this "WScript" thing somewhere before and it just produces errors (maybe obsolete or something) so please do not suggest it...
Anyway... all I wish to do is completely stop the script in the event of a condition not being met. Obviously I don't want "Exit Sub" because the code would then carry on running if that sub is embedded!
I am aware of the "stop" command but I am under the impression that it is only used for debugging.
Hopefully a very simple question.
UPDATE and Conclusion: Before I close this subject I will just expand a little on what I was trying to do...
I had a number of main subs that were being started by a button click. In order to make it so that I did not have to edit each individual sub I embedded a universal sub within each one that did a preliminary check.
Part of that preliminary check was to stop the program in the case of an incorrect user input. If an error was detected I wanted to halt all progress from that point on. An "exit sub" would obviously just skip the rest of that preliminary sub and the main sub would carry on executing.
In the end it was just a case of writing in an error flag (that is checked in the main subs) or incorporating the error condition operation in each main procedure. In that way you exit the main sub and the problem is solved.
It was not laziness - I just wanted to reduce the amount of code. Thank you for the responses anyway.
I've found that the WScript is always available if running a .vbs/.vbe/.wsf script using either the wscript.exe or cscript.exe engine. When WScript is not available is if running using a different engine. E.g. running VBScript within a HTA, a webpage, in VBA or from a hosted COM script control.
To exit a script which is not running from wscript.exe or cscript.exe, you can do something like the following:
main
Sub main
' execute code here
' oops a confition is not met:
If Not condition then Exit Sub
' more code to execute if condition was met
End Sub
You can use something like this:
Sub MyFunc
----------
My Code
----------
End Sub
Function Main
On Error Resume Next
MyFunc
If Err.Number <> 0
Exit Function
End Function
It'll stop executing the code, the point it finds an exception or throws an error.
The simplest way, What i found is: WScript.Quit
The Wscript object is only available if you are running in the Windows Script Host (wscript.exe,cscript.exe). NOT Internet Explorer (iexplorer.exe, mshta.exe)
Well an easy way to do this is to declare a global variable that gets set to false until an error occured, and if the error occured then that variable will be set to true, after that anytime that variable gets checked you can exit sub\function\for\do\whatever.
Example:
Dim ErrorOccured
On Error Resume Next
ErrorOccured=False
Sub Main()
If ErrorOccured Then Exit Sub
'some code
MsgBox "Main has run"
End Sub
Sub MakeAnError
If ErrorOccured Then Exit Sub
'some code
Err.Raise 2
If Err Then ErrorOccured=True
End Sub
Function TellMeRandom
If ErrorOccured Then Exit Function
'some code
Randomize
TellMeRandom =Int((100- 1+ 1) * Rnd + 1)*1
End Function
Function ResetError
ErrorOccured=False
End Function
Call Main 'Main will run because an error has not occured (ErrorOccured is False)
MsgBox TellMeRandom 'This will return a random number 1-100
Call MakeAnError 'This will set the Global ErrorOccured to true
MsgBox TellMeRandom 'This will be blank because the ErrorOccured prevented it from running
Call Main 'This will not run because the ErrorOccured prevented it from running
Call ResetError 'This will set the Global ErrorOccured to false
Call Main 'This will run because ErrorOccured is back to False
MsgBox TellMeRandom 'This will return a random number 1-100 because ErrorOccured is back to false
Just remember to Add If ErrorOccured then Exit Sub for a sub routine or If ErrorOccured then Exit Function for a function.
You could also raise an error such as: Err.Raise 507
This Error will exit your current script : "An exception occurred".

drag and drop on a Rubyscript: displaying raise errormessage?

I have a script which I start by a drag and drop of a file from Explorer onto a link on the Windows Desktop to my script, so the filename becomes the parameter of my script. This is handy for users who don't know how to start my script with a valid parameter. This part works perfectly.
But when I raise an error in the script, the errormessage is displayed but the console window closes without giving the user the time to read the message.
Putting a gets or a sleep at the end of the script or after the raise doesn't help.
How do I fix that please ?
if ARGV[0]
filename = ARGV[0]
else
raise "No filename given"
end
#some other code with wrong data
error = true
if error
raise "An error has occured, wrong data"
end
Add this around your entire program:
begin
all your code...
rescue
puts $!
system('pause')
end

Try-Catch-End Try in VBScript doesn't seem to work

I'm trying the following code:
Try ' DOESN'T WORK
Throw 2 ' How do I throw an exception?
Catch ex
'What do I do here?
End Try
but I'm getting the error Statement expected in the catch clause.
Does anyone know how I can catch/throw exceptions in VBScript using try/catch? (I am not looking for solutions with On Error Do X.)
Handling Errors
A sort of an "older style" of error handling is available to us in VBScript, that does make use of On Error Resume Next. First we enable that (often at the top of a file; but you may use it in place of the first Err.Clear below for their combined effect), then before running our possibly-error-generating code, clear any errors that have already occurred, run the possibly-error-generating code, and then explicitly check for errors:
On Error Resume Next
' ...
' Other Code Here (that may have raised an Error)
' ...
Err.Clear ' Clear any possible Error that previous code raised
Set myObj = CreateObject("SomeKindOfClassThatDoesNotExist")
If Err.Number <> 0 Then
WScript.Echo "Error: " & Err.Number
WScript.Echo "Error (Hex): " & Hex(Err.Number)
WScript.Echo "Source: " & Err.Source
WScript.Echo "Description: " & Err.Description
Err.Clear ' Clear the Error
End If
On Error Goto 0 ' Don't resume on Error
WScript.Echo "This text will always print."
Above, we're just printing out the error if it occurred. If the error was fatal to the script, you could replace the second Err.clear with WScript.Quit(Err.Number).
Also note the On Error Goto 0 which turns off resuming execution at the next statement when an error occurs.
If you want to test behavior for when the Set succeeds, go ahead and comment that line out, or create an object that will succeed, such as vbscript.regexp.
The On Error directive only affects the current running scope (current Sub or Function) and does not affect calling or called scopes.
Raising Errors
If you want to check some sort of state and then raise an error to be handled by code that calls your function, you would use Err.Raise. Err.Raise takes up to five arguments, Number, Source, Description, HelpFile, and HelpContext. Using help files and contexts is beyond the scope of this text. Number is an error number you choose, Source is the name of your application/class/object/property that is raising the error, and Description is a short description of the error that occurred.
If MyValue <> 42 Then
Err.Raise(42, "HitchhikerMatrix", "There is no spoon!")
End If
You could then handle the raised error as discussed above.
Change Log
Edit #1:
Added an Err.Clear before the possibly error causing line to clear any previous errors that may have been ignored.
Edit #2:
Clarified.
Edit #3:
Added comments in code block. Clarified that there was expected to be more code between On Error Resume Next and Err.Clear. Fixed some grammar to be less awkward. Added info on Err.Raise. Formatting.
VBScript doesn't have Try/Catch. (VBScript language reference. If it had Try, it would be listed in the Statements section.)
On Error Resume Next is the only error handling in VBScript. Sorry. If you want try/catch, JScript is an option. It's supported everywhere that VBScript is and has the same capabilities.
Try Catch exists via workaround in VBScript:
http://web.archive.org/web/20140221063207/http://my.opera.com/Lee_Harvey/blog/2007/04/21/try-catch-finally-in-vbscript-sure
Class CFunc1
Private Sub Class_Initialize
WScript.Echo "Starting"
Dim i : i = 65535 ^ 65535
MsgBox "Should not see this"
End Sub
Private Sub CatchErr
If Err.Number = 0 Then Exit Sub
Select Case Err.Number
Case 6 WScript.Echo "Overflow handled!"
Case Else WScript.Echo "Unhandled error " & Err.Number & " occurred."
End Select
Err.Clear
End Sub
Private Sub Class_Terminate
CatchErr
WScript.Echo "Exiting"
End Sub
End Class
Dim Func1 : Set Func1 = New CFunc1 : Set Func1 = Nothing
Sometimes, especially when you work with VB, you can miss obvious solutions. Like I was doing last 2 days.
the code, which generates error needs to be moved to a separate function. And in the beginning of the function you write On Error Resume Next. This is how an error can be "swallowed", without swallowing any other errors. Dividing code into small separate functions also improves readability, refactoring & makes it easier to add some new functionality.

VB6 error propagation

I'm using an error handler on my main calling procedure and letting the other procedures just roll up to that error handler.
Should I be clearing the error each time? Or should I Exit Sub instead of letting the error handler continue on the End Sub?
I'm asking because I've read that I may catch the first error, and then the other errors won't be handled.
Sorry if this is less than clear. Not really sure what I'm saying.
Thanks!!
Edit: Something like this. Is this necessary?
Public Sub SubA()
On Error Goto ProcError
' other code
MsgBox FuncA()
ProcExit:
Exit Sub
ProcError:
MsgBox Err.Description
Resume ProcExit
End Sub
OP: Should I be clearing the error each time? Or should I Exit Sub instead of letting the error handler continue on the End Sub?
What do you mean by clearing the Error?
Usually, the procedure is written in this manner
public sub myProcedure()
on error goto e:
'statements that could raise error
exit sub
e:
Log err.Number, err.Description, "error occurred in myProcedure"
end sub
OR
You could choose not to add the error handler. In which case, the error will be propagated to the caller (or the procedure where it is handled).
Please post the sample code of what you are trying to achieve & your expectation.
EDIT: Here is what the code posted by you means
Public Sub SubA()
On Error Goto ProcError
' other code
MsgBox FuncA()
exit sub 'put exit sub otherwise it will execute the line below, even if no error
ProcExit:
'this statement will get executed after the error msgbox is shown
msgbox "Reached ProcExit"
Exit Sub
ProcError:
MsgBox Err.Description 'catch the error and show the msgbox
'error is cleared the point it reaches ProcError
'Resume ProcExit acts as goto, to execute any statements after the error is handled
Resume ProcExit
End Sub
With your particular example, you do not need to clear the errors out because your pattern is based on catching errors. Though it does not hurt:
ProcExit:
Exit Sub
ProcError:
MsgBox Err.Description
Err.Clear
Resume ProcExit
Now, if you had a pattern where you checking for errors instead of catching them, then yes, you'd have to clear it. Here is small example:
On Error Resume Next
Dim o as Object
Set o = myCollection(someKey)
if Err.Number <> 0 then
... respond to error
Err.Clear
I hope this helps.
The Err object is cleared whenever you exit a Sub as expected (e.g., no error occurs). In your example, the Resume ProcExit statement is unnecessary. The following two subs behave the same way:
Public Sub SubA()
On Error Goto ProcError
MsgBox FuncA()
ProcExit:
Exit Sub
ProcError:
MsgBox Err.Description
Resume ProcExit
End Sub
Public Sub SubA()
On Error Goto ProcError
MsgBox FuncA()
Exit Sub
ProcError:
MsgBox Err.Description
End Sub
You don't have to use the Exit Sub statement to clear the Err object. Simply falling out of the sub when you hit End Sub has the same affect.
If you want errors from "the other procedures" to "roll up" (a better word is propagate) to the error handler on your main calling procedure, they shouldn't contain error handlers at all. For instance, suppose Main calls SubA, and SubA calls FuncA. An error occurs in FuncA. If you handle the error in FuncA by simply displaying a message box, like you do in your example, the code is going to continue executing in SubA, but will be in an unstable state because something went wrong in FuncA and SubA does not know about it.
One option is to refrain from putting error handlers in SubA and FuncA. When an error happens in FuncA, it gets raised to SubA, which in turn raises it to Main where it is then properly handled.
An even better option is to trap the errors, log them, then re-raise them. Then when the error finally gets to your Main Sub with the error handler, you'll have more information to work with.

Resources