sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Organising namespaces and loading scripts on demand

    Scheduled Pinned Locked Moved Developers' Forum
    7 Posts 3 Posters 260 Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • A Offline
      archidave
      last edited by

      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?
      thanks

      Dave

      "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
      
      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by

        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.

        Thomas Thomassen — SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • Dan RathbunD Offline
          Dan Rathbun
          last edited by

          @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 the require method, and as Thomas says, happens most often with rbs files.

          💭

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • thomthomT Offline
            thomthom
            last edited by

            Ah, yea. I'd forgotten about the eval trick.

            Thomas Thomassen — SketchUp Monkey & Coding addict
            List of my plugins and link to the CookieWare fund

            1 Reply Last reply Reply Quote 0
            • A Offline
              archidave
              last edited by

              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 the require 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 use eval('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
              
              1 Reply Last reply Reply Quote 0
              • Dan RathbunD Offline
                Dan Rathbun
                last edited by

                @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 to eval (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
                

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • thomthomT Offline
                  thomthom
                  last edited by

                  <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>
                  

                  ?

                  Thomas Thomassen — SketchUp Monkey & Coding addict
                  List of my plugins and link to the CookieWare fund

                  1 Reply Last reply Reply Quote 0
                  • 1 / 1
                  • First post
                    Last post
                  Buy SketchPlus
                  Buy SUbD
                  Buy WrapR
                  Buy eBook
                  Buy Modelur
                  Buy Vertex Tools
                  Buy SketchCuisine
                  Buy FormFonts

                  Advertisement