Sketchup.require failing in local gem after encryption

signing
ruby
sketchup::require
path
encryption

#1

I am using a ruby gem in an extension. I include a local version of the gem a subfolder, so users don’t have to install it themselves. The gem is pure Ruby, so no problem with binaries.

Prior to doing extension signing/encryption, the following was working in main.rb and I could use the gem methods on any computer:

Sketchup.require('somtum/gems/locale/locale')

Then each file in locale would require whatever it needed using native require calls.

For reference, here is the folder structure:

somtum.rb
somtum/
somtum/main.rb
somtum/gems/
somtum/gems/locale/locale.rb
somtum/gems/locale/locale/version.rb
somtum/gems/locale/locale/middleware.rb
somtum/gems/locale/locale/info.rb
somtum/gems/locale/locale/driver/cgi.rb
somtum/gems/locale/locale/driver/env.rb
somtum/gems/locale/locale/driver/win32_table.rb
somtum/gems/locale/locale/driver/posix.rb
somtum/gems/locale/locale/driver/win32.rb
somtum/gems/locale/locale/taglist.rb
somtum/gems/locale/locale/driver.rb
somtum/gems/locale/locale/tag.rb
somtum/gems/locale/locale/data/languages.tab.gz
somtum/gems/locale/locale/data/regions.tab.gz
somtum/gems/locale/locale/info/language.rb
somtum/gems/locale/locale/info/region.rb
somtum/gems/locale/locale/tag/irregular.rb
somtum/gems/locale/locale/tag/common.rb
somtum/gems/locale/locale/tag/simple.rb
somtum/gems/locale/locale/tag/posix.rb
somtum/gems/locale/locale/tag/rfc.rb
somtum/gems/locale/locale/tag/cldr.rb

After signing/encryption, this fails.

First I tried to replace all the require calls in my gems folder with Sketchup.require

So for instance, locale.rb now contains

Sketchup.require 'locale/tag'
Sketchup.require 'locale/taglist'
Sketchup.require 'locale/driver'
Sketchup.require 'locale/version'

Here is the error

Error Loading File locale/tag
Could not find included file 'locale/tag'
Error Loading File locale/taglist
Could not find included file 'locale/taglist'
Error Loading File locale/driver
Could not find included file 'locale/driver'
Error Loading File locale/version
Could not find included file 'locale/version'
Error Loading File Z:/shared/plug/src/somtum/gems/locale/locale.rb
Error: #<NameError: uninitialized constant Locale::Tag>
Z:/shared/plug/src/somtum/gems/locale/locale.rb:91:in <module:Locale>'
Z:/shared/plug/src/somtum/gems/locale/locale.rb:23:in <top (required)>'
Z:/shared/plug/src/somtum/main.rb:20:in `require'

So it appears that its still failing, and I’m not sure why.

Another option would be to sign/encrypt the extension and then copy over the encrypted gem with an unencrypted gem. However, this breaks the signing mechanism.

Any ideas how I can make the require calls work? Am I doing something obviously wrong?


#2

Sketchup.require ‘locale/tag’
Sketchup.require ‘locale/taglist’
Sketchup.require ‘locale/driver’
Sketchup.require ‘locale/version’

Try:

Sketchup.require 'somtum/gems/locale/locale/tag'
Sketchup.require 'somtum/gems/locale/locale/taglist'
Sketchup.require 'somtum/gems/locale/locale/driver'
Sketchup.require 'somtum/gems/locale/locale/version'

#3

Mayby to try Sketchup.load instead of Sketchup.require? The load method is used to include encrypted and nonencrypted ruby files according to API Docs.


#4

Mayby to try Sketchup.load instead of Sketchup.require ?

This will end up failing as well since require is just an alias of load. My guess is somtum replaced require_relative calls with Sketchup.require. If they were originally require calls, I don’t see how it would have worked unless ‘Z:/shared/plug/src/somtum/gems/locale’ was in $LOAD_PATH (in which case Sketchup.require shouldn’t have failed).


#5

Yea, looks like it’s an issue with the relative paths. They need to be relative to the Plugins directory.

Also, when using a gem in your extension, if you publish it, make sure to wrap everything into your own namespace. Otherwise it will be rejected by extension warehouse. Reason being is that if multiple extensions bundled the same gem - but of different versions - you would clash.


#6

I’m using this little method to replace require_relative when embedding libraries in my plugins.

# Load file relative to callers location. Unlike Kernel.require_relative this
# supports SketchUp's encrypted extension files.
#
# @param path [String]
#
# @return [Boolean] True when file is loaded. False if already loaded.
def self.require_relative(path)
  base = File.dirname(caller_locations(1, 1).first.absolute_path)
  path = File.join(base, path)

  Sketchup.require(path)
end