Keeping gems locally inside extension

I’m working on extension which using should be as easy as possible, and I have following issue.

I’m using external gems in my ruby code and when I move extension into Plugins folder for new setup of sketchup I’m receiving an error like this one:
Error: #<LoadError: cannot load such file – rubyXL.rb>
I know that i could just install gem through console but this extension will be used by non technical user, on many pc’s.
My idea is to keep locally gems in the extension folder. Is this possible? How to do this? Where i can download package with gem? If it’s not possible, do you have any other ideas for this issue?

If you can do something manually through a console, you can automate through code.

You can require ‘rubgems’, then try to require the gems that you need and if they are not installed (exception), you invoke something like Gems.install .... However this is synchronous and freezesSketchUp for a while.
See here:

Alternatively, there might be ways to bundle them, but ensure they are in your namespace.

It is pre-loaded by SketchUp during startup (but doesn’t hurt to call require too much.)

Oh, … and it’s

Gem::install("gem-name")

It is easy to bundle pure-Ruby gems, and wrap them in your plugin sub-module namespace.

But not easy if the gems have binaries. You run into the issue of Mac vs. PC, and then also 32-bit vs. 64-bit binaries on WIndows editions.

Oh is that you Tomasz ? … from SketchUcation ?

1 Like

Thank you for your answers!

ok so basically I could install gems in pre-loaded stage. Should i first check if they are existing?

Is there any other way to just keep ruby gems in extension and call them without installation? I could for example download all needed tree gems and then put it to proper sketchup folder.

@DanRathbun - My name is Tomasz, but I’m very new to Sketchup and I’m not yet on SketchUcation :slight_smile:

The global require method will do this. (RubyGems modifies it to load gems.)
So for example …

require "zip"

… will load the RubyZip gem, IF it is installed.
If not it will raise an exception. Lets try and load a bogus gem named “bogus-gem” …

require "bogus-gem"
#=> Error: #<LoadError: cannot load such file -- bogus-gem>
#=> C:/Program Files/SketchUp/SketchUp 2016/Tools/RubyStdLib/rubygems/core_ext/kernel_require.rb:45:in `require'

… see how the first backtrace is from rubygems ?

So you can trap that LoadError exception in a rescue clause …

begin
  require "zip"
rescue LoadError
  begin
    Gem::install("rubyzip")
  rescue Gem::InstallError => error
    puts "ERROR! RubyZip could not be installed."
    puts error.message
  else
    require "zip"
  end
end

Now, RubyZip is a weird variance that does not have the same load name as it’s gemname.
Normally gems names and the name of their loader is the same so you can “require” the same string.

The folder can be gotten from SketchUp Ruby thus …

ENV["GEM_HOME"]

… but you should be an expert at how rubygems are setup so as not to break the user’s installation.

…okay a different Tomasz. Welcome …

1 Like

Dan, thank you for this post, it helps a lot, however I’ve noticed that when
I put following expression into my code:

then at the first try it displays:

Error: #<LoadError: cannot load such file – rubyXL>

however when i restart sketchup everything works fine. Any idea to make it works at the first time?

Thanks in advance

This code works for me (Windows SU2017). But doesn’t explain the underlying fault.

begin
  require "rubyXL"
  puts '1'
rescue LoadError
  begin
  puts '2'
  Gem::install('rubyXL')
  puts '3'
  rescue LoadError => error
  puts '4'
  puts "ERROR! RubyXL could not be installed."
  puts error.message
  end 
  puts '5'
  require "rubyXL"
end

The error that is caught at step- 4 reads:

ERROR! RubyXL could not be installed.
Could not find 'nokogiri' (>= 1.4.4) among 1 total gem(s)
Checked in 'GEM_PATH=C:/Users/USER1/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Gems64', execute `gem env` for more information
1 Like

All those puts slow down the execution, that may allow Windows to “catch up”.
Sometimes it transparently caches filesystem updates, and Ruby calls to load newly created or copied files fail because the OS reports that the file(s) do not exist.

I often add in calls to return a directory listing in hopes that it “kicks” WIndows into updating what it thinks are in the source directory.

Dir::chdir(gem_directory) { Dir["*.*"] }

As we’ve been discussing here,… RubyGems is very poorly integrated into SketchUp.

It is very likely that a custom Gem::Installer subclass is needed for SketchUp.

Excellent response Dan!

‘nokogiri’ is a compiled gem which RubyXL requires…

Gem.install fails when trying to install this dependency …

john

Yes, it seems like others have reported this in the past.
Perhaps search the forums on “nokogiri” ?

https://forums.sketchup.com/search?q=nokogiri

Ah… I see that nokogiri has binary libraries.

But there is another issue and that is Nokogiri stopped supporting Ruby versions less than 2.2, so if one is to install on Ruby 2.0 (SketchUp 2016) you would need to know the last Nokogiri version that supported Ruby 2.0 so you could specify that when you install the gem.

Checking out the CHANGELOG at the Nokogiri Git repo, I find that it is v1.6.8.1 that is the last to support Ruby 2.0 (SketchUp 2016), so at the console I got no errors …

Gem::install 'nokogiri', '= 1.6.8.1'
#=> [
#=>   #<Gem::Specification:0x645e330 mini_portile2-2.1.0>,
#=>   #<Gem::Specification:0x5ae8aa8 nokogiri-1.6.8.1-x64-mingw32>
#=> ]
require "nokogiri"
#=> true

It seems nokogiri distributes gem with precompiled binaries for Windows.


I also just tried a nokogiri install on SU2018 and it installed the latest v 1.8.1 with no issues.


@m07t0m, what SketchUp version are you running ? (2.5 is not valid.)

@DanRathbun I’m using Sketchup Pro 2018

Your profile reads “2.5” … how’d that happen ?

Ha, my mistake :slight_smile:
By writing 2.5 I thought about ruby version which is also not true because Ruby for Sketchup Pro 2018 is v.2.2
Corrected

1 Like

That is the latest version, but SketchUp does not use it yet. Perhaps next year?

I read that not all gems are yet compatible with Ruby 2.5, …
so it may be more likely SketchUp moves up to 2.4.x.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.