Ruby works in Sketchup 2023, doesn't work in Sketchup 2024

Hi. Please explain:

this string work in Sketchup 2023:

Class.new($stdout.class){}.new

#<#<Class:0x000002a88e3674d0>:0x000002a88e3672c8>

and doesn’t work in Sketchup 2024:

Class.new($stdout.class){}.new

Error: #<TypeError: allocator undefined for #<Class:0x0000025eb832fc80>>
(eval):1:in `new'
(eval):1:in `<main>'
SketchUp:in `eval'
=> nil

Why?

So, question come down to:

in Sketchup 2023 it work:

 aa = Sketchup::Console.new
 #<Sketchup::Console:0x00000286d5d94a28>

in Sketchup 2024 it doesn’t work:

aa = Sketchup::Console.new
Error: #<TypeError: allocator undefined for Sketchup::Console>
(eval):1:in `new'
(eval):1:in `<main>'
SketchUp:in `eval'
=> nil

Does it from SketchUp API answer your question?

The Console class is used by SketchUp to direct $stdout and $stderr to the Ruby Console. It is a singleton class that only has one instance available. This instance is accessible via the SKETCHUP_CONSOLE constant.

Please update your profile, SketchUp web don’t let you use Ruby console.

1 Like

SketchUp 24 upgraded to Ruby 3.2 and things change. Refer to Ruby documentation.

I want make little fix for Ruby Console+ plugin. As far as I understand, a new class for Sketchup::Console has been made in this plugin, with a certain method overload.

So… ok, I am understand, that troubles in changing Ruby 2.7 to Ruby 3.2.

I solved error in first post.

Second trouble:

RuntimeError: The SortedSet class has been extracted from the set library. You must use the sorted_set gem or other alternatives.

Okay… how I can install sorted_set in Sketchup2024.Ruby ?

That might be difficult. sorted_set has a dependency on rbtree, which contains a c file (it’s an ‘extension’ gem).

So, you’d have to compile the rbtree gem in a manner compatible with SketchUp, then use it with the single Ruby file that sorted_set contains.

Thank you. overall, I have fixed this error. It has nothing to do with the code, it was bypassed through begin/rescue.

To be specific, your Ruby statement attempted to create a subclass of Sketchup::Console, which is a singleton class (meaning only one instance is allowed.)

How did you solve this?

If you need a sorted set, then it would be easier (I think) to convert an unordered Set to a new ordered Set .

require "set"
# s1 is an unordered set, s2 will be ordered ...
s2 = s1.to_set { s1.to_a.sort }

But you will have reorder this way if any new items are pushed into the set.

So, this plugin (Ruby Console+) was created, when Sketchup::Console wasn’t singleton.

this part of the code was falling into error in Sketchup 2024.

      @@stdout_redirecter ||= ObjectReplacer.new('$stdout', Class.new($stdout.class){
          def write(*args)
            puts args
            # For write/puts, provide only the direct caller (script file),
            # not the complete backtrace.
            # Ignore callers that are subclasses or intercepters of the console itself.
            _caller = [caller.find{ |s| IGNORED_CONSOLE_SUBCLASSERS.none?{ |r| s[r] } }]
            PRIMARY_CONSOLE.value.print(*args, :backtrace => _caller) unless PRIMARY_CONSOLE.value.nil?
            # Sketchup::Console supports only one argument, where as Ruby Kernel.puts
            # sends two arguments (string, "\n") or separate method invocations depending on arity.
            args.each{ |arg| super(arg) }
          end
      }.new)

I changed it to code:

      cons_std_out = Class.new($stdout.class) {
        self.instance_eval do
          def write(*args)
             # For write/puts, provide only the direct caller (script file),
            # not the complete backtrace.
            # Ignore callers that are subclasses or intercepters of the console itself.
            _caller = [caller.find{ |s| IGNORED_CONSOLE_SUBCLASSERS.none?{ |r| s[r] } }]
            PRIMARY_CONSOLE.value.print(*args, :backtrace => _caller) unless PRIMARY_CONSOLE.value.nil?
            # Sketchup::Console supports only one argument, where as Ruby Kernel.puts
            # sends two arguments (string, "\n") or separate method invocations depending on arity.
            args.each{ |arg| SKETCHUP_CONSOLE.write(arg) }
          end
        end
    }

      @@stdout_redirecter ||= ObjectReplacer.new('$stdout', cons_std_out)

(remove “new” in creating class, and add “self.instance_eval”).

This reference clearly reveals that .new calls .allocate and then .initiallize. But I do not see anywhere that it explains why a “allocator undefined” error might occur. Does Ruby 3 require .allocate to be explicitly defined?

@JimG55 First of all, the Ruby documentation is written toward standalone Ruby process, not one that is encapsulated within another application’s process.

The SketchUp Extensibility team has had to do some hacky things over the years when exposing the C++ internals of SketchUp to Ruby. One of these hacky things is the implementation of the Ruby Console.

A bit of history: The Sketchup::Console class was first implemented with the 2014 release which also debuted Ruby 2.0.0 for SketchUp. Prior to the 2014 release (SketchUp used Ruby 1.8.x,) there was no API class for the console window and all we could do was call:

Sketchup.send_action("showRubyPanel:")

On Windows platform, before the 2023 release the window objects were MFC class (or subclass) objects. But SketchUp has begun a migration for the GUI to the cross-platform Qt libraries. Since the migration began there have been several complaints that the console (or STDOUT) has slowed noticeably and often messages are displayed out of the order expected.
I am not sure whether the culprit is Ruby 3 or that the console window is a Qt library class object. The Extensibility Team has had to look into this several times in that past couple of dev cycles.


The Console+ extension has had issues in some of the past SketchUp releases, but the author has adapted it to keep working. To be honest I have never understood the strategy for creating an extra console. I remember early on there was a problem with the attempt to clone STDOUT and the code pattern needed to be adjusted slightly. (I don’t know if that conversation was in the public forum or not. If so, it was either in the old SketchUp Google group or over at SketchUcation.)

I vaguely recall a proposal that there should be an article written on cloning $stdout (STDOUT) or the console, but I don’t think it has been published yet. (I do not have a link to it in my API bookmarks if it does exist.) The article is needed because I recall comments from the API coders that they “hacked” $stdout is a strange way that wasn’t obvious. (This may have morphed over the years as well.)

It may be best to ping @Aerilius, @bugra and @tt_su about this.


I realize something changed in Ruby 3.0 but I’m not a nitty gritty expert on the Ruby C core.

Perhaps @MSP_Greg can weigh in?

Thanks for the very quick response. I will pursue the question further as you suggest. It seems like I would not be the only one to encounter this issue.

I am aware of the issue and found a solution, just not yet released.

The problem is that in SketchUp, we have classes backed by C++ classes and they do not always have the same object-oriented behavior as pure Ruby classes. Specifically, the SketchUp Console class had twice been turned uninheritable (which was reverted again), and in 2024 it is uninstantiatable. This hints at code refactoring and stricter best-practices in C++, which generally is a good thing.

I think I had chosen to subclass the built-in console (instead of wrapping/delegating) in order to avoid monkey-patching and keep it closely compatible if future versions add methods or other changes.

I agree that in the best case we wouldn’t need it anymore. The built-in Console GUI had a single line and had no history (and various performance issues), which bugged me until I created an alternative.

Thanks for the very fast response. So I should just wait for the release of a SU2024 updata?

It appears that the interpretter wants me to explicitly define a .allocate method similar to how I need to define a .initialize method.