• Login
sketchucation logo sketchucation
  • Login
⚠️ Libfredo 15.4b | Minor release with bugfixes and improvements Update

Saving all instance variables of an object

Scheduled Pinned Locked Moved Developers' Forum
14 Posts 4 Posters 1.1k Views 4 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
    abakobo
    last edited by 13 Jul 2015, 17:22

    Hi

    I wonder if i can create functions that load/saves all the instance variables of an object in a convenient way that could be used after for any object... (or/and if it has been done already (couldn't find it on Google..))
    I've just started to use .each and other ruby nice stuffs so i'm a bit confused and don't know what is actualy possible.

    Saving

    
    def Save_Obj_Inst_Vars(FILENAME,object)
    
     fileout = File.open FILENAME, "w+"
    
     fileout.puts object.class #write the class type to check compatibility when loading
    
     object.instance_variables.each do |the_var|
      fileout.puts the_var.class
      fileout.puts the_var
     end
     fileout.close
    
    end
    
    

    Loading

    
    def Load_Obj_Inst_Var(FILENAME,object)
    
     filein = File.open FILENAME, "r"
     filein.rewind #needed if file was not closed?
    
     class_type=filein.gets 
    
     if class_type==object.class 
      object.instance_variables.each do |the_var|
       typ=filein.gets
       val=filein.gets
       case typ
        when 'int'
         val=val.to_i
        when 'float'
         val=val.to_f
        when 'bool'
         val=val.to_b
        when 'string'
         # already string? do nothing?
       end
       the_var=val
      end
     else
      puts 'bad type!'
     end
    
     filein.close
    
    end
    
    

    Do I have a chance to get something like that working? will the instance_variables array be in the same order all the time with the ".instance_variables" method so I can load it safely? What would be a classy ruby code style to do this? Can I differentiate public and private instance variable (the ones with att_accessor)?

    many thanks

    ako

    1 Reply Last reply Reply Quote 0
    • D Offline
      Dan Rathbun
      last edited by 14 Jul 2015, 02:52

      @abakobo said:

      Do I have a chance to get something like that working?

      (1) Always use the block form of File.open so the file is automatically closed.

      The names returned by the array have "@" at the beginning of them.

      In Ruby 1.8.x, the members are all strings, in Ruby 2.x the members are all symbols.

      If it were me, and I was not going to use Marshal, I'd use a comma separated format:
      puts "%s,%s,%s" % [ the_var.to_s, eval(the_var.to_s).class.name, eval(the_var.to_s).to_s.inspect ]

      Right now I am just using Sketchup::write_default() and Sketchup::read_default() to store and recall plugin variables.

      But there are library utilities like PStore:
      http://phrogz.net/ProgrammingRuby/lib_standard.html#PStore

      @abakobo said:

      ... will the instance_variables array be in the same order all the time with the ".instance_variables" method so I can load it safely?

      No, do not count on any particular order. Always refer to variables by their reference name.

      But I do not understand what you mean by "the instance_variables array" as opposed to the ".instance_variables method". The former (array) is returned by the introspection method, and it is an array of string or symbol names of the variables, not the objects that the variables reference.

      @abakobo said:

      What would be a classy ruby code style to do this?

      There is [url=http://ruby-doc.org/core-2.0.0/Marshal.html:1ko8kfu8]Marshal[/url:1ko8kfu8].
      You can define marshal_dump and marshal_load methods for your classes to leverage this feature.

      @abakobo said:

      Can I differentiate public and private instance variable (the ones with att_accessor)?

      There really is no such thing as private instance variables.

      But you can look through an array returned by instance_methods() to see if there is a method with the same name as a given instance variable. (But that is not an absolute assurance that the method was created with the attribute methods.)

      The methodname strings or symbols will not have the "@" symbol at the beginning.
      So you'll need to strip the "@" off the var name for comparison:
      if obj.instance_methods().find {|meth| the_var.to_s[1..-1] == meth.to_s }
      If there is an accessor method, it will be returned and eval true by if, but if not in the array, nil is returned by find, and eval'd as false.

      I'm not here much anymore.

      1 Reply Last reply Reply Quote 0
      • A Offline
        abakobo
        last edited by 14 Jul 2015, 09:10

        Thank you very much!

        This helped me a lot and I have ALL the infos I needed!

        ako

        1 Reply Last reply Reply Quote 0
        • A Offline
          abakobo
          last edited by 14 Jul 2015, 18:02

          Hi

          I decided to use Marshal as I suppose I won't do better! 😜 (though it's version dependent and has some security issues)

          I found some code examples modified and ran it... cool stuff. But there are two things I don't understand in the code I copied!

          
          class MyObject 
          	
          	def initialize(value)  
          		@value = value 
          		@arr= [4,5,6]
          	end  
          	attr_accessor ;value, ;arr
          	
          	def incr
          		@value=@value+1
          	end
          	
          end  
          
          
          obj=MyObject.new(99)
          
          file_name=UI.savepanel("Save","",".oob")
          
          File.open(file_name, 'w+') do |f|
          	Marshal.dump(obj, f) 
          end
          
          
          File.open(file_name) do |f|  
          	@obj2 = Marshal.load(f)  
          end  
          
          obj3=@obj2.clone
          obj3.incr
          puts obj3.value,obj3.arr
          
          

          Why must I use @ or $ for my obj2?

          And why the code below doesn't close the file in comparaison to the one above. Is that the "block form" advised in Dan's post? I miss the mechanics of that "do ||" statement, I tought it was just a looping tool. ---> I read this now: http://blog.rubybestpractices.com/posts/gregory/009-beautiful-blocks.html

          
          f=File.open(file_name, 'w+')
          puts f
          Marshal.dump(obj, f)
          
          #need f.close!
          
          

          Thanks a lot for your answers!

          ako

          1 Reply Last reply Reply Quote 0
          • S Offline
            slbaumgartner
            last edited by 15 Jul 2015, 14:07

            @abakobo said:

            Why must I use @ or $ for my obj2?
            [

            These prefixes are part of the names of variables. They tell Ruby what scope the variables belong to (@ for attributes of objects, $ for globals - there is also @@ for class variables). Variables without one of these leading characters are local to the code scope where they appear.

            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by 17 Jul 2015, 18:32

              @slbaumgartner said:

              They tell Ruby what scope the variables belong to (@ for attributes of objects, $ for globals

              And for the record - global variables should be avoided. In Extension Warehouse they are an immediate rejection.

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

              1 Reply Last reply Reply Quote 0
              • D Offline
                Dan Rathbun
                last edited by 18 Jul 2015, 10:41

                @thomthom said:

                And for the record - global variables should be avoided. In Extension Warehouse they are an immediate rejection.

                And yet.. the global objectspace is still cluttered with global variables created by SketchUp Team extensions!

                Many of these are for LanguageHandler instances that are no longer needed once the Preferences UI strings have been loaded, or a local extension hash loaded with strings.

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • thomthomT Offline
                  thomthom
                  last edited by 19 Jul 2015, 08:59

                  Yea - there's a need for a cleanup for the old SketchUp extensions.

                  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
                    abakobo
                    last edited by 4 Aug 2015, 17:06

                    I tried to save an object containing an SKUI window object (using marshal) and had a bad type error... I suppose it's not possible to save an SKUI window with marshal due to it's limitations:

                    *Marshal can't dump following objects:

                    anonymous Class/Module.
                    
                    objects which related to its system (ex: Dir, File::Stat, IO, File, Socket and so on)
                    
                    an instance of MatchData, Data, Method, UnboundMethod, Proc, Thread, ThreadGroup, Continuation
                    
                    objects which defines singleton methods*
                    

                    I did it manualy this time but wonder if there's something similar to Marshal with what I would be able to save objects containing SKUI windows for later use.

                    I remeber i saw somthing with a name looking like "yalm"..
                    Would Pstore do it?

                    Many Thanks

                    ako

                    1 Reply Last reply Reply Quote 0
                    • thomthomT Offline
                      thomthom
                      last edited by 4 Aug 2015, 17:25

                      Classes needs to implement support for marshalling. In the case of SKUI the Window class holds on to references to UI::WebDialog - which cannot be serialized. This also is also the case for Sketchup::Entity derived classes.

                      Btw, why are you trying to marshall a SKUI Window? Are you trying to save the window position?
                      Or are you trying to save the whole state of it - including HTML content and session?

                      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
                        abakobo
                        last edited by 4 Aug 2015, 18:09

                        I'm trying to save all the .visible? .caption(for lbls) and .value(for inputs) for now.

                        I would like to create a window where there's a "add item" on the window that add a SKUI_group on the window corresponding to the new item...
                        My object have only two instance variables for now, the number of items(an int) and the SKUI window.

                        For the non customisable plugin I could save the .visible? .caption and .value by listing them manualy in my Save method but with a customizable window it would probably be painful...

                        thanks for your answers
                        AND THANKS A LOT FOR SKUI (sorry for shouting but i really mean it)

                        P.S. I noticed a little bug: I have to initialise myself the .visible of each visible unmodified SKUI items before saving them because it was returning nil with the .visible? method if .visible= was never used.

                        1 Reply Last reply Reply Quote 0
                        • thomthomT Offline
                          thomthom
                          last edited by 4 Aug 2015, 21:54

                          @abakobo said:

                          P.S. I noticed a little bug: I have to initialise myself the .visible of each visible unmodified SKUI items before saving them because it was returning nil with the .visible? method if .visible= was never used.

                          Hmm... Could you file this bug in the GitHub repo with a small code snippet?

                          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
                            abakobo
                            last edited by 5 Aug 2015, 07:57

                            I never did that but will learn how to.
                            Glad to participate... πŸ˜„

                            1 Reply Last reply Reply Quote 0
                            • A Offline
                              abakobo
                              last edited by 5 Aug 2015, 10:08

                              Bug posted in the GitHub Issues field!

                              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