# Sketchup.require failing in local gem after encryption

**URL:** <https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372>\
**Category:** Ruby API\
**Tags:** signing, ruby, sketchup::require, path, encryption\
**Created:** [August 23, 2018, 12:35pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372 "2018-08-23T12:35:53Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![somtum](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/somtum/32/44151_2.png) [@somtum](https://forums.sketchup.com/u/somtum)\
**Post date:** [August 23, 2018, 12:35pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/1 "2018-08-23T12:35:53Z")

</div>

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:

```ruby
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

```ruby
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?

---

<div class="post-metadata">

**Author:** ![phillippe](https://avatars.discourse-cdn.com/v4/letter/p/71c47a/32.png) [@phillippe](https://forums.sketchup.com/u/phillippe)\
**Post date:** [August 23, 2018, 2:09pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/2 "2018-08-23T14:09:05Z")

</div>

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

Try:

```auto
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'

```

---

<div class="post-metadata">

**Author:** ![kirill200777](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/kirill200777/32/40095_2.png) [@kirill200777](https://forums.sketchup.com/u/kirill200777)\
**Post date:** [August 24, 2018, 12:27pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/3 "2018-08-24T12:27:09Z")

</div>

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](https://ruby.sketchup.com/Sketchup.html#load-class_method).

---

<div class="post-metadata">

**Author:** ![phillippe](https://avatars.discourse-cdn.com/v4/letter/p/71c47a/32.png) [@phillippe](https://forums.sketchup.com/u/phillippe)\
**Post date:** [August 24, 2018, 1:29pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/4 "2018-08-24T13:29:39Z")

</div>

> 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).

---

<div class="post-metadata">

**Author:** ![tt\_su](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/tt_su/32/17_2.png) [@tt\_su](https://forums.sketchup.com/u/tt_su)\
**Post date:** [August 24, 2018, 1:43pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/5 "2018-08-24T13:43:47Z")

</div>

> [@phillippe](#):
>
> My guess is somtum replaced `require_relative` calls with `Sketchup.require` .

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.

---

<div class="post-metadata">

**Author:** ![eneroth3](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/eneroth3/32/1222_2.png) [@eneroth3](https://forums.sketchup.com/u/eneroth3)\
**Post date:** [August 24, 2018, 2:57pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/6 "2018-08-24T14:57:19Z")

</div>

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

```

---

<div class="post-metadata">

**Author:** ![KarenAvdalyan](https://avatars.discourse-cdn.com/v4/letter/k/cab0a1/32.png) [@KarenAvdalyan](https://forums.sketchup.com/u/KarenAvdalyan)\
**Post date:** [April 9, 2019, 2:26pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/7 "2019-04-09T14:26:04Z")

</div>

But where to put this function so it was visible(or overriden) everywhere?

---

<div class="post-metadata">

**Author:** ![eneroth3](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/eneroth3/32/1222_2.png) [@eneroth3](https://forums.sketchup.com/u/eneroth3)\
**Post date:** [April 9, 2019, 2:34pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/8 "2019-04-09T14:34:59Z")

</div>

Good question!

From what I know it can’t override the kernel method only within my module. What I do is a simple search and replace throughout the embedded libraries to make them reefer to my own method. It could probably be done with refinements too but that would still require changes to all files using it.

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [April 9, 2019, 10:16pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/9 "2019-04-09T22:16:12Z")

</div>

> [@eneroth3](#):
>
> From what I know it can’t override the kernel method only within my module.

Sure it can. Why do say it cannot ?

Firstly, the definition you show above is a module method and that cannot override an instance method that is inherited.

But if you define it as a local instance method of your module or class, then it WILL override the mixed in method from `Kernel`. (ie, `require_relative` is defined in `Kernel` which is _included_ into `Object`, which is the superclass of `Module`, which is the superclass of `Class`.)

Seeing as how you are likely to do this many times … this is the perfect situation for a **mixin** library module (just as `Kernel` is itself a mixed in library module.)

Assume the following saved in a `"lib/require_relative_for_sketchup.rb"` file …

```ruby
module AuthorNamespace

  module Lib
    module RequireRelativeForSketchUp
    
      # 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 require_relative(path)
        base = File.dirname(caller_locations(1, 1).first.absolute_path)
        path = File.join(base, path)

        Sketchup.require(path)
      end

    end
  end

end

```

Then, in another file…

```ruby
module AuthorNamespace
  
  LIBPATH ||= File.join( __dir__ ,"lib")
  require File.join(LIBPATH,"require_relative_for_sketchup.rb")

  module SomePlugin

    extend self
    include Lib::RequireRelativeForSketchUp
    
    # other definitions: constants, methods, etc.
    
    class SomeTool
    
      include Lib::RequireRelativeForSketchUp
    
    end  
    
    # more definitions: methods, menu code, etc.
  
  end

end

```

If you find later that the code for the override method needs adjustment, the fix need only be applied one place in the codebase.

---

<div class="post-metadata">

**Author:** ![MSP\_Greg](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/msp_greg/32/206066_2.png) [@MSP\_Greg](https://forums.sketchup.com/u/MSP_Greg)\
**Post date:** [April 11, 2019, 2:28am UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/10 "2019-04-11T02:28:54Z")

</div>

@somtum

I think you might investigate adding the real path of `somtum/gems/locale` to `$LOAD_PATH`, assuming that [`Sketchup.require`](https://msp-greg.github.io/su/Sketchup.html#require-class_method) isn’t re-inventing the wheel.

Using a mix-in is ok, but still requires adding code to potentially a lot of files.

Trimble/SketchUp should consider:

1. Adding `Sketchup.require_relative`

2. Same for `autoload` ([Kernel.autoload](https://msp-greg.github.io/ruby_2_5/Core/Kernel.html#autoload-class_method) and [Module#autoload](https://msp-greg.github.io/ruby_2_5/Core/Module.html#autoload-instance_method)). This might make it easier for plug-in devs to not set their code up for 'load everything on startup"…

3. Consider aliasing the original methods, and replacing them with the Sketchup versions.

---

<div class="post-metadata">

**Author:** ![tt\_su](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/tt_su/32/17_2.png) [@tt\_su](https://forums.sketchup.com/u/tt_su)\
**Post date:** [April 12, 2019, 11:40am UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/11 "2019-04-12T11:40:07Z")

</div>

> [@MSP\_Greg](#):
>
> I think you might investigate adding the real path of `somtum/gems/locale` to `$LOAD_PATH` , assuming that [`Sketchup.require`](https://msp-greg.github.io/su/Sketchup.html#require-class_method) isn’t re-inventing the wheel.

That will be rejected in extension reviews. If extensions add paths that belong to their extension to the `$LOAD_PATH` there can be conflicts between other extensions when they try to resolve require paths.

As things are now - tweak your bundled gems to use `Sketchup.require` with paths relative to the Plugins directory. (And I hope you have changed the namespace of your bundled gem to be confined to your own extension’s namespace?)

---

<div class="post-metadata">

**Author:** ![MSP\_Greg](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/msp_greg/32/206066_2.png) [@MSP\_Greg](https://forums.sketchup.com/u/MSP_Greg)\
**Post date:** [April 12, 2019, 1:07pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/12 "2019-04-12T13:07:41Z")

</div>

Seems odd, but I suppose a malicious actor could…

I suspect the best solution is to compute full paths and use them in requires? If everything is namespaced, a constant equal to ` __dir__ ` could be set in the top namespace file…

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [April 12, 2019, 3:17pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/13 "2019-04-12T15:17:47Z")

</div>

> [@tt\_su](#):
>
> As things are now - tweak your bundled gems to use `Sketchup.require` with paths relative to the Plugins directory.

Hmmm … This is a case where long time Rubyists using the SketchUp API have taken for granted the knowledge of how to load code files. We **know** that `Sketchup.require` uses `Kernel.require` for non-encrypted files, so therefore it’s documentation applies to `Sketchup.require` as well with regard to the use of absolute paths versus relative paths from the `$LOAD_PATH` array members.

But, I never realized that the API doc for `Sketchup.require` / `Sketchup.load` says nothing of this. It’s docstring should at the least mention that relative paths will be relative to the “Plugins” path for extensions installed in the user’s “AppData” / “Application Support” directories.

> [@MSP\_Greg](#):
>
> I suspect the best solution is to compute full paths and use them in requires?

Not necessary unless it is in the minority of extensions installed with standalone installers into special paths other than the current version’s %AppData% or %ProgramData% paths (which are added as needed to the Ruby `$LOAD_PATH` array.)

It is just an educational issue. Many new coders are not first learning the basics of core Ruby before diving into SketchUp extension programming.

At one time (before the API documentation was generated by YARD and served up by GitHub, … it was hosted on SketchUp servers and had some introductory tutorial pages that I think explained the basics of loading code files. We lost these files when we switched to using YARD.

---

<div class="post-metadata">

**Author:** ![tt\_su](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/tt_su/32/17_2.png) [@tt\_su](https://forums.sketchup.com/u/tt_su)\
**Post date:** [April 23, 2019, 3:33pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/14 "2019-04-23T15:33:51Z")

</div>

> [@DanRathbun](#):
>
> But, I never realized that the API doc for `Sketchup.require` / `Sketchup.load` says nothing of this. It’s docstring should at the least mention that relative paths will be relative to the “Plugins” path for extensions installed in the user’s “AppData” / “Application Support” directories.

Well, that’s only because SU add the Plugins directory to the `$LOAD_PATH`.

> [@DanRathbun](#):
>
> At one time (before the API documentation was generated by YARD and served up by GitHub, … it was hosted on SketchUp servers and had some introductory tutorial pages that I think explained the basics of loading code files. We lost these files when we switched to using YARD.

I think I backed up the old API docs before we switched to YARD. I have to dig in some old backup archive.

The WayBackMachine have most of the old docs, but it appear the Getting Started pages are missing:  
[https://web.archive.org/web/20120311205755/https://developers.google.com/sketchup/docs/classes](https://web.archive.org/web/20120311205755/https://developers.google.com/sketchup/docs/classes)

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [April 23, 2019, 6:54pm UTC](https://forums.sketchup.com/t/sketchup-require-failing-in-local-gem-after-encryption/75372/15 "2019-04-23T18:54:43Z")

</div>

> [@tt\_su](#):
>
> Well, that’s only because SU add the Plugins directory to the `$LOAD_PATH` .

YES, and the docs should mention this so as to inform the coder why relative paths from the “Plugins” path will work, as well as a link to the `Kernel.require` docs.

> [@tt\_su](#):
>
> The WayBackMachine have most of the old docs, but it appear the Getting Started pages are missing:

Yes. It was under: **Introduction \> Tutorials \> Loading Ruby Scripts**
