SketchUp STL String Encoding Issues


The SketchUp STL extension has a bug report where Sketchup.file_loaded? throws an error when it attempts to .downcase a string containing non-ascii characters.

Do we know how to definitely fix these encoding issues yet? They seem to be an ongoing problem.

Here are the bug reports:


Why do you not try to forced the string’s encoding to UTF-8 before doing anything else with it ?
You already do that when setting the extension-loader’s path.

current_path = File.dirname(__FILE__)
if current_path.respond_to?(:force_encoding)

But when you do the menu creation you do not.

unless file_loaded?(__FILE__)

If you tweak it perhaps as shown below, then does it work ?

if defined?(Encoding)
  me = __FILE__.force_encoding("UTF-8")
  me = __FILE__
unless file_loaded?(me)

Repeat this ‘me’ setup for all similar tests in any of the files using file_loaded ??
OR do NOT pass the whole __FILE__ thus:

  me = File.basename(__FILE__)
  me = "CE_STL_importer" unless me
  me = "CE_STL_importer"
unless file_loaded?(me)

Or even setting ‘me’ as a simple “string” anyway - thus side stepping the File hiccups and encoding issue entirely.

The file_loaded expects a UTF-8 string, so give it one, one way or another…


We have a comment # Ensure to open the file in with no encoding. but I am unsure why now.

Your solution seems too obvious, but I’ll try it anyhow. Haha, thanks.


@TIG, @jim_foltz,

This is really a question, as mac’s don’t have the issue…

Isn’t the error really in sketchup.rb?

if I grep out all three .downcase SketchUp still loads everything and runs fine…

why does it need to downcase at all?

I can never find a any links to why you would need to downcase a path, although it’s quite common…



Plugins were inconsistent when requiring sketchup.rb. Some used require "sketchup.rb", others require "Sketchup.rb", so the file sketchup.rb was being required more than once. This caused some problem I can’t quite recall - maybe it was only duplicate menu items for the Ruby Console. Downcasing all required files solved it.


Well, maybe. That’s what I was thinking also, but wanted to leave the question more open.

Apparently, you can’t downcase every CP949 or CP950 encoded string, and the file path is encoded using CP950. We can force the file encoding to utf-8 before downcasing, but is that the right thing to do? There are some indications online that it is not a clean conversion.

Should this be done in sketchup.rb file, or is the extension author responsible? In the short term, it must be up to each author.

I also read where this may have been fixed in Ruby 2.1.


But as I said… your code already changes to UTF-8 for the ‘Extension’ set up…

For file_loaded usage you do not need to pass the __FILE__ - although many of us do !
You can parse off the File.basename(__FILE__) and use that, or set a UTF-8 ‘string’ avoid even any potential File issues…
The file_loaded list is unlikely to contain an earlier entry based on either of those, unless the user has multiple Plugins folders in $: loading the same code, or the ‘string’ is moronically set up like ‘my_plugin’, where it might get repeated by others…


would the extension author need to ‘fix’ encoding without the downcase imposed by sketchup.rb?

for example, would this not avoid the require “sketchup.rb” / require “Sketchup.rb” issue and any down-casing errors?

# Call this method to see if a file is already loaded.
def file_loaded?(filename)
    $loaded_files.include? (File.basename(filename, ".*").downcase || filename)

# Call this function at the end of a file that you are loading to
# let the system know that you have loaded it.
def file_loaded(filename)
    $loaded_files.push(filename) if not file_loaded?(filename)



NO. Not exactly. You need to use rescue in modifier position, not ||.
Also the use of parenthesis will be interpreted as wrapping the parameter list, so should not have a space following the method name:

def file_loaded?(filename)
  $loaded_files.include?(File.basename(filename, ".*").downcase rescue filename)


def file_loaded?(filepath)
  filename = File.basename(filepath, ".*")
  filename.downcase! rescue nil

But I’ve been preaching that it is unnecessary to push paths of any kind into $loaded_files, as they are already pushed into $LOADED_FEATURES.

So instead do this (but NOT from toplevel nor console!):

# Avoid File.basename & other string methods.
thisfile = caller(0).split(':').first
# Downcase it suppressing errors
thisfile.downcase! rescue nil
# Prepend it with Namespace qualification:
thisfile = "#{Module::nesting[0].name}:#{thisfile}"
  if file_loaded?(thisfile)
    # do once code
  # handle error in sketchup.rb

I have also preached to “steal” the methods from “sketchup.rb” add them to a mixin module, FIX THEM and use this mixin instead of “sketchup.rb”.

I have logged several bug reports for “sketchup.rb”, that have not yet been repaired.

If anyone wants I have a test “sketchup.rb” override (that I had written several cycles back, but no longer works as a toggle-able extension in the “Plugins” folder, since SU2015 because “Tools” is loaded before “Plugins”. So you’d have to replace it I think.)

PM me if ya want to check it out. It could be wrapped in a mixin module I suppose.


Is there really a good reason to use file_loaded? and file_loaded methods?

If they are only for preventing duplicate menu items, there are better ways. If a user is getting duplicate menu items, then it would a clear indication something is wrong with their setup. It would act as a warning in that case and is desirable.

Extension authors should probably stop using these methods altogether for released extensions.


I think that is the primary reason.

But I often have other “run once” code. If it (the run once code) is all in one file (even though the extension has multiple files,) which is good practice,… I use some module variable like:

@@loaded = false unless defined?(@@loaded)

# at the right place
if not @@loaded
  # run once code

If you wish to test multiple files, well just define your own @@loaded_files array within your plugin module. You control what is pushed into it, and how it is tested for members.