sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Global Object Stupidity, Ruby Question

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 6 Posters 593 Views 6 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.
    • Chris FullmerC Offline
      Chris Fullmer
      last edited by

      @martinrinehart said:

      This is just plain dumb, isn't it? My webdialog has a "window" global object. Your webdialog has another "window." You and I can choose identical "global" names, but they are attached to separate global objects. No problem. Am I missing something?

      I think the problem is that the global variable points to an object. And it can only point to one object. So if you name your global that same as someone else, then you are playing a dangerous game. The ruby that gets loaded first will define the global to point to their window object. But then the next ruby will load and redefine the global to point to their window object. Now the first ruby still thinks that the global is pointing to its winow object, but its not. So it tries to interact with its window object, but it is the wrong window object.

      At least that is my understanding.

      Chris

      Lately you've been tan, suspicious for the winter.
      All my Plugins I've written

      1 Reply Last reply Reply Quote 0
      • M Offline
        MartinRinehart
        last edited by

        @msp_greg said:

        I knew you'd get back to this...

        Looks like you were there before me.

        You explained the fixes, but not the problem. Is the problem this: there is a single Ruby workspace. If my Ruby loads and assigns to "foo", then your Ruby is loaded and it assigns to "foo" my "foo" and your "foo" are the same and I lost the race by coming in first?

        So JavaScript, which is legendary for its global object issues, in this instance has lots of window "globals" and they're all private. It's Ruby that has global object issues.

        @chris fullmer said:

        I think the problem is that the global variable points to an object. And it can only point to one object.
        Chris

        Watch out! In JavaScript in a browser "window" is the global object, so these three are all the same.

        
        foo = 123;
        var foo = 123;
        window.foo = 123;
        
        

        The first two are just shorthand for the third.

        But the "global object" is not so global. If your webdialog is flying along side mine, we both have a separate "window", so our JavaScripts have no conflicts. In fact, if you use frames, each frame has a "window" object so "window.foo" could exist and be different in each frame.

        Author, Edges to Rubies - The Complete SketchUp Tutorial at http://www.MartinRinehart.com/models/tutorial.

        1 Reply Last reply Reply Quote 0
        • Chris FullmerC Offline
          Chris Fullmer
          last edited by

          Yes, well its the same idea. In JS, each window is separate from the other. And in SketchUp, each SketchUp instance is different than the others. So you can run 2 instances of SU side by side, and the globals of your script in one window don't mess up the globals in another.

          But within a single instance of SU, all globals are in fact global. And if one script changes a global, then i rightly messes up anyone else's identically named globals. Its why they are called globals.

          If you make a window object, and point a global variable to it. Then someone else comes along and re-points that global variable to their window object, your window object still exists, it just has nothing pointed at it. And no way to access it.

          Lately you've been tan, suspicious for the winter.
          All my Plugins I've written

          1 Reply Last reply Reply Quote 0
          • fredo6F Offline
            fredo6
            last edited by

            This is just a matter of scope of the script engine.

            You will agree that if you run 2 instancesof Sketchup, the global variables are not shared (because Sketchup runs two different Ruby environment instances)

            In Java script, the scope of the script engine is at the level of the browser session (materialized by 'window').

            Anyway, Greg'advice is very relevant. You can always code without global variables. This said, Ruby'strength (or weakness) is that the exception are the constants, among which are the Module and Class names. All SU Ruby scripters should maybe maintain a table of namespace (module name) to avoid clashes.

            Fredo

            1 Reply Last reply Reply Quote 0
            • M Offline
              MartinRinehart
              last edited by

              @unknownuser said:

              All SU Ruby scripters should maybe maintain a table of namespace (module name) to avoid clashes.

              Yes, and if you find a good "how to convert your Ruby to a module" explanation, please send it my way. I tried "module vismap" at the start and "end" at the end and found out that was just the beginning.

              Author, Edges to Rubies - The Complete SketchUp Tutorial at http://www.MartinRinehart.com/models/tutorial.

              1 Reply Last reply Reply Quote 0
              • fredo6F Offline
                fredo6
                last edited by

                @martinrinehart said:

                @unknownuser said:

                All SU Ruby scripters should maybe maintain a table of namespace (module name) to avoid clashes.

                Yes, and if you find a good "how to convert your Ruby to a module" explanation, please send it my way. I tried "module vismap" at the start and "end" at the end and found out that was just the beginning.

                Then you need either:

                • to prefix your methods with the module name (or self)
                • or you create a class, and then create an instance of that class to use the method.

                Fredo

                1 Reply Last reply Reply Quote 0
                • Chris FullmerC Offline
                  Chris Fullmer
                  last edited by

                  Here's an example of a script where I've wrapped my script into a module. Like Fredo says, you then have to define each method by using "def module_name.method_name" or "def self.module_name". I've bolded the 3 things to look out for.

                  1. Define the module.
                  2. Define methods correctly
                  3. Call the methods correctly

                  ` module Clf_face_to_component
                  def Clf_face_to_component.main

                  (code here)

                  end #method
                  end #module

                  UI.menu("Plugins").add_item("Faces into Components") { Clf_face_to_component.main}`

                  Chris

                  Lately you've been tan, suspicious for the winter.
                  All my Plugins I've written

                  1 Reply Last reply Reply Quote 0
                  • J Offline
                    Jim
                    last edited by

                    For example, there is no top-level "active_model" - it is Sketchup.active_model. So if we ask Ruby what Sketchup is, we see it is a Module.

                    Sketchup.class
                    Module.
                    

                    Which, if we were to define it ourselves, might look like this:

                    
                    module Sketchup
                      def Sketchup.active_model # or self.active_model
                         return TheActiveModel
                      end
                    end
                    
                    

                    It's a way to collect related methods and avoid over-writing someone else's methods and variables.

                    You can still use classes if they are appropriate, just define them in the module.

                    
                    module ME
                      TWO_PI = 2.0 * Math;;PI # < Module-level constant
                      class Model
                      end
                    end
                    
                    

                    which would then be access externally as model = ME::Model And the constant can be access by: value = ME::TWO_PI

                    Hi

                    1 Reply Last reply Reply Quote 0
                    • M Offline
                      MartinRinehart
                      last edited by

                      Thanks, guys.

                      
                      # vismap.rb
                      
                      require 'sketchup'
                      
                      module Vismap
                      
                      class Vismap_Model
                      
                      	def initialize()
                      		@model = Sketchup.active_model
                      		@layers = @model.layers
                      		@scenes = @model.pages
                      	end
                      
                      	def layers()
                      		return @layers
                      	end
                      
                      	def layer_names()
                      		names = []
                      		@layers.each { |lr| names.push(lr.name) }
                      		return names
                      	end
                      
                      	def scenes
                      		return @scenes
                      	end
                      
                      	def scene_names()
                      		names = []
                      		@scenes.each { |s| names.push(s.name) }
                      		return names
                      	end
                      
                          # return "VIVV...", one "V"isbl or "I"nvisbl for each scene in each layer
                          def getVisibles()
                          	answer = 'V' * (@scenes.count*@layers.length)
                          	i = 0
                          	@scenes.each do |s|
                      			s.layers.each do |lr|
                      				loc = Vismap.locate( lr.name, layer_names() ) * @scenes.count
                      				loc += Vismap.locate( s.name, scene_names() )
                      				answer[loc..loc] = "I"
                      			end
                      			i += 1
                          	end
                          	return answer
                      
                          end # getVisibles()
                      
                          # JSON to send to webdialog
                          def getJson()
                          	ret = '{ '
                      		begin
                      			ret += 'layers;' + Vismap.namesJson( self.layer_names )
                      			ret += ', scenes;' + Vismap.namesJson( self.scene_names )
                      			vis = self.getVisibles()
                      			ret += ", vis;'" + vis + "'"
                      			ret += ' }'
                      		rescue
                      			errMsg = $!.to_s
                      			errMsg.gsub!( '<', '&lt;' )
                      			vis = 'vis;\"Error - ' + errMsg + '\"'
                      			ret = '{ layers;\"\", scenes;\"\",' + vis + ' }'
                      		end
                          	return ret
                      
                          end # getJson()
                      
                      	# given "VI" string (see getVisibles) sets visibilities
                      	def setVisibles( vis )
                      
                      		sn = 0 # scene number
                      		@scenes.each do |s|
                      
                      			ln = 0 # layer number
                      			@layers.each do |lr|
                      
                      				vn = ln*@scenes.count + sn # vis number
                      				v_or_i = vis[vn..vn]
                      
                      				s.set_visibility( @layers[ln], v_or_i == 'V' )
                      				ln += 1
                      
                      			end # layers.each
                      
                      			sn += 1
                      
                      		end # scenes.each
                      
                      	end # of setVisibles()
                      
                      end # of class Model
                      
                      class Bitmap
                      =begin
                      JavaScript returns the new list of Visibles and Invisibles as a bit map encoded in a string. The first three characters encode the length of the string. Each following character encodes six bits of the map. CHR(48) == 000000; CHR(49) == 000001; CHR(50) == 000010; CHR(51) == 000011; etc.
                      =end
                      	@@vismap_powers = [ 32, 16, 8, 4, 2, 1 ]
                      	@@base = 48
                      
                      	def initialize( map )
                      		@map = map
                      		self.getLength() # sets @length
                      		self.getVis()    # sets @vis
                      	end # end of initialize()
                      	
                      	def length()
                      		return @length
                      	end
                      	
                      	def vis()
                      		return @vis
                      	end
                      	
                      	def getVis()
                      		@vis = ''
                      		bits = @map[3,@map.length - 3]
                      		(0..bits.length-1).each do |i|
                      			word = bits[i]
                      			word -= @@base;
                      			@vis += self.getVisFromWord( word )
                      			@vis = @vis[0, @length]
                      		end
                      	end
                      	
                      	def getVisFromWord( word )
                      		v = ''
                      		@@vismap_powers.each do |p|
                      			v += ( p & word ) > 0 ? 'V' ; 'I'
                      		end
                      		return v
                      	end
                      	
                      	def getLength()
                      		@length = 64 * 64 * ( @map[0] - @@base )
                      		@length += 64 * ( @map[1] - @@base )
                      		@length += @map[2] - @@base;
                      	end
                      	
                      end # of class Bitmap
                      
                      def self.check( len )
                      	nlrs = $vismap_model.layers().length
                      	nsns = $vismap_model.scenes().count 
                      	ok = ( len == (nlrs * nsns) )
                      	
                      	UI;;messagebox(
                      		"Wrong number of layers and/or scenes \n" +
                      		"Click \"Get Data from Model\" and try again." ) if ( !ok ) 
                      			
                      	return ok
                      end
                      
                      def self.launchWebDialog
                      
                      	wd = UI;;WebDialog.new( "Layer/Scene Visibility Map", true, 
                      			'vismap_v1.0', 400, 300, 100, 500, true )
                      
                          wd.add_action_callback( "refresh" ) do |js_wd, msg|
                      		reloadModel()
                          	json = $vismap_model.getJson
                          	script = 'rubyReturned( "' + json + '" );'
                      		# puts script
                          	js_wd.execute_script( script )
                          end
                      	
                          wd.add_action_callback( "newVis" ) do |js_wd, msg|
                      
                      		reloadModel()
                      		
                      		unless msg.nil?() 
                      			map = Bitmap.new( msg )
                      			$vismap_model.setVisibles( map.vis ) if Vismap.check( map.length() ) 
                      		end
                      				
                      	end # of newVis()
                      	
                      	pathname = Sketchup.find_support_file( 'vismap.html', 'Plugins/vismap/' )
                          wd.set_file( pathname  )
                          wd.show()
                      
                      end # launchWebDialog()
                      
                      def self.reloadModel()
                      	$vismap_model = Vismap_Model.new
                      end
                      
                      # true if any member of array matches item
                      def self.is_in( item, array )
                      	return self.locate( item, array ) > -1
                      end
                      
                      # index of item in array (-1 == not found)
                      def self.locate( item, array )
                      	i = 0
                      	array.each do |a|
                      		return i if (a == item)
                      		i += 1
                      	end
                      	return -1
                      end
                      
                      # convert array of names to JSON array
                      def self.namesJson( names )
                      
                      	ret = '[ '
                      	start = true
                      	names.each do |n|
                      		unless start
                      			ret += ', '
                      		else
                      			start = false
                      		end
                      		ret += quote( n )	
                      	end
                      	ret += ' ]'
                      	return ret
                      
                      end # namesJson()
                      
                      # convert name (which may contain embedded quotes) to name in quotes
                      def self.quote( name )
                      	name.gsub!( '"', '\"' )
                      	name.gsub!( "'", "\'" )
                      	#	name.gsub!( "\", "\\\\" ) # how do you do this in Ruby?
                      	return "'" + name + "'"
                      end
                      
                      launchWebDialog()
                      
                      end # module Vismap
                      
                      # end of vismap.rb
                      
                      

                      Author, Edges to Rubies - The Complete SketchUp Tutorial at http://www.MartinRinehart.com/models/tutorial.

                      1 Reply Last reply Reply Quote 0
                      • N Offline
                        NewOne
                        last edited by

                        I think this can help to understand modules. Since a few hours ago, I did not had any idea about what modules are. This gave me a clue.
                        I hope others will find it enlighting too. 💭
                        http://www.rubyfleebie.com/an-introduction-to-modules-part-1/

                        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