openURL broken on MAC

I tend to always use system commands to open files (or folders)


# OSX vs WINDOWS
PLATFORM_IS_OSX     = ((Object::RUBY_PLATFORM =~ /darwin/i) ? true : false).freeze()
PLATFORM_IS_WINDOWS = (!PLATFORM_IS_OSX).freeze()

# get folder path and do repl
folder_path = "path/to/the/folder"
folder_path =  folder_path.gsub("/", "\\\\" if PLATFORM_IS_WINDOWS 
# construct the command to open Explorer on Windows or Finder on OsX
command = PLATFORM_IS_WINDOWS ? "start \"\" \"#{folder_path}\"" : "open \"#{folder_path}\"" 

Edit: shoot, missed the most important line :slight_smile:

# launch the command
system(command)
2 Likes

It was inconsistent across platforms. And it prevented URLs with fragments # to load properly because the # was URL encoded (among other characters).

Since Ruby provide encoding capabilities out of the box we made it so both platforms would require the API user to provide a correctly formatted URL.

Got a code example for this?

1 Like

Could this fix for cross-platform inconsistencies with URLs have introduced a platform difference for local paths? I’ve used openURL quite a few times to open local documents.

This is btw the solution I use now.

The URL specs say either %20 or + may substitute for space.

Edit: After some more research, it seems that there has been confusion about this for some time. The established practice when encoding the request part (after the ?) in an HTML GET or POST request was to use +. So, using + instead of %20 is still generally allowed in that context. But for the path part of the URL it seems to be preferred to use %20 for consistency with how other illegal characters are encoded.

The change in behavior in UI.openURL jumped out on Mac because the normal path for extension files is

/Users/username/Library/Application Support/SketchUp 2019/SketchUp/Plugins

which contains two spaces and will no longer work without encoding.

Replies;

  1. The “PLATFORM_IS” approach is extremely problematic to any developer who does have both platforms to test. You make the change, assemble all the code, upload it to the warehouse, thousands of users download it, then you see typo that you couldn’t test.
  2. Opening a 30 page user manual in the default browser is much better than using HTML dialog. The help file can contain links to other websites, and the user has browser support for search within the document.
  3. Before Trimble allowed such a change, they should have performed a global search for OpenURL in all ruby code in the warehouse (I expect that they keep the unencrypted ruby) and send a red alert email to every developer. Another indication that adult supervision is lacking.
1 Like

Why?
Just create a method that does this good for once and for all and just call that method from everywhere in your code…


# somewhere in constants.rb f.e.
# OSX vs WINDOWS
PLATFORM_IS_OSX     = ((Object::RUBY_PLATFORM =~ /darwin/i) ? true : false).freeze()
PLATFORM_IS_WINDOWS = (!PLATFORM_IS_OSX).freeze()

# somewhere in utils.rb f.e.
def open_external(path)
  # do replace on windows
  path=  path.gsub("/", "\\\\") if PLATFORM_IS_WINDOWS 
  # construct the command to open Explorer on Windows or Finder on OsX
  command = PLATFORM_IS_WINDOWS ? "start \"\" \"#{path}\"" : "open \"#{path}\""
  system(command)
end #def

# somewhere in your code
open_external("C:/users/") # this should work both for folders and files

And somehow every new ruby developer will have to trip over this problem, beg for help, then finally solve it “once and for all” for himself.

Your approach also shows a lack of “adult supervision”.

I am afraid I am not getting it.

1 Like

It means being aware of the big picture. “Solutions” like yours are what the API is for.
It maybe it should have a method “OpenURLfromSU” well tested by Trimble on both platforms to do thus.
It should not have to be reinvented and propagated by every developer.

if you check the API or Julia’s link. you’ll see that SU does have a platform method…

Sketchup.platform == :platform_win
# or
Sketchup.platform == :platform_osx

and as you don’t even need a url to open a html file in a browser or any in Finder on a mac, you set yourself up for a fall…

help = File.join(File.dirname(__FILE__), 'myextensions', 'help.html')

if Sketchup.platform == :platform_win
  UI.openURL("file:///#{help}")
else # use one of the incredibly common, standard Ruby methods
  # all these work
  `open "#{help}"`
  # or
  %x[ open "#{help}" ]
  # or
  system("open #{help.inspect}")
  # there are even more variants, this opens any file type in Finder...
  %x[ open -R #{help.inspect}]  
end

there is no need to reinvent the wheel if carry out some ‘due diligence’ before publishing…

john

1 Like

Hmm… opening a file is something very common and should’nt even be part of a sketchup specific api imho. So maybe it is not reinventing the wheel…

1 Like

Never noticed it. Got added in 2014 it seems. The check I use has been stuck on top of my constants.rb file for ages I believe.
Will change my starter kit to use the sketchup specific method. Thanks.

RE: openURL broken on MAC - #13 by kengey, post 13

A few observations …
path.gsub("/", "\\\\") if PLATFORM_IS_WINDOWS

It’s totally unnecessary to replace forward unix-like slashes with double backslashes on Windows. Windows NT has always AFAIK accepted pathnames with forward slashes. I usually do the opposite, replacing backslashes with forward slashes (there are some Sketchup module methods that return double backslashed pathnames on Windows, but shouldn’t have been written this way.) …

path = path.gsub(/(\\\\|\\)/,'/') if PLATFORM_IS_WIN

I think the main exception is registry hive paths.


PLATFORM_IS_OSX = ((Object::RUBY_PLATFORM =~ /darwin/i) ? true : false).freeze()
  • RUBY_PLATFORM being a constant defined in Object, is global.
    The class qualification is not necessary.

  • =~ does not return a boolean true || false so you use a tertiary IF, but instead it’s better (more elegant) to do the opposite and use !~ method which does directly return true || false so no tertiary IF is needed (ie., it’s faster.) Ex …

    PLATFORM_IS_WIN = RUBY_PLATFORM !~ /darwin/i
    PLATFORM_IS_OSX = !PLATFORM_IS_WIN
    
  • The Sketchup.platform method came out for SU2014 but for backward compatibility you can use a rescue clause when the Sketchup module doesn’t respond to a ::platform() call. IE …

    PLATFORM_IS_WIN =(
     Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/i
    )
    PLATFORM_IS_OSX = !PLATFORM_IS_WIN
    
  • Freezing / Constants are not really constant. Ie …

    EDIT (ADD): Trying to freeze an immediate singleton object like true or false is a frivolous endeavor.

    PLATFORM_IS_OSX = !PLATFORM_IS_WIN.freeze()
    

    Then do this …

    PLATFORM_IS_OSX = "I've been changed!"
    

    You get a warning that the constant was previously set, but it is still reassigned to point at the new object (in this case a String.) The global = reference assignment function is an interpreter function, not a Ruby method, so it can reassign references that point at frozen objects so that they point at other objects (frozen or not.)
    So to truly freeze your constants, you must wrap them within a nested mixin module, freeze that module, and then mixin (via include) this module wherever you need to access these constants.

    module Author
      module SomePlugin
    
        module Constants
          PLATFORM_IS_WIN =(
            Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/i
          )
          PLATFORM_IS_OSX = !PLATFORM_IS_WIN
        end
        Constants.freeze
    
        include Constants
        
        # Plugin module code here can access Constants.constants
    
      end
    end
    

    Or perhaps the constants are in a separate file oustide the current plugin module. Ex …

    # constants.rb
    module Author
      module Constants
        PLATFORM_IS_WIN =(
          Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/i
        )
        PLATFORM_IS_OSX = !PLATFORM_IS_WIN
      end
      Constants.freeze
    end
    
    # plugin_main.rb
    require 'constants.rb'
    module Author
     module SomePlugin
    
       include Author::Constants
       
       # Plugin module code here can access Author::Constants.constants
    
     end
    end
    

Just my 5 cents worth … :wink:

Thanks for the observations, Dan.
Will take them into account.

1 Like

Hmm… not sure…

What type of docs? Do you have an example of how you have launced documents? (and what type of documents?)

The Windows version never auto-encoded the given URL, and we’d never heard any questions and complains about that. Given that an Windows is 90% of our userbase we felt confident at the time wasn’t a big problem. We do understand though that changes are frustrating and try to keep things working whenever possible. In this case the encoding Mac performed had problems of it’s own in that it would encode important characters such as #.

That’s not particularly constructive Barry. Keep it civil - no need to get personal.

3 Likes

I’m using it to open external SketchUp files in my reference manger and I’ve worked on extensions using it for opening PDF manuals. I used it just the other day to open .layout files generated by the SketchUp Ruby Layout API. Not sure if I’ve used it more but those are the things I can remember on the top of my head.

Can you provide a small snippet for what doesn’t work any more?

I don’t use Mac myself but this is what a user reported and how I followed up Eneroth Reference Manager - #32 by Early_Hominid.

1 Like

I also found this other thread on the topic - following up there.

In my case I believe it now fails because of underscore characters in folder or file names.
But I have no MAC I can use to test.