Reloading my plugins

When I’m debugging my plugins I typically encounter an error, fix it, move the updated .rb or .rbz file into the current plugin folder and then restart SketchUp and try to duplicate the error again.

Sometimes it will take a few iterations before I get it right. However I’m finding that I spend a lot of time just restarting SketchUp so that it loads the updated plugin files.

Is there a way to reload a plugin without having to keep restarting SketchUp?

I’ve set up SketchUp to load extensions directly from my development folder so i don’t need to create any intermediate RBZ. The script I have in my plugins folder look like this:

pattern = "D:/Sketchup Plugins/Working Dir/*/src/"

Dir.glob(pattern).each do |dir|
  $LOAD_PATH << dir
  Dir.glob("#{dir}/*.rb").each { |p| require p }
end

This allows each project to have its own folder, corresponding to a Git repo. Each such folder has a src folder corresponding to what will become the RBZ, but also allows additional folders, e.g. for unit tests, 3D models icons are based on etc. I know ThomThom does something similarly, but explicitly lists projects to load rather than iterating all possible projects.

In my main extension file I have this method for simply reloading the extension.

# Reload extension.
#
# @param clear_console [Boolean] Whether console should be cleared.
# @param undo [Boolean] Whether last oration should be undone.
#
# @return [void]
def self.reload(clear_console = true, undo = false)
  # Hide warnings for already defined constants.
  verbose = $VERBOSE
  $VERBOSE = nil
  Dir.glob(File.join(PLUGIN_ROOT, "**/*.{rb,rbe}")).each { |f| load(f) }
  $VERBOSE = verbose

  # Use a timer to make call to method itself register to console.
  # Otherwise the user cannot use up arrow to repeat command.
  UI.start_timer(0) { SKETCHUP_CONSOLE.clear } if clear_console

  Sketchup.undo if undo

  nil
end

After having called this once I just press Arrow Up and Enter in the console a bunch of times while testing.

1 Like

I use load(rb_file) and UI.start_timer with File.mtime to auto reload

1 Like

I have this workflow:

  1. Keep your plugins folder as empty as possible on your development machine so that there is no interference from other plugins
  2. There is a startup argument for SketchUp that lets you launch sketchup auto-loading a .rb file. You can use that to auto load your extension even if it isn’t located in the plugins folder. In my development folder I have a .bat to launch SketchUp with the following content:
c:
cd C:\Program Files\SketchUp\SketchUp 2019\
SketchUp.exe -rdebug "ide port=7000" -RubyStartup "%~dp0launch.rb"
  1. This .bat tries to launch SketchUp with a .rb file named launch.rb located in the same folder as the .bat file. The contents of launch.rb is:
require "sketchup"

timer_id = UI.start_timer(0, false) {
	
	# always show the console
	SKETCHUP_CONSOLE.show

	# stop the timer
	UI.stop_timer(timer_id)
	
	src_folder = "#{File.dirname(__FILE__)}/src_extension/"
	extension_files = Dir[src_folder + "*.rb"]

	extension_files.each do |f|
		extension_name = File.basename( f, ".*" )
		extension_folder = "#{src_folder}#{extension_name}"
		$LOAD_PATH << extension_folder
		require f
	end #do
}
  1. You will notice that I do the real loading of the extension in a timer and that the real extension is located in ./src_extension/ which in return contains the extension as you would place it in the plugins folder.
  2. I use a timer because I believe that errors that occur during the initial loading of Sketchup are not outputted to the console.

Why?

  1. As mentioned, only the extension I am working on is loaded so there is no interference or time lost loading unneeded extensions.
  2. you can also specify a .skp that has to be loaded, so you do not lose time specifying and searching for your test file over and over again.
  3. I do not launch the .bat myself, but launch it from my IDE (visual studio code) in a task. Have a look at my task.json file:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "launch_SU19",
            "type": "shell",
            "command": "open -a SketchUp --args -RubyStartup \"$PWD/launch.rb\"",
            "windows": {
                "command": "./launch_SU19.bat"
            },
            "problemMatcher": []
        }
    ]
}
  1. as you see, I also have a MAC to develop and test on osx. The .bat will not work on osx, therefore this command on osx: open -a SketchUp --args -RubyStartup \"$PWD/launch.rb\"
2 Likes

Yup, same as mentioned above: use a loader script in your Plugins directory to set up additional directories to load extensions directly from your source.

The Examples/Tutorials repo have a brief example of this:

While we are at the topic of debugging - the debugger is really great for seeing what is going on without having to add/remove puts statements: https://github.com/SketchUp/sketchup-ruby-debugger

Quickest setup to get the debugger running is VS Code: https://github.com/SketchUp/sketchup-extension-vscode-project

Ruby Mine is also a great editor to debug in - though it’s a few more steps to set up the project.

1 Like

If you have Ruby installed on your machine you can use skippy: https://github.com/thomthom/skippy
skippy sketchup:debug 2019 will locate SketchUp (if it’s in the default installation path) and launch it on both Windows and Mac.

2 Likes

“rbe” and “rbs” will not work with load.

2 Likes