Cross-platform Generate xlsx Document

… by reducing the entries in the global $LOADED_FEATURES array, which will serve to speed up searches (using string comparisons on the array members) for the require method.

1 Like

Don’t you have to strip out the requires, and make sure the files are loaded in the right order?

What is the difference? Can you shed some :bulb: on my ignorance. I noticed I had to prefix the class with my namespace even when initializing the class from within my module, but i wasn’t sure why. (I’m afraid I’m revealing my ignorance :grimacing:)

Yes. But that can be automated by creating a dependency tree and flattening the files into 1. You just start with the first file and iterate all require and require_relative and remember which absolute paths have been parsed. if the current require is requiring a new file you grab the contents and replace the require with the contents. If the require is pointing to a file that has already been loaded you just comment out that line. Now, if you do this recursively, you will end up with a large file, containing all sources in the correct order.

1 Like

You make it sound so simple :wink: That is basically what my script does.

Do you have a similar script for packaging html/js/css into constants inside a main ruby file? Then the whole plugin could exist in a single rb except for the image assets.

Yea, as I remember, it was exactly what Ken describes that I had problems with.

The difference would be that you are creating a snapshot using a particular gem’s version for your extension. This works because you test and know that version works with your extension and the version of Ruby that SketchUp uses at that time.
This might change in the future as newer version of Ruby are distro’d with SketchUp.

My idea was a more “on the fly” approach to get around some of the gem install issues. Where an extension could request a certain gem version, and it would be encapsulated when the command was run.
I didn’t fully finish it, It was still in the try and fail stage.

I would once having the new gem code text, use Module.module_eval and pass it the text

html_text =,"some_html_file.html"))

… and then …

html = %[#{html_text}]

… or …

HTML ||= %[#{html_text}]

You can also use #{} string interpolation within HEREDOCs.

I see, except for the combining into 1 file part. But, this should work as well the way you do it.
Now, you will notice in write_xlsx that there are a few references to modules and classes where there is pointing to a global module while -because you subnamespaced it- actually a relative module is needed. I do not really know how to explain this in English, but, here we go: in write_xlsx you will see a lot of references that start with ::, for example ‘::Zip’, thus, pointing to a toplevel class or module named Zip. But, since you have subnamespaced Zip as, for example Neil::Zip, ::Zip will give an error.

Yes and no. My GUI’s are react.js apps, so they are kind of packaged. But, I do not package them into a .rb file. The only reason I could see is to hide the sources? But then… Developer Console is there for anybody to see the sources.

That would be the easy part. I was thinking about changing the html to include the javascript and css from linked files. That require a bit of parsing.

It’s called the scope operator.
And when it has no namespace preceding it, it refers to the toplevel ObjectSpace.

1 Like

Well a HEREDOC or a double quoted string can do it (using string interpolation.)

Within Ruby …

js_text =,"dialog.js"))
css_text =,"dialog.css"))

html = %[
<!DOCTYPE html>


Note that when we do this, all the code is loaded into the Ruby process’ memory.
When you let the CEF dialog load directly from html, js and css files, the code will be in the CEF instances memory (which happens anyway.)

Thanks for all your help. I’ll have to come back here for a refresher when I get ready to package my app.

There also is a standard templating library that can build your HTML text using <%= #Ruby code %> tags within the html.

It is sort of like how PHP is parsed on web servers.

See: Class: ERB (Ruby 2.5.5)
and the internal comments in “erb.rb”.

The YARD documenter uses it to build the doc web pages. uses YARD.

Thanks again everyone for your all your help. The performance seems to be pretty good.



Yea, looks good!


Can you shed some light on the process? Perhaps an example or tutorial.
I’m about where you were 7 years ago when you posted this.

The solution lists several links. The one that looks the most useful is UnmanagedExports, but I really have no idea how to get all the parts and pieces working and use it in Ruby. (I would be willing to pay for a sample project or tutorial)

There are a few ways to use C# together with ruby, side by side.

  1. You can create a c# console application and compile to both a windows and an osx executable and execute those from Ruby and wait for their completions (see: Generate Native Executable from .NET Core 3.1 Project - CodeProject). You can pass arguments to the process, just like you can to an ordinary function. You could see this approach the same as contemporary lambdas used in webservices.
  2. Instead of an executable one can also compile C# into a library (dll on windows or dylib on osx) and export some functions (see: You can then use Fiddle (GitHub - ruby/fiddle: A libffi wrapper for Ruby.) to wrap the native library and call it from ruby.
  3. I have tried wrapping the coreclr as a ruby c++ extension once… did not make it.
  4. Windows only… and… pretty old tech: register you dll as a COM object and then call it using Win32OLE.


Back then I ended up crafting a COM object. The biggest disadvantage was that this was Windows only. But, on the other hand, one gained also power over things such as WPF… from ruby :slight_smile:

1 Like

A valuable book for adding Ruby bindings for a library is the book …
Extending Ruby 1.9: Writing Extensions in C
There’s a PDF link in the Ruby Resources downloadable book list.

Thanks Dan. I have done a few ruby c++ extensions, going from geometric calculations to running native HTTP and Websocket servers directly in SketchUp using native threads. But, wrapping the coreclr… that was a bit over the top of my head.