Dear friends, I try to add a face but 4 points are in a line so I received following error.
“Error: #<ArgumentError: Cannot convert argument to Geom::Point3d>”
Is it possible codes continue and I do something when I receive this error. Something like following codes.
face1 = grp.entities.add_face [pt1, pt2, pt4, pt3]
if ArgumentError
p "ArgumentError"
else
#do something
end
This question is for all kind of errors that we received and we don’t want codes terminated.
Thank you in advance.
Just saying…(if you want to deal with the message text)
Be aware that for example the #add_face method can generate different message text for ArgumentError, e.g: Points are not planar... Duplicate points in array... Not enough edges...
Then a TypeError can raised, like wrong argument type...
Your indentation is incorrect. The rescue should be at the same level as it’s begin or the def.
Even though technically Christina is correct, the API authors decided not to create API specific exception classes (which was a poor decision,) … so the only way we have to differentiate the various exceptions is by the generated message of the standard exceptions raised.
Given that error messages may be localized, if the API had specific error classes (maybe for the factory methods) that returned a number, that might be helpful…
SketchUp API error messages are not localized, but they could. Or the English error messages could be reworded in the next version.
You can avoid specific errors from happening with validation of the user input (e.g. if points are planar) and then give feedback to the user and do an “early exit” from the method.
If you want to narrow down the type of error, but the error class is not specific enough, you can make a begin rescue end block very close around that single method call where you expect errors. This way you can be sure that the ArgumentError does not come from another method call above. You can make nested rescue blocks, for example keep the outer one for general errors.
begin
face1 = grp.entities.add_face [pt1, pt2, pt4, pt3]
rescue ArgumentError => err
# This ArgumentError can only come from add_face
# do something
end
Do not handle errors when you don’t know how your application/extension can proceed. For example if you cannot think of any alternative way to add a face for these points, then you actually cannot handle this error. Then you can only exit the method and let the user know why the expected action does not happen.
This was probably just a placeholder. If you would do this you would get less information than from the original ArgumentError because it had a precise message and a very useful backtrace that points you to the exact location. (For this reason, never try to make errors completely silent.) Somewhat more useful is:
puts(err.message)
puts(err.backtrace.join($/))
(Should actually be printed to $stderr, but SketchUp doesn’t implement puts on it?)
A good practice is for a library to create a single “generic” exception class (typically a subclass of StandardError or RuntimeError) and have its other exception classes derive from that class. This allows the user to rescue the generic exception, thus catching all exceptions the library may raise even if future versions of the library add new exception subclasses.
So I’d would think that there would be some kind of general SketchUp application exception super class (which would be a subclass of StandardError,) OR as I’ve said in previous discussions I suggested that there be a dedicated Sketchup::Exception submodule that could encapsulate all the API exceptions so that they are not scattered throughout the documentation as they are in the Ruby core.
Then within this module could reside subclasses of that would be categorical and say descendants of a Sketchup::Exception::ArgumentError:
Sketchup::GeometryError for an example.
Beneath this, specific subclasses such as:
Sketchup::Exception::NonPlanarPointsError
Sketchup::Exception::DuplicatePointsError
Sketchup::Exception::NotEnoughEdgesError
etc.
But then the API has to define constants for these “error codes”. (It already takes this approach for some API functionality.)
But in my mind, I don’t see the benefit of this route when the simple definition of an exception subclass is the recommended way. (Ie, … a class identifier is a constant reference.)
The docs says …
An Exception object carries information about an exception:
Its type (the exception’s class).
An optional descriptive message.
Optional backtrace information.
So the exception’s class name is the only thing required.
You are right it is just a place holder. In face when I find this error, I will delete group send message to user that your step information is wrong (one step cannot have 4 points in one line) and back to begin of codes. I just try to ask my question as simple as possible. Using exceptions can help us to save codes.
Very interesting thoughts!
But if you try to catch all sorts of ArgumentError you would miss Sketchup::Exception::ArgumentError. A case for multiple inheritance or mixins?
It can be very complex so let me give you an example. I try to make stair by codes. When user draw a possible stair, no error happen but when user draw an impossible stair I receive error when draw face1. following you can see an example for impossible stair. I check many times and error just happen when logically stair cannot exist. One solution is I try to limit user for this error that will have many different condition and I should write some codes for each one and other solution is using this error.
Well of course this one might need to be a subclass of ArgumentError (which is one of the subclasses of StandardError.)
But it is unlikely after 20 years that they’ll change course and create more API classes. (So we are probably just wasting our time fantasizing about it.)
Yes you need to use input validation on the values from your input box fields to prevent the user from drawing invalid stair configurations. You test the input values before your code attempts to draw geometry, and if the values are bad then you display a error message box to the user and redisplay the input box.