I’ve never noticed this before but during testing of one of my plugins I decided to show the ruby console right before the loading of the plugin. My code is the following:
THIS_DIR = File.dirname(__FILE__)
# Fix for ruby 2.0
if THIS_DIR.respond_to?(:force_encoding)
THIS_DIR = THIS_DIR.dup.force_encoding("UTF-8")
end
My error message is:
c:/users/administrator/appdata/roaming/sketchup/sketchup 2017/sketchup/plugins/medeek_foundation_ext/medeek_foundation_load.rbs:39: warning: already initialized constant Medeek_Engineering_Inc_Extensions::MedeekFoundationPlugin::THIS_DIR
c:/users/administrator/appdata/roaming/sketchup/sketchup 2017/sketchup/plugins/medeek_foundation_ext/medeek_foundation_load.rbs:36: warning: previous definition of THIS_DIR was here
I really have no idea what the problem is here or what I’m doing wrong. I guess I’ve never seen this before because I usually don’t show the console in the plugin load .rbz.
You are doing nothing wrong.
Ruby expects you to define a Constant only once.
When you reassign it there’s a warning message - as you see - but it’s still changed.
There are ways to redefine a Constant in code which suppress the error, but in your case why not recast it to only define it once, thus:
this_dir = File.dirname(__FILE__)
if this_dir.respond_to?(:force_encoding)
THIS_DIR = this_dir.force_encoding("UTF-8")
else
THIS_DIR = this_dir
end
I’m not sure I fully understand what the double pipe or equals is doing in this case, never seen that operator before. I really do learn something every day as a developer.
This works all the way back to SketchUp 2014, which is quite ancient by now. Trying to support older SU versions will make the code quite a bit bulkier and uglier as it doesn’t support a number of newer methods and idioms. EDIT: Not to mention SU API, like HtmlDialogs .
In the general case I’d use a intermediate variable and set the constant once. This is just 3 lines of code and has a single level of indentation which makes it more readable.
this_dir = File.dirname(__FILE__)
this_dir.force_encoding("UTF-8") if this_dir.respond_to?(:force_encoding)
THIS_DIR = this_dir
The warnings are there because the Ruby core devs are heading towards true constants.
Already they have implemented no dynamic constant assignment within methods.
The average user is only going to load your code once, so they’ll not likely run into the warning.
It is you (the dev) who reloads your code during development that sees the warning.
There are several ways to handle this so constants are loaded once.
The simplest is to have all your constants in one file that is loaded the first time.
Then during dev when you are tweaking things you need only reload the file that was tweaked.
The other way is to use the same pattern we use to prevent multiple menu items …
… ie, the first file to load:
module Medeek
module NiftyFoundation
if !@loaded
# define constants here
end
# define methods and classes, or load other files here, etc.
end
end
… ie, the last file to load:
module Medeek
module NiftyFoundation
if !@loaded
# define commands, menus and toolbars
@loaded = true
end
end
end
I prefer not to clutter the code with checks if the constant is already defined. Instead the debug/test reload scrip can just hide the warnings. It’s not very important if this is “proper” Ruby as it’s never used in production, just for testing. This also has the benefit that it allows you to redefine the constants without restarting SketchUp when testing, at least for as long as Ruby supports it.
# 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
# HACK: 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