Use Singleton Error

When I updated to SketchUp Version 23.0.419, an error occurred in the extension that was being developed. Before the update, running SketchUp didn’t give me any errors. The contents of the error are as follows.

Error: #<NameError: undefined method extend_object' for class Singleton’
Did you mean? extended>
C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/Singleton.rb:150:in undef_method' C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/Singleton.rb:150:in singleton class’
C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/Singleton.rb:138:in module:Singleton
C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/Singleton.rb:94:in <top (required)>' C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/rubygems/core_ext/kernel_require.rb:83:in require’
C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/rubygems/core_ext/kernel_require.rb:83:in `require’

I wonder what the reason is.

When I do:

require 'singleton'

… at the Ruby console, I get no error in the latest version of SketchUp which was updated to use Ruby 2.7.7.

Note, that I do not see any changes in the "Tools/RubyStdLib/singleton.rb" file between Ruby 2.7.2 and 2.7.7. In fact, both modules are version "0.1.0".

When you updated, did you download the installer and right-click it and choose “Run as administrator” ? … or did you do the web update from within a running SketchUp ?

If the latter, then shut down all applications, reboot the computer, then go download the full installer, and right-click it and “Run as administrator”. Afterward, reboot the computer again.

Then see if you can reproduce the Ruby error.

When is the error occurring for you ? (From the backtrace you posted, it looks like just requiring the Singleton library has caused the error.)

Are you modifying the Singleton module in any way ? directly, or indirectly with include or append ?

Is your extension (or another) trying to extend the custom class that has Singleton mixed in ?

Case insensitive file systems can be a PITA. The file in question is singleton.rb, not Singleton.rb.

Somewhere in your code you probably have

require "Singleton"

but elsewhere you have

require "singleton"

Or, your error log shows:

C:/Program Files/SketchUp/SketchUp 2023/Tools/RubyStdLib/Singleton.rb

From a console:

ruby -rsingleton -rSingleton -e "puts 'case issue'"

throws your error, but the following does not:

ruby -rsingleton -rsingleton -e "puts 'case issue'"

Ruby is loading the file twice because of the ‘casing’ change.

1 Like

JFYI, I’m not sure what I think of this, but considering that most desktop OS’s do have case insensitive file systems, Ruby could handle this type of error in a different manner.

It may be considered ‘expected’ behavior.

I filed an issue on the Ruby bug tracker:

See Bug #19691: Case insensitive file systems, require filename casing - Ruby master - Ruby Issue Tracking System

I think it is expected behavior for case-sensitive file systems.

But I agree, as I believe that a great majority of the Ruby world is on case-insensitive file systems, and that there should be a default ARGV switch for the Kernel require suite of methods to do insensitive path matching into the $LOADED_FEATURES array. See C Ruby API rb_require_string()

The SketchUp world has dealt with this by down casing the path string arguments to Sketchup::require so that the entire path string pushed into the $LOADED_FEATURES array is lower cased both for it’s internal decryption condition and when passed on to a global require call for unencrypted rb files. (This API feature then can cause loading issues on case-sensitive file systems. I’m not even sure if SketchUp is supported on case-sensitive file system installs.)

Good catch on the double loading.

The issue arises because of the Singleton library’s switching off object extending for classes that mix in this library.

It does this (in part) by calling undef_method(:extend_object) (at line 150 in "singleton.rb").

The first time loading the file is fine, the class callback method is undefined. This is proven by the second inadvertent loading where the extend_object class method cannot be found to be undefined, hence the NameError seen in the first post.

The "singleton.rb" file says at line 149 says …

# extending an object with Singleton is a bad idea

… meaning that the Ruby team does not want us to include the Singleton module into a custom mixin module and then try to use this mixin as an argument to extend another object, class or module.

In fact, the Singleton module does not allow itself to be included into a module at all, as just after undefining extend_object in the file it overrides append_features to raise a TypeError if this is attempted by code.

What is a bit weird, perhaps an oversight as the Singleton module likely predated the prepend feature, is that it does not override prepend_features to prevent it from prepending a module.
Should a Ruby library issue be opened with regard to this?

Note however, that nothing has been done to prevent the actual singleton instance object from being extended after creation via the Object#extend method. This seems to be okay to do.

That hasn’t really been mentioned. Using the above on Ubuntu, if the file Singleton.* exists on the $LOAD_PATH, it will be loaded, otherwise it will raise LoadError.

From the above linked Ruby issue, it seems that macOS is functioning as expected in Ruby 3.1 and later, and it’s broken in Windows, as shown here (I tested back to Ruby 2.5). It is considered a bug, as one of the Ruby committers found that File.realpath is probably the culprit.

But I agree, as I believe that a great majority of the Ruby world is on case-insensitive file systems

I might disagree. The majority of desktops are case insensitive, but most Ruby projects run on servers. An example might be a popular Ruby web/app server, which sees over 200k daily downloads.

GitHub, Shopify and other wellknown companies run very large RoR (Ruby on Rails) apps.

Both Discourse and Mastodon are also RoR apps.

An error occurred right after the update, but after some time it worked. However, I have already modified it in a way that does not use singleton. Thank you for your reply.

As we noted above, some other extension had already loaded it as "singleton.rb" but your code loaded it a second time as "Singleton.rb".

The lesson is always use the exact case of the filename when making require calls.

Most probably the error on the second load attempt would not hurt how the Singleton class works.