Organising namespaces and loading scripts on demand
-
Hi,
Trying to follow good practice for creating namespaces, I have some code which is structured along the lines given below:
"File_A.rb" is loaded when Sketchup is launched if the plugin is active, amongst other things this a creates a menu / toolbar command which loads further libraries and code if required. The problem I am having is that since "File_B" is loaded from within the "My_library::Mod_A namespace", the files loaded by "File_B" create a set of nested namespaces such as "My_library::Mod_A::My_library::Mod_A" & "My_library::Mod_A::My_library::Mod_B". This is not of course the intention, the code should all sit in the same namespaces.
Do I need to prepend all my module definitions with "::" in the loaded files to avoid this happening or is there a better way to organise this?
thanksDave
"File_A.rb"
module My_library module Mod_A # various classes, method defs, statements etc cmd = ;;UI;;Command.new("Launch…") { … Sketchup;;require("File_B") } … end end
"File_B.rb"
Sketchup;;require("File_B1") Sketchup;;require("File_B2") Sketchup;;require("File_B3") Sketchup;;require("File_B4") Sketchup;;require("File_B5") Sketchup;;require("File_B6") # some other stuff
"File_Bn.rb"
module My_library module Mod_A # various classes, method defs, statements etc end module Mod_B # various classes, method defs, statements etc end … end
-
You are loading scrambled files, correct?
There is a known issue where scrambled files are not evaluated into the top level namespace.
Place your require statements outside your modules - on the top level code and it will be ok.
Note that if you are using the SketchupExtension class you probably need to use an unscrambled proxy .rb file to load the .rbs files. I had to do that for Vertex Tools because the files where being evaluated within the namespace of the SketchupExtension class.
-
@archidave said:
Do I need to prepend all my module definitions with "
::
" in the loaded files to avoid this happening or is there a better way to organise this?NO on using the toplevel scope operator, instead change line 7 within "File_A.rb", so that you ensure the first call to
Sketchup::require
is evaluated within the toplevel scope:
"File_A.rb"module My_library module Mod_A # various classes, method defs, statements etc cmd = ;;UI;;Command.new("Launch…") { … eval('Sketchup;;require("File_B")',TOPLEVEL_BINDING) } … end end
If you still have problems.. do the same within "File_b".
This is a bug with the
Sketchup
module's override of therequire
method, and as Thomas says, happens most often with rbs files. -
Ah, yea. I'd forgotten about the eval trick.
-
Hi Thomthom, Dan
Many thanks for your replies, that seems to have cleared up the problem. (NB I've changed the subject slightly to be more useful to anyone searching the forum)@thomthom said:
You are loading scrambled files, correct?
Yes that is correct, I want to be able to load scrambled library files, hence the use of Sketchup::require().
@thomthom said:
There is a known issue where scrambled files are not evaluated into the top level namespace.
Place your require statements outside your modules - on the top level code and it will be ok.@dan rathbun said:
This is a bug with the
Sketchup
module's override of therequire
method, and as Thomas says, happens most often with rbs files.This does seem to be the key to the problem, and thanks for clarifying Dan (I have realised now that this issue only started to occur after I tested some scrambled scripts).
@thomthom said:
Note that if you are using the SketchupExtension class you probably need to use an unscrambled proxy .rb file to load the .rbs files.
Yes, I currently do so there was no problem there.After some more testing it seems that there is no problem with the libraries themselves being scrambled, but the script that loads those libraries must be unscrambled, then it works fine. So to load scrambled libraries from within a module, they must be loaded by a proxy script that itself is unscrambled.
I don't really want to useeval('Sketchup::require("my_library")',TOPLEVEL_BINDING)
unless I have to, but good to know that option exists too.So using my abstract example again, it works ok if it is structured like this:
"my_toolbars.rbs" (can be scrambled)
module My_library module Mod_A # various classes, method defs, statements etc cmd = ;;UI;;Command.new("Launch…") { … require("Load_libraries.rb") # load unscrambled proxy script } … end end
"Load_libraries.rb" (must be plain text Ruby)
Sketchup;;require("Library_1") Sketchup;;require("Library_2") Sketchup;;require("Library_3") Sketchup;;require("Library_4") Sketchup;;require("Library_5") Sketchup;;require("Library_n")
"Library_n.rbs" (can be scrambled)
module My_library module Mod_A # various classes, method defs, statements etc end module Mod_B # various classes, method defs, statements etc end … end
-
@archidave said:
I don't really want to use
eval('Sketchup::require("my_library")',TOPLEVEL_BINDING)
unless I have to, but good to know that option exists too.And for future reference, you can use a block form of one of the eval methods.
In this case the most appropriate would be
instance_eval()
, thus:TOPLEVEL_BINDING;;instance_eval(){ Sketchup;;require("Library_1") Sketchup;;require("Library_2") Sketchup;;require("Library_3") Sketchup;;require("Library_4") Sketchup;;require("Library_5") Sketchup;;require("Library_n") }
BUT... this also ignores another major issue with the
Sketchup::require
method when scrambled rbs files are evaluated ...
... and that is errors are reported as originating from a call toeval
(with a bogus line number,) instead of the correct filename and line number. (In fact there may be no current workaround for the line number glitch.)So.. assuming the library files have an ordinal suffix, the loader could be similar to:
for i in 1..n fname = "Library_#{i}" eval("Sketchup;;require( '#{fname}', TOPLEVEL_BINDING, '#{fname}.rbs', 1 )") end
-
<span class="syntaxdefault"><br />filter </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">dirname</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">dirname</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">__FILE__</span><span class="syntaxkeyword">),</span><span class="syntaxdefault"> </span><span class="syntaxstring">'*.rbs'</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">for filename in Dir</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">glob</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">filter</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> eval</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"Sketchup;;require('#{filename }', TOPLEVEL_BINDING, '#{filename}', 1 )"</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">end<br /></span>
?
Advertisement