Weirdest loading bug ever?
-
This is such a strange issue, I don't even know how to describe it properly.
I am developing a plugin for distribution, and therefore I am using scrambled files. I do most of my coding/debugging with the unscrambled files and only load the scrambled files to make sure they work before I send them to my boss. We're just now entering the testing phase.
I only noticed I had an issue when I realized one of my messageboxes was wrong while I was using the scrambled files. It was a silly bug - it had a blank where it needed a dropdown. I fixed it, scrambled it, restarted sketchup - and the blank was still there. So I reworked that messagebox and reordered the inputs, scrambled, reloaded - and it was still the same (wrong) messagebox from before. When I loaded the unscrambled version, the messagebox was fixed, but as soon as I tried to load a scrambled version it was wrong again.
I thought it might be the scrambler, that maybe it was just outputting the wrong file, but when I added or removed comments the scrambled file changed size. I thought it might be a caching issue, so I shut down my computer - but it was still there the next day.
So then, on a whim, I renamed the folder I was loading the plugin from. The images were gone, but my plugin still popped up and worked! The wrong messagebox version, of course.
I was able to load my plugin on a borrowed laptop just to make sure the scrambled files are actually correct, but now I'm worried that I'll be giving out new versions to my testers and this weird glitch is going to keep the older version there, especially since this glitch has appeared on my boss's computer as well.
I am completely flabbergasted, I have no idea how this is even possible. I am using Sketchup.load(extension_name) and Sketchup version 7 running on Windows 7, and my boss has Sketchup 7 running on Windows XP.
Has anybody else had this issue? Is there some sort of unload or reload command that I need to include to make sure Sketchup is using the correct files? Is this a known bug they fixed with Sketchup 8? Or am I the only one with this problem?
-
Thanks for all your help! But I'm not sure I understand - is it better to have the loading script inside the widget folder instead of the plugin folder?
My current loading script is inside the plugin folder, and goes something like this:
Sketchup.load('LothCatWidget/widget') WIDGET_tool = WIDGETmaker.new plugins = "LothCatWidget/" imgdir = plugins # create toolbar tb = UI;;Toolbar.new("LothCatWidget Toolbar") # Button 1 cmd = UI;;Command.new("Widget") { Sketchup.active_model.select_tool WIDGET_tool } cmd.large_icon = cmd.small_icon = File.join(imgdir, "WIDGET.png") cmd.status_bar_text = cmd.tooltip = "Widget" tb.add_item cmd
Would it be better to have this script inside the folder? Do I need to separate out the 'load' command from the toolbar script? And are you saying that it's the fact that I'm using Sketchup.load instead of Sketchup.require that's causing my weird bug?
-
@dan rathbun said:
Also.. the image paths for toolbar cmds, in rbs may give you problems...
I went for a swim, and thot about this some more.
I remembered finding images could be a problem, so I looked at several Google supplied examples.
The
UI::Command
instance methodslarge_icon()
andsmall_icon()
can (in unscrambled rb files,) take either an absolute path, or a relative path (that is relative to the dir that the ruby script is in, NOT relative to the Plugins folder.)A scrambled rbs file CAN take an absolute path. But I don't know if it can take a relative path.
-
@lothcat said:
Thanks for all your help! But I'm not sure I understand - is it better to have the loading script inside the widget folder instead of the plugin folder?
YES.
- The only file in the Plugins folder is as I showed above, the file that registers the plugin with Sketchup, so it can be enabled / disabled with the Window (menu) > Preferences (dialog) > Extensions (panel)
@lothcat said:
My current loading script is inside the plugin folder, and goes something like this:
Sketchup.load('LothCatWidget/widget')
Remove this first line.. and create the "lothcat/widget/widget_loader.rb" file as above.- You should have an "author" subdir for all YOUR plugins, beneath the Plugins dir.* For example.. we call it "lothcat" (but it could be a company name, if you release plugins thru a company. As long as it's unique. Don't use some other entity's trademarked name, like Coca-Cola!)* Then, EACH separate plugin of your's, goes in a separate subdir of your "author" subdir.* A specific plugin subdir, can have it's own subdirs, if you wish, such as "images"* It's all about organizing, your OWN "filespace"...* ... but more importantly, not mixing up YOUR files with everyone else's, ...* ... and keeping the files for each of YOUR separate plugins from getting mixed up together.
@lothcat said:
Do I need to separate out the 'load' command from the toolbar script?
It becomes a one-line script, named widget_loader.rb (as shown above,) saved into the widget dir, of YOUR "author/company" dir (which we call "lothcat" here for example.)
@lothcat said:And are you saying that it's the fact that I'm using
Sketchup.load
instead ofSketchup.require
that's causing my weird bug?
Well.. you mentioned strange things happening if files get loaded twice. Use the require method to be sure the "package" is loaded only once.Did you use
__FILE__
anywhere to build paths to datafiles or image files ??Also.. the image paths for toolbar cmds, in rbs may give you problems... see below:
@lothcat said:
WIDGET_tool = WIDGETmaker.new > > plugins = "LothCatWidget/" > imgdir = plugins > > > # create toolbar > tb = UI;;Toolbar.new("LothCatWidget Toolbar") > > # Button 1 > cmd = UI;;Command.new("Widget") { Sketchup.active_model.select_tool WIDGET_tool } > cmd.large_icon = cmd.small_icon = File.join(imgdir, "WIDGET.png") > cmd.status_bar_text = cmd.tooltip = "Widget" > tb.add_item cmd >
Would it be better to have this script inside the folder?
YES... the script snippet above, along with your
Tool
class definition, needs to be wrapped in your plugin namespace. (Your defining it at the TOPLEVEL which is withinObject
.)
It would be scrambled as "widget.rbs", and saved into the "widget" dir, beneath your "author/company" dir ("lothcat" or whatever name you use.)I'd also suggest (since you are within your namespace
Lothcat::Widget
, that you use either a constant, or a module @@var to hold your toolbar reference.Like so:
# widget.rbs require('sketchup.rb') module Lothcat;;Widget # The constants PATH, ABSDIR, RELDIR, RBSFILE, etc., can be # accessed here because they are local to this namespace. # The same is true for the module var @@plugin, which is the # reference to your SketchupExtension plugin instance. def self.plugin() @@plugin end class WIDGETmaker # your Tool class definition end #class WIDGET_tool = WIDGETmaker.new def self.tool() WIDGET_tool end # plugins = "LothCatWidget/" # dont need, use local constant # RELDIR defined in "plugins/lothcat_widget_ext.rb" # # imgdir = plugins # this may have problems in rbs # try an absolute path, use ABSDIR; imgdir = ABSDIR # or ABSDIR + "/images" if in a subdir # do only once block # unless file_loaded?( RBSFILE ) # create toolbar @@toolbar = UI;;Toolbar.new("LothCatWidget Toolbar") def self.toolbar() @@toolbar end # Button 1 cmd = UI;;Command.new("Widget") { Sketchup.active_model.select_tool WIDGET_tool } cmd.large_icon = cmd.small_icon = File.join(imgdir, "WIDGET.png") cmd.status_bar_text = cmd.tooltip = "Widget" @@toolbar.add_item cmd file_loaded( RBSFILE ) end # unless # The rest of your scrambled code goes here. # Can have nested submodules and class definitions, etc. end #mod Lothcat;;Widget
-
Fixed code examples above (added a RBSFILE constant.)
Also created a generic [ Code ] example thread (per request.)
-
There are a few quirks you need to be aware of with scrambled rubies.
1) If your using the
SketchupExtension
class (see file Tools/extensions.rb,) the file refered to in thepath
attribute must be an unscrambled script. Convention is that it is named with a "_loader.rb" suffix. So if the name of your plugin is "widget" then the registration script in the plugins folder would be "lothcat_widget_ext.rb", which sets the path to "lothcat/widget/widget_loader.rb" (in your plugin subfolder, of your author subfolder, which you should be using, by the way.)
The script for "lothcat/widget/widget_loader.rb" would be a one-liner, that simply says:
Sketchup.require("lothcat/widget/widget")
which will (if it isn't loaded,) will callSketchup.load("lothcat/widget/widget.rbs")
2) **Special Ruby vars**The special Ruby keywords (actually built-in functions,)
__FILE__
and__LINE__
do NOT work inside scrambled rbs scripts (as of v8.0M1.) This is because scrambled scripts are loaded into the system as an encrypted String, decrypted bySketchup.load()
internally into a plain text String, and that String is then passed as the argument to theObject.eval()
method. Google neglected to search and replace those two constants, before passing the code String toeval
. I've reported it in the last beta round, and we've complained about it all thru the ver 7 lifecycle as well.
Hoping it will be fixed in the next release.Workaround:
Keep a reference to your
SketchupExtension
instance object, by doing this for your extension registration script (this file goes in the main Plugins folder.)
lothcat_widget_ext.rbrequire('extensions.rb') module Lothcat # Proprietary TopLevel Namespace; No Tresspassing! module Widget # Namespace for THIS plugin # Create an entry in the Extension list that loads # a script called; "lothcat/widget/widget_loader.rb" @@plugin = SketchupExtension.new( "Lothcat's Widget", "lothcat/widget/widget_loader.rb" ) @@plugin.creator = 'Lothcat' @@plugin.copyright = "(c)2011 by Lothcat" @@plugin.version = '1.0.0' @@plugin.description = "A Widget that does fancy things." Sketchup.register_extension( @@plugin, true ) unless @@plugin.class.method_defined?(;path) # # define a singleton method for @@plugin to access the path attribute # (because Google did not do it in extensions.rb !!) # def @@plugin.path() @path end end # unless # Create local path and filename constants; # PATH = @@plugin.path() LOADER_SUFFIX = '_loader' LOADER = File.basename(PATH) RBSFILE = LOADER.split("_")[0] << '.rbs' # RELDIR is relative to Plugins dir, OR the dir from # the $LOAD_PATH array that require used to find it. RELDIR = File.dirname(PATH) ABSDIR = File.expand_path(RELDIR) # absolute path end # module Lothcat;;Widget end # module Lothcat
"lothcat/widget/widget_loader.rb"
Sketchup.require("lothcat/widget/widget")
Now all of the code in the "lothcat/widget/widget.rbs" file should also be namespace wrapped within module
Lothcat::Widget
like so:require('sketchup.rb') module Lothcat;;Widget # The constants PATH, ABSDIR, RELDIR, RBSFILE, etc., can be # accessed here because they are local to this namespace. # The same is true for the module var @@plugin, which is the # reference to your SketchupExtension plugin instance. # The rest of your scrambled code goes here. # Can have nested submodules and class definitions, etc. ### Do only once block # unless file_loaded?( RBSFILE ) # define menu items and toolbars file_loaded( RBSFILE ) end # once block end #mod Lothcat;;Widget
-
I'm trying to use this loader, but I keep getting errors. Specifically:
Error Loading File F:/Program Files (x86)/Google/Google SketchUp 7/Plugins/lothcat/widget/widget.rb
uninitialized constant Lothcat::Widget::RBSFILEError Loading File F:/Program Files (x86)/Google/Google SketchUp 7/Plugins/lothcat/widget/widget_loader.rb
uninitialized constant Lothcat::Widget::RBSFILEError Loading File lothcat_widget_ext.rb
uninitialized constant Lothcat::Widget::RBSFILEWhen I changed the names, I still get an uninitialized constant error.
-
Are you loading the "lothcat/widget/widget.rb" directly using the
load()
command at the console?
If so you need to first load "lothcat_widget_ext.rb" where theRBSFILE
constant gets defined.You need to learn how to debug !! I cannot always do it for you.
I inserted debugging puts() statements into the "lothcat_wigdet_ext.rb" file, like so:# Create local path and filename constants; # PATH = @@plugin.path() puts "Lothcat;;Widget;;PATH = '#{PATH}'" LOADER_SUFFIX = '_loader' LOADER = File.basename(PATH) puts "Lothcat;;Widget;;LOADER = '#{LOADER}'" RBSFILE = LOADER.split("_")[0] << '.rbs' puts "Lothcat;;Widget;;RBSFILE = '#{RBSFILE}'" # RELDIR is relative to Plugins dir, OR the dir from # the $LOAD_PATH array that require used to find it. RELDIR = File.dirname(PATH) puts "Lothcat;;Widget;;RELDIR = '#{RELDIR}'" ABSDIR = File.expand_path(RELDIR) # absolute path puts "Lothcat;;Widget;;ABSDIR = '#{ABSDIR}'"
I then loaded the file, and the console output was:
Lothcat::Widget::PATH = 'lothcat/widget/widget_loader.rb' Lothcat::Widget::LOADER = 'widget_loader.rb' Lothcat::Widget::RBSFILE = 'widget.rbs' Lothcat::Widget::RELDIR = 'lothcat/widget' Lothcat::Widget::ABSDIR = 'F:/Program Files (x86)/Google/Google SketchUp 7/Plugins/lothcat/widget'
Looks to me like you are not loading loading the extension registration script, before the plugin script.
-
Also... the "lothcat/widget/widget_loader.rb" can be changed so it autoloads either an rb or an rbs file.
This can make it easier during development."lothcat/widget/widget_loader.rb"
# # "widget_loader.rb" # require('sketchup.rb') module Lothcat;;Widget # Namespace for THIS plugin # Conditionally loads a script: # 1) trys; "lothcat/widget/widget.rb" # 2) trys; "lothcat/widget/widget.rbs" begin require(File.join(RELDIR,"widget.rb")) rescue LoadError ==> e if e.message.include?("no such file to load -- #{RELDIR}/widget.rb") begin Sketchup.require(File.join(RELDIR,"widget.rbs")) rescue raise else unless file_loaded?(File.join(RELDIR,File.basename(__FILE__))) file_loaded(File.join(RELDIR,File.basename(__FILE__))) end # if not loaded end else raise # just reraise the error end else unless file_loaded?(File.join(RELDIR,File.basename(__FILE__))) file_loaded(File.join(RELDIR,File.basename(__FILE__))) end # if not loaded end end # module Lothcat;;Widget
-
You're right, I'm leaning on you a lot - it's because you're introducing a ton of stuff here that I've never used, and I wasn't even sure where to begin debugging. I'm still new to this.
I tried modifying your code to my module, but when it didn't work, I tried making the snippets exactly how you wrote them.
I'm putting the ext file in the plugin folder, and the others under lothcat/widget, then starting up sketchup rather than using load. The error is what appears on startup. I thought maybe it was loading the files in the @@plugin statement, so I moved that further down... and that didn't work either.
I can fiddle with it on my own for a while to try to find the problem.
Thank you so much for your help!
-
Why are you still using Sketchup 7 ??
Version 8 fixes all manner of bugs, and runs Ruby v1.8.6-p287
SU 7, "out-of-the-box" still has Ruby v1.8.0 (initial rel.)If you don't want to move up to ver 8, at the very least, update the Ruby DLL in the "Sketchup 7" dir, to v1.8.6-p287.
Get it here: Ruby Interpreter DLLs (Win32)
-
I'm still using seven because I want to make sure that everyone in the company can use it, but if I have to force people to upgrade, so be it.
Turning off the RELDIR/ABSDIR calls seems to fix it for now.
-
@lothcat said:
I'm still using seven because I want to make sure that everyone in the company can use it, but if I have to force people to upgrade, so be it.
Well OK.. but update the DLL to v1.8.6-p287, at least. Then retry the code.
@lothcat said:
Turning off the RELDIR/ABSDIR calls seems to fix it for now.
That does not make sense.. and is not a real solution.
When you get an error during Sketchup startup.. the display of the error messages are hard to read in that little box. Press the OK button, and let Sketchup finish loading.
Immediately open the Ruby Console.
and type$!
(The last error message will be redisplayed.)
... then immediately, typeputs $@
(The backtrace for that last error will be displayed.)Don't make any typo errors in the console, or those two variables will lose the info from the LoadError, and take on new typo booboo error!
The backtrace will list the error and the filename where the error occured, followed by a colon, and the line number from the code.
Then the same for the file and line that called the previous line, and so on, all the way back to the original require() call, that tried to load "lothcat_widget_ext.rb"So it's the first line of the backtrace where the actual error occurs. The backtrace you sent earlier shows that some of those constants may not be getting set.
I will bet that it's because your running Ruby v1.8.0, update that DLL.
Debugging tip. Always verify that the first file to load, is correct. So debug the extension registration script, and all those constant will be available in the plugin file.
-
Ok found it!!!
Duh (slap me.)
File.expand_path
assumes the relative path is from the current working directory.
Which you can get:
Dir.getwd
So in the example above:
(line 42)ABSDIR = File.expand_path(RELDIR)
# absolute path
will be wrong.I'm doing this in my files now:
ROOT = $LOAD_PATH.find(false) do |abspath| Kernel.test(?d, File.join(abspath,RELDIR) ) end if ROOT ABSDIR = File.join( ROOT, RELDIR ) else # assume the target dir is directly below, the dir that THIS file is in. ABSDIR = File.join( File.dirname(__FILE__), RELDIR ) end
-
Thank you so much! It's working now and I'm not having that weird loading bug!
Also, thank you for being patient with me. This was a real learning experience.
-
Advertisement