• Login
sketchucation logo sketchucation
  • Login
πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

Ruby "good practice" using constants?

Scheduled Pinned Locked Moved Developers' Forum
23 Posts 3 Posters 2.9k 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.
  • T Offline
    thomthom
    last edited by 26 Sept 2012, 20:47

    @dan rathbun said:

    Sub-modules do not inherit the local constants of outer modules.

    My snippet works. Try it.
    ModuleRef.png

    @dan rathbun said:

    This is what include and extend are for. Shared library modules are best written as "mixin" modules.

    Does that duplicate the methods? Or do they all refer to the source module?

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

    1 Reply Last reply Reply Quote 0
    • T Offline
      thomthom
      last edited by 26 Sept 2012, 20:51

      This on the other hand doesn't work:
      ModuleRef2.png

      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 26 Sept 2012, 20:56

        I did the first all in one line, at the console, and it did not work:

        ` module Dan; OUTER = self; module Plugin; PLUGIN = self; class Special; CLASS = self; end; end; end

        $ Dan::Plugin::Special::OUTER
        %(#008000)[Error: #<NameError: (eval): uninitialized constant Dan::Plugin::Special::OUTER>
        (eval)]`

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • D Offline
          Dan Rathbun
          last edited by 26 Sept 2012, 21:00

          @thomthom said:

          @dan rathbun said:

          This is what include and extend are for. Shared library modules are best written as "mixin" modules.

          Does that duplicate the methods?

          NO.

          @thomthom said:

          Or do they all refer to the source module?

          YES... it's like a proxy lookup.

          So if you define two sub-modules that include a library mixin module of constants, and sub-module two changes a value of a constant, it changes IN the mixin module, and any other sub-module that has included the mixin module, will see the changes.

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • D Offline
            Dan Rathbun
            last edited by 26 Sept 2012, 21:16

            @thomthom said:

            My snippet works. Try it.

            Reason, because it's a Ruby interpreter block scope issue (Easter egg like thing.)

            The interpreter reads the humanized script, and translates this:

            module TT;;Plugins;;Example
            
              PLUGIN = self
            
              module FooBar
                def self.magic_button
                   puts PLUGIN.name
                end
              end
            
            end
            

            .. to (something similar on the C-side):

            TT;;Plugins;;Example = Module.new {
            
              PLUGIN = self
            
              FooBar = Module.new {
                def self.magic_button
                   puts PLUGIN.name
                end
              }
            
            }
            

            So the Foobar definition block has access to the object references in the wrapping scope.

            IMHO: Although it works.. explaining why is complicated and will likely confuse newbies, and it not really following good organizational form, (which is what we want to teach newbies.)

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • T Offline
              thomthom
              last edited by 26 Sept 2012, 21:41

              @dan rathbun said:

              So if you define two sub-modules that include a library mixin module of constants, and sub-module two changes a value of a constant, it changes IN the mixin module, and any other sub-module that has included the mixin module, will see the changes.

              That's interesting. So one can then add all common methods and constants to the mixin... and no extra overhead.

              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 26 Sept 2012, 23:23

                @thomthom said:

                That's interesting. So one can then add all common methods and constants to the mixin... and no extra overhead.

                Yea! That is the whole point ... and it also works with the module vars in the mixin module.

                However sometimes evaluation may actually occur with in the Mixin module, rather than the "mixee" module. SO .. test.

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • T Offline
                  thomthom
                  last edited by 27 Sept 2012, 07:13

                  @dan rathbun said:

                  However sometimes evaluation may actually occur with in the Mixin module, rather than the "mixee" module. SO .. test.

                  What evaluation?

                  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 27 Sept 2012, 07:26

                    of methods... so example you'd have to pass in references from the mixee modules. (Don't expect the mixin method to have access to objects in the mixee module. ... From what I remember.)

                    However (as always,) mixing into classes is different. If the mixin instance method has a ref to a @var, the object used is the one in the mixee class. Which is what you would expect.

                    It's just that including modules into are a bit more "funky" then mixing modules into a class.

                    I'm not here much anymore.

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Dan Rathbun
                      last edited by 27 Sept 2012, 07:27

                      But we are getting off-topic here ... let's get back on constants.

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • T Offline
                        thomthom
                        last edited by 27 Sept 2012, 07:50

                        @dan rathbun said:

                        of methods... so example you'd have to pass in references from the mixee modules. (Don't expect the mixin method to have access to objects in the mixee module. ... From what I remember.)

                        I'm not quite following you here.. πŸ˜•
                        Got a sample code to illustrate?

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

                        1 Reply Last reply Reply Quote 0
                        • brewskyB Offline
                          brewsky
                          last edited by 27 Sept 2012, 08:25

                          Thanks guys!

                          I have to do some reading to be able to follow the discussion πŸ˜‰
                          I kinda lost it somewhere along the way...

                          TT's first post came close to what I want to do.
                          This is more what I mean:

                          module TT;;Plugins
                          
                            PLUGIN = QuadFaceTools.new
                          
                          end
                          

                          @dan rathbun said:

                          Can you give us a code shell showing the namespace nesting, and how you wish to share the reference to your classes ??

                          This is an example of what I'm doing now.
                          I make some sort of "root-plugin" object(class-instance, not a module) that holds all other plugin objects/data.
                          And pass this on to all nested objects to be able to access the embedded data.

                          module Brewsky;;BimTools
                          
                            class BimTools
                              attr_accessor ;project_list, ;web_dialog
                              def initialize
                                btProject = BtProject.new(self)
                              end
                            end
                            
                            class BtProject
                              attr_reader ;model, ;guid, ;name, ;description
                              def initialize(bt)
                                @bt = bt
                              end
                              def update_dialog(value)
                                dialog = @bt.web_dialog
                                
                                # do something with "dialog" using "value"
                                
                              end
                            end
                            
                            BimTools.new
                          
                          end
                          

                          Sketchup BIM-Tools - http://sketchucation.com/forums/viewtopic.php?p=299107

                          1 Reply Last reply Reply Quote 0
                          • D Offline
                            Dan Rathbun
                            last edited by 28 Sept 2012, 02:51

                            Sometimes I pass in the outer namespace via the constructor (as you show in your example,) but usually it is into Observer instances. I normally give the "handle" the name @parent, @outer or similar.

                            Access to data objects in the parent namespace, (if they are few,) can be done with more clarity, by also passing them in via the constructor call.
                            See my simple plugin example: [Code] AnimateSelection Example
                            In this example, the references are passed in as individual arguments.
                            But if there are many, it may make more sense to collect the objects into a Hash or a Struct, and pass that in.

                            πŸ’­

                            I'm not here much anymore.

                            1 Reply Last reply Reply Quote 0
                            • brewskyB Offline
                              brewsky
                              last edited by 28 Sept 2012, 19:09

                              I guess the way I'm passing the object into every sub-object is "structurally" the best way to go.
                              But in this way I'm constantly making new pointers to always the same old base-object.
                              And because there is only one instance, would it not be clearer to use some sort of "almost-global" object, such as a module-constant, and have access to it anywhere in the program?

                              Like TT does?
                              And after thinking on this, maybe TT's way of just making a module as a base-object for the plugin is a better approach than my BimTools-class. Because is't only used once, the module-approach seems more fitting...

                              Something like:

                              module Brewsky
                              
                                class BimTools
                                  attr_accessor ;project_list, ;web_dialog
                                  def initialize
                                    btProject = BtProject.new
                                  end
                                end
                                
                                class BtProject
                                  attr_reader ;model, ;guid, ;name, ;description
                                  def update_dialog(value)
                                    dialog = PLUGIN.web_dialog
                                    
                                    # do something with "dialog" using "value"
                                    
                                  end
                                end
                                
                                PLUGIN = BimTools.new
                              
                              end
                              

                              Sketchup BIM-Tools - http://sketchucation.com/forums/viewtopic.php?p=299107

                              1 Reply Last reply Reply Quote 0
                              • D Offline
                                Dan Rathbun
                                last edited by 8 Oct 2012, 14:11

                                Here is a SketchUp specific example of using a Constant Library mixin module so an author's various plugin modules (and/or submodules,) can share the references to the author's menu and submenu objects.

                                See: One Submenu for many plugins

                                πŸ’­

                                I'm not here much anymore.

                                1 Reply Last reply Reply Quote 0
                                • brewskyB Offline
                                  brewsky
                                  last edited by 12 Nov 2012, 20:53

                                  @dan rathbun said:

                                  So for example, your nested module Brewsky::BimTools::Manager is actually an instance object, and the preceeding identifier is the reference to the instance.

                                  If you remember this... then it can be easier to understand how using an anonymous singleton proxy class instance inside your Module class instance, makes sense.

                                  Thank you very much for this very helpful post!
                                  I completely missed it untill now 😳

                                  My plugin is in need of "some" improvement... πŸ˜‰

                                  Sketchup BIM-Tools - http://sketchucation.com/forums/viewtopic.php?p=299107

                                  1 Reply Last reply Reply Quote 0
                                  • D Offline
                                    Dan Rathbun
                                    last edited by 16 Dec 2012, 21:45

                                    @brewsky said:

                                    And after thinking on this, maybe TT's way of just making a module as a base-object for the plugin is a better approach than my BimTools-class. Because is't only used once, the module-approach seems more fitting...

                                    Oh hell yes.

                                    If you need only one copy of a code object, then generally it should be a module.

                                    If you need multiple copies of a code object (usually because the code must adapt to many other instance objects,) then you make it a class, and instantiate instances that are syncronized to a particular instance object.

                                    Often coders try to avoid using a module, because they think it's a static kind of object, and they believe it is harder to use than a class instance.
                                    What they miss is, that a module definition, is really an instance of class Module. So for example, your nested module Brewsky::BimTools::Manager is actually an instance object, and the preceeding identifier is the reference to the instance.

                                    If you remember this... then it can be easier to understand how using an anonymous singleton proxy class instance inside your Module class instance, makes sense.

                                    Imagine the Module class is "the hen".

                                    It lays an egg, which is your nested Manager module instance, that could be created thus:
                                    ` Brewsky::BimTools::Manager = Module.new {

                                    plugin managerial code here

                                    }But the Ruby interpreter calls the new()` constructor for you on the C-side of things. (Ie, the defintion block syntax for scripts, was invented for human happiness and readability; Ruby itself does not really need it.)

                                    But having methods in modules communicate (call each other,) works a bit different than in a class definition. Instance method definitions in a module, are meant for Library Mixin modules. (Read up on the include and extend methods.) They become different kinds of methods, depending on whether they are mixed into a class or module, and whether include and extend is used to do the mixing.)

                                    So at first blush, the coder thinks they must define all methods in a module as module functions that must be called with self.method_name(), ... they find this cumbersome, and they switch back to using a class defintion, and using only one instance of it. (A sort of psuedo-singleton class.)

                                    BUT.. the egg can have a membrane inside it's shell. This membrane analogy is the anonymous singleton proxy class instance created with the following syntax:

                                    module Brewsky
                                      module BimTools
                                      end
                                    end
                                    
                                    module Brewsky;;BimTools;;Manager
                                    
                                      # module variables and constants declared here
                                      MGR_VERSION ||= '1.2.3'
                                      
                                      @@bimmenu ||= nil
                                    
                                      class << self # self evaluates to the module instance
                                    
                                        # Everything in here acts like a class
                                        #  instance BECAUSE IT ACTUALLY IS !
                                    
                                        # In here we can access the module @@vars directly.
                                    
                                        # In here we define instance methods, not module methods.
                                        # But if they are public, they can be called like module
                                        # functions, from anywhere outside the module.
                                        
                                        private
                                        
                                        def get_version()
                                          MGR_VERSION
                                        end
                                    
                                        # In here we can call any other method in here,
                                        #  without module qualification.
                                    
                                        public
                                        
                                        def version()
                                          get_version()
                                        end
                                    
                                      end # proxy class
                                    
                                      # Out here we can call any of the methods inside
                                      #  the proxy class directly, without qualification.
                                      unless @@bimmenu
                                        @@bimmenu = UI.menu('Plugins').add_submenu('BIMTools')
                                        @@bimmenu.add_item('Version') { UI.messagebox("BIMTools ver #{version()}") }
                                      end
                                    
                                    end # module Brewsky;;BimTools;;Manager
                                    
                                    # 99.9% of the time, there is no good reason to
                                    # have any executing code outside your namespace.
                                    
                                    

                                    πŸ’­

                                    EDIT(2012-12-16): changed post title to "Why use a module instead of a class ?"

                                    I'm not here much anymore.

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

                                    Advertisement