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

Storing last values used in the registry?

Scheduled Pinned Locked Moved Developers' Forum
13 Posts 4 Posters 1.2k 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.
  • D Offline
    Dan Rathbun
    last edited by 6 Mar 2012, 20:38

    You are confusing terms again.

    They are input dialog boxes, NOT menus.

    NO. Each one of your plugins should only use ONE registry key.

    • Please begin all your keys with "Plugin_"

    Reason.. this sets them apart from all other Sketchup subkeys, but still grouped together. And it follows the convention used by the WebDialog keys, which are always (automatically,) prefixed with "WebDialog_"

    • Whitespace (and '::') in keynames should be replaced with "_".
      like:
      REGKEY = 'Plugin_'<<Module.nesting[0].name.split('::').join('_')
      notice I use a constant (all caps,) because it will never change.
      It would produce for your example:
      'Plugin_TNT_Bookshelf'

    BUT ...
    Each "set" of values OR special setting has it's own ATTRIBUTE name (under the common plugin KEY.)
    "RightHandDoorParams"
    "LeftHandDoorParams"

    I'm not here much anymore.

    1 Reply Last reply Reply Quote 0
    • D Offline
      Dan Rathbun
      last edited by 6 Mar 2012, 20:59

      Next issue.

      I gave you a couple of basic saving and loading option methods, in this thread's code sample:
      http://forums.sketchucation.com/viewtopic.php?f=180&t=43673&p=390107#p389920

      What do you want to do differently ??

      We can tweak the process.

      For example.. if you still wanted to use unique @@ names, like @@lhd_width, @@lhd_height, @@lhd_style, etc., instead of @@opts[:lhd_width], etc. everywhere in your code ...
      ... you CAN do that and still use the @@opts hash of saving and restoring.

      The trick is to collect ALL module variables (also called class variables,) into a array of var name strings, using the standard method class_variables()
      then iterate that array thus:

      vars = class_variables()
      vars.each do |var|
        eval("@@opts[#{var.gsub('@@',';')}]= #{var}")
      end
      # Now we can save the opts hash; 
      set_saved_opts()
      

      The reverse, after calling get_saved_opts(), to distribute the saved settings back to your module variables:

      get_saved_opts()
      @@opts.each do |attr,val|
        eval("@@#{attr.to_s} = @@opts[#{attr}]")
      end
      

      I'm not here much anymore.

      1 Reply Last reply Reply Quote 0
      • T Offline
        tomot
        last edited by 6 Mar 2012, 22:18

        @dan rathbun said:

        You are confusing terms again.
        They are input dialog boxes, NOT menus.

        yes, menus my bad!... been a long day so far, could not sleep, I started coding at 3:30 am this morning, with good intentions trying your outline, finally had to sideline that effort, it in favor of a simpler older script of mine in need of a module. Regardless this small demonstration script, is a starting point, for going forward. 😄 using module & registry works!..........comments welcome!


        tnt_bookshelf.rb

        [my plugins](http://thingsvirtual.blogspot.ca/)
        tomot

        1 Reply Last reply Reply Quote 0
        • D Offline
          Dan Rathbun
          last edited by 6 Mar 2012, 23:01

          OK looking at it... and making a few quick changes.

          ADD: Here's version '1.1.1'
          Fixed line 65: forgot to paste in the new attribute name "BookshelfDimensions" .. sorry.


          TNT_1_1_1.zip


          I fixed it so there is only ONE key for the plugin, and each dialog has a separate attribute beneath that key.

          viz:
          Plugin_TNT_Bookshelf_REGKEY.png
          Also:

          • Put the plugin inside a plugin submodule: TNT::BookShelf.
          • Plugin now resides with the path "tnt/bookshelf/"
          • Added a VERSION constant.
          • Wrapped the undo operation in a begin ... rescue ... end block.
          • Moved the "BookShelf Details" dialog before the undo operation.
          • Moved the last line: file_loaded(*filepath*) inside the file_loaded? conditional block. (Just to be sure it only gets pushed into $loaded_files once. Although file_loaded() may test for this, there's no sense calling it if not needed to.)
          • Made note (in file header,) that on XP the REGKEY path differs from Win6+.

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • D Offline
            Dan Rathbun
            last edited by 6 Mar 2012, 23:43

            Bumped: version '1.1.1'
            Fixed line 65: forgot to paste in the new attribute name "BookshelfDimensions" .. sorry.

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • T Offline
              tomot
              last edited by 6 Mar 2012, 23:59

              Dan thanks for your patience! I'm going to digest your changes...tomorrow.
              After 12 hrs of sitting,... my ass is developing flat spots 😄
              In the next stage I will be tackling how the incorporating of therectangle.rb code
              which is used in my doortool ruby works with the module & registry stuff I have learned to implement today.
              ttyl!

              [my plugins](http://thingsvirtual.blogspot.ca/)
              tomot

              1 Reply Last reply Reply Quote 0
              • T Offline
                tomot
                last edited by 7 Mar 2012, 15:20

                Looks great Dan! Now unless I'm missing something, (which happens quite often), does the storing of last used dialog values in the registry not make for a more elegant solution then using the @@ approach?

                [my plugins](http://thingsvirtual.blogspot.ca/)
                tomot

                1 Reply Last reply Reply Quote 0
                • D Offline
                  Dan Rathbun
                  last edited by 7 Mar 2012, 16:28

                  Firstly... the difference between @ vars and @@ vars in modules are subtle. (Save that issue for later.)

                  Elegant? Well your really doing the same thing ... but dialog by dialog, instead of the plugin's whole set of saved values.

                  Also you're doing it in a sort of brute force manner. You are accessing the stored values in the registry (whether you need to not,) and always saving them (without really testing if they are good values. Relying on the user to input values they wish to save.)
                  Also you are creating the literal strings for the inputboxes each time the 'main' method is called.
                  But that's OK for now... you can understand what's happening.

                  Later on you (when you're ready to get fancier,) you might move the defaults, prompts etc out of the method into module vars. But it's not that important for a really simple single command plugin module. As your plugins get more complex and bigger, you will want to centralize common functions like loading and saving defaults into one method ... rather than have them scattered throughout your code. (Easier maintenance!)

                  Ruby is multi-paradigm... "there is more that one way to skin a cat."


                  The BIG lessons you have learned, is module wrapping, using variables that have namespace scope, and saving default values.
                  Also take note of the operation block.


                  I have noticed problems with the API's read_default() on PC when it tries to read REG_SZ strings values. We need to store quotes with the value in the registry. Using the inspect() method is a good idea, because it will escape embedded ' or " if used for unit symbols.
                  If I try to read the "SnapLength" attribute in the "Preferences" key, I get nil, because it's set to 1" instead of '1"' or "1\""
                  Also it cannot see any keys with spaces in their names, and just returns nil.

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • T Offline
                    tomot
                    last edited by 7 Mar 2012, 16:53

                    Nice explanation! if I continue for now to go down the registry path
                    How does or can values accept strings ? such as door open, or door closed?


                    values.jpg

                    [my plugins](http://thingsvirtual.blogspot.ca/)
                    tomot

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Dan Rathbun
                      last edited by 7 Mar 2012, 20:11

                      @tomot said:

                      Nice explanation! if I continue for now to go down the registry path
                      How does or can values accept strings ? such as door open, or door closed?

                      OK just tested a bit ... the write_default and read_default have no problems if you feed a string (or most simple class types,) to them. The write stores it so it can be read OK.

                      The problem arrises when there is more than one double quote char ( ") in sequence, AND they are not escaped.
                      Because write_default always surrounds a string argument, perhaps by calling inspect() internally to the method.

                      so this was wrong, on my part:

                          #  set_saved_opts()
                          #
                          def set_saved_opts()
                            @@opts.each_pair {|attr,val|
                              if val.is_a?(String)
                                Sketchup.write_default( REGKEY, attr.to_s, val.inspect )
                              else
                                Sketchup.write_default( REGKEY, attr.to_s, val )
                              end
                            }
                          end#def set_saved_opts()
                      
                      

                      I knew we needed to handle strings specially, but I went the opposite way. (The inspect method adds quotes.)

                      We really do not want to ADD any more quotes chars...

                      ... we want to either strip them off of strings, or be sure they are escaped.

                      Let's go with option 2, and use the gsub method, to escape all internal double quotes, like:
                      gsub(34.chr,92.chr<<34.chr)

                          #  set_saved_opts()
                          #
                          def set_saved_opts()
                            @@opts.each_pair {|attr,val|
                              if val.is_a?(String)
                                Sketchup.write_default( REGKEY, attr.to_s, val.gsub(34.chr,92.chr<<34.chr) )
                              else
                                Sketchup.write_default( REGKEY, attr.to_s, val )
                              end
                            }
                          end#def set_saved_opts()
                      
                      

                      In your case if you had a results array that had an embedded string:
                      [1, 2, "door closed", 2.54]
                      and you use inspect() on it, you get this:
                      "[1, 2, "door closed", 2.54]"
                      and read_default cannot eval it, so it returns nil
                      Also, you cannot double inspect it, because that will result in the whole registry value delimited by 2 double quotes:
                      [1, 2, "door closed", 2.54].inspect.inspect
                      puts this: %(#008000)[""[1, 2, \"door closed\", 2.54]""] into the registry, and read_default will poop out again, (returning nil.)

                      So... you need to use:
                      results.inspect.gsub(34.chr,92.chr<<34.chr)

                      You can try it at the console:
                      Sketchup.write_default("Plugin_TNT_Bookshelf", "Array", [1,2,"door closed",2.54].inspect.gsub(34.chr,92.chr<<34.chr))
                      and then to test retrieving it:
                      [ruby:3jpmcjqh]arr = Sketchup.read_default("Plugin_TNT_Bookshelf", "Array")[/ruby:3jpmcjqh]
                      which if all goes well, should return:
                      [ruby:3jpmcjqh]'[1,2,"door closed",2.54]'[/ruby:3jpmcjqh] which can be eval'd back into an array.

                      OK?

                      However... write_default and read_default can ALSO write and read arrays directly if you DON'T inspect them.
                      This is because the 'write' converts them to a string, before storing them in the registry,... and then the 'read' evals those strings back into an [ruby:3jpmcjqh]Array[/ruby:3jpmcjqh].

                      But.. to confuse the issue... they do not handle hashes well. We have to resort to the [ruby:3jpmcjqh].inspect.gsub(34.chr,92.chr<<34.chr)[/ruby:3jpmcjqh] treatment for any hash arguments to write_default, and eval the return strings from read_default.


                      Now.. (if your dizzy trying to absorb this,) perhaps, you'll understand why I like to write one method to get all this proper handling correct, and then reuse that method in multiple plugins. (Say via a mixin module.) Trying to remember all the quirky issues, when it comes time to write and read values, is a pain in the butt.


                      You don't run into this 'nested string' in hashes and arrays problem, if all your variables are saved into individual attributes in the registry.
                      (... And they are all single value types, ie, not arrays, hashes, structs, etc.)

                      def save_my_vars()
                        vars = instance_variables + class_variables
                        vars.each{|var| eval("Sketchup.write_default(#{REGKEY}, '#{var}', #{var}")
                      end
                      
                      def load_my_vars()
                        vars = instance_variables + class_variables
                        vars.each{|var| eval("#{var} = Sketchup.read_default(#{REGKEY}, '#{var}'")
                      end
                      
                      

                      But.. that will save ALL of your variables... even iterators, and ones you do not really need to save.

                      This is why I collect only the ones I wish to save, into an [ruby:3jpmcjqh]@@opts[/ruby:3jpmcjqh] hash, and then write only those values to the registry.

                      Example.. at the top of your Bookshelf module, where you define your instance [ruby:3jpmcjqh]@[/ruby:3jpmcjqh] variables... you could just as easily define them AND an [ruby:3jpmcjqh]@@opts[/ruby:3jpmcjqh] hash, all in one go:

                      # default bookshelf values used for script development
                      unless defined?(@@opts)
                        @@opts = {
                          ;height => @height = 2.feet, 
                          ;width  => @width = 2.feet,
                          ;depth  => @depth = 1.inch, 
                          ;ny     => @ny = 5,
                          ;nz     => @nz = 5,
                          ;dist   => @dist = 1.inch
                        }
                      end
                      
                      

                      Anyway... as long as the simple way works.. use it. When things get more complex... and you need to centralize your default value handling... you've got a topic thread here to mine for ideas.

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • K Offline
                        ktkoh
                        last edited by 8 Mar 2012, 13:01

                        I have been following this topic as I have in the past used a file to store variables between sessions and my question is does the registry storing of variables only work on Win based computers and not on the Apple OS?

                        Keith

                        1 Reply Last reply Reply Quote 0
                        • TIGT Offline
                          TIG Moderator
                          last edited by 8 Mar 2012, 13:40

                          The Sketchup.read_defaults and Sketchup.write_defaults use each PC's Sketchup 'Registry' entries OR a MAC's Sketchup 'plist' file entries... so they should work cross-platform.
                          The main issue with using the Registry is storing data restructured into a format that can be recovered and then converted back into the required 'class' later - e.g. a string/float/integer/length/boolean/array/hash etc will need some 'manipulation' before writing - but if you have been using a 'file' to store such things then you've been writing them as strings already - when you reread the file you presumably convert the strings back with say string.to_f to make the value a number etc... [like an 'ini' file].
                          The Registry data exists across sessions globally for Sketchup on each PC, not just the current SKP.
                          So if you want SKP specific data saving then it's best to use model-attributes to save things with the SKP [you can save attributes as most common data types directly - except a hash] - the data is thereby accessible to all uses on the network when you script reads the attributes as it runs, and later updates the attributes as it closes, this can all be done independent of each PC's Registry entries.

                          Horses for courses...

                          TIG

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

                          Advertisement