Rescue in UtilitiesTools.rb

I am looking at utilitiestools.rb wright now and have question about …

why it works… this part…

# Try to create a Face from the Edges in the active component
    face = nil
    begin
        face = Sketchup.active_model.active_entities.add_face edges
    rescue
    end
    
    # If a Face wasn't created, then there should be an error message
    # telling what the problem was
    if( not face )
        if( $! )
            msg = $!.message
        else
            msg = $uStrings.GetString("Create Face from Edges failed")
        end
        UI.messagebox msg
    end

I’m pretty sure that $ ! should keep ‘nil’ anywhere outside of the rescue or ensure… So how is it that it works here… Are the sKetchup only errors somehow unicly deffined to keep the error info in the $! variable even after the rescue clause?

This doesn’t work:

begin
p aaaa
rescue
end
if $!
puts 'exists'
else
puts "doesn't"
end
=> doesn't

Yes this is true.

It may have worked in older SketchUp versions that used Ruby 1.8 branch for scripting.
I vaguely seem to remember something about $! changing.

Could be they did something “funky” on the C side. But this is poor practice as $! is supposed to be a read only variable.

Do you really see it working ?

I do not think it should. The blank rescue clause implies that an exception needs to be trapped, in order for the code to continue to the if $! statement.

These examples are very old and were written when even Ruby was relatively new. They continue to show the very poor practice of using global variables for strings when they should be using @@vars or local constants inside the extension namespace module.

The code should be at the least …

  # Try to create a Face from the Edges in the active component
  face = nil
  msg  = ""
  begin
    face = Sketchup.active_model.active_entities.add_face edges
  rescue => err
    msg = err.message
  end

  # If a Face wasn't created, then there should be an error message
  # telling what the problem was
  if face.nil?
    UI.messagebox(
      $uStrings.GetString("Create Face from Edges failed:") + "\n#{msg}"
    )
  end

This is badly written code (as most of the old plugin examples). You should never use an empty rescue. Even if $! had worked, it is much harder to read code where the error is handled somewhere further down and not in the rescue block.

3 Likes

Where did you come across this example?

The very old SketchUp OEM example, not updated since 2013 (when it was module wrapped.)
https://extensions.sketchup.com/en/content/utilities-tools

Within the "su_utilities/utilitiestools.rb" file, beginning line 35.

An effort is needed to hunt down bad API examples, or even better, catch them, put them on GitHub, fix them and let the history of what was changed and why be public so others can learn from it.

2 Likes

Agree. There are too many ancient examples that either don’t take advantage of subsequent changes to Ruby version or the SketchUp Ruby API or show bad coding practices. And don’t get me started on the example snippets in the API documentation itself!

2 Likes

I just happen to know you love those snippets so much. :wink:

1 Like

I think Matz included globals into Ruby to make coders comfortable who were familiar with shell scripting or perl, overlooking all the issues globals create. Modern styles uniformly discourage both creating and using globals, as there is always a clearer way.

1 Like

I do not think it should work but well… some examples…
face%20tool
Thats what happens when I draw for not aligned edges and choose ‘Create Face’… I got message that edges are not alligned… I didn’t see that kind of message string in the code so I assumed it is sketchup error passed to /$!..
utilitiestools.rb (7.5 KB)
This is file from that plugin

Maybe rescue shouldn’t be left empty but it is cheeky trick to ensure that plugin doesn’t break…

I downloaded it over a month ago and had no time to look into it till now… was worried that I will not be able to answer thomthom’s question , but here you go… Man… Do you sleep with sKetchup under your pillow…?
And to all of You… thanks for emazingly fast response… :astonished:

Have been coding SketchUp Ruby for almost 12 years.

Perhaps it works because the code is all wrapped up in a method.
$! may not be cleared (reset to nil) until the local method returns ?

It is not SketchUp “passing” to the global reference $!.
The Entities.add_face method checks the arguments, and if the edges are non-planar then it calls the C-side equivalent of raise(), ie

raise(ArgumentError,"Selected edges are not planar",caller)

There are several other argument error messages possible including “Edges are not planar”, “Points are not planar”, and “Duplicate points in array”.

Anyway, it is the Exception class constructor that internally sets the $! reference to point at the current exception object. It’s documentation says …

When an exception has been raised but not yet handled (in rescue , ensure , at_exit and END blocks) the global variable $! will contain the current exception and $@ contains the current exception’s backtrace.

So it should not really work, unless Ruby is detecting the empty rescue clause as a re-raise (ie, a raise call with no arguments re-raises the exception referenced by $! ?)

Yes, please report these old examples in our issue tracker.

I logged this one here: Clean up extension examples · Issue #294 · SketchUp/api-issue-tracker · GitHub