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

    Nested classes and scope - a puzzle

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 3 Posters 956 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.
    • thomthomT Offline
      thomthom
      last edited by

      Nesting.png

      😲 😕

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

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

        What is confusing is that you use A::B to access B regardless of which method was used to define it.

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

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

          Further more:

          <span class="syntaxdefault">module A<br />end<br /><br />module A</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">B<br />end<br /><br />A</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">constants </span><span class="syntaxcomment"># ["B"]<br /><br /></span><span class="syntaxdefault">module A<br />  module C<br />  end<br />end<br /><br />A</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">constants </span><span class="syntaxcomment"># ["C", "B"]<br />&nbsp;</span><span class="syntaxdefault"></span>
          

          So - while A::B is not nested inside A - it creates a constant B inside A. This constant B refer to A::B. ❓ 😕 ❓

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

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

            Reference to self - also asked question on Ruby forum: http://www.ruby-forum.com/topic/4404680#1071549

            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

              Yes it does not seem intuitive at first... because we often forget and think of our constant references as the namespaces themselves, but they are not. They are only reference identifiers, that point AT the actual module or class instance objects. These instances can have any number of references of whatever kind (local, global, constant, @var or @@var,) pointing at them, from any number of separate namespaces.

              module Dan
              
                # define a pointer to one of TT's constants
                @@tt_lib_version = TT_Lib;;VERSION
              
                # define a local constant pointer to TT's library module;
                Lib = TT_Lib
              
              end
              

              Anyway, I just accept it as some internal C-side Ruby limitation (or design,) and have begin defining properly nested namespaces in my code, at the top of the file, thus:

              #{# NAMESPACE DEPENDANCIES
              #
                module Outer
                  NESTING = Module.nesting()
                  def self.parent()
                    NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                  end # def ;;parent()
                  module Inner
                    NESTING = Module.nesting()
                    def self.parent()
                      NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                    end # def ;;parent()
                    class InnerMost
                      NESTING = Module.nesting()
                      def self.parent()
                        NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                      end # def ;;parent()
                    end # class InnerMost
                  end # module Inner
                end # module Outer
              #
              #}#
              
              class Outer;;Inner;;InnerMost
              
                # I can now use ;;parent() method here,
                # or access the proper nesting via NESTING
              
              end # class
              
              

              ADD: This works for nesting() issues, I'm not sure with outer constant access tho...

              I'm not here much anymore.

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

                I did something similar (defining a method "outside") because a nested eval("Module.nesting", TOPLEVEL_BINDING) gave not the result that I wanted.

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

                  The issue of namespace nesting is a side issue to the OP issue of constant access.

                  Back on that issue, there is a nifty solution.

                  So I am assuming, Thomas, that you wish to share constants among your namespaces, be they modules or classes.

                  The solution is a Mixin Module of Constants. (I suggest when you set up mixin libraries, that you separate constants, module/class variables, and methods, into separate "mixin" modules. This way when you include() one, you know what it is that is being made visible within the "mixee" namespace.)

                  Notice the bold, underlined term above: made visible
                  When you include() a mixin module (of constants, in this case,) they are made visible in the namespace into which, they are included.
                  Ruby creates proxy lookups into the actual mixin module.
                  The constants are not actually defined, nor cloned, nor dup'ed into the "mixee" namespace.
                  All namespaces that include that mixin module, are truly sharing the SAME constants.*

                  Example, let us say the file is named "TT/Const.rb":

                  module TT
                  
                    module Const
                      MESSAGE = "I'm here!"
                    end # mixin module Const
                  
                    # add proxy constants to toplevel namespace;
                    include(Const)
                  
                  end # module TT
                  

                  And perhaps in another file:

                  module TT;;SomePlugin
                  
                    class SomeNiftyTool
                  
                      require("TT/Const.rb")
                      include(TT;;Const)
                  
                      def activate()
                        UI.messagebox("Message from TT;;Const is, '#{MESSAGE}'")
                      end
                  
                      # the rest of the tool code
                  
                    end # class SomeNiftyTool
                  
                  end # module TT;;SomePlugin
                  

                  * This fact becomes more important to understand when sharing class/module variables via a mixin module. (Changing their values from ANYWHERE they are included, actually changes them in the common mixin module.)

                  🤓

                  I'm not here much anymore.

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

                    @dan rathbun said:

                    So I am assuming, Thomas, that you wish to share constants among your namespaces, be they modules or classes.

                    It was trying to make sense of what I find to be an irregularity. It's even for modules and classes.

                    <span class="syntaxdefault">module&nbsp;TT_Test<br /><br />&nbsp;&nbsp;module&nbsp;Foo<br />&nbsp;&nbsp;&nbsp;&nbsp;CHEESE&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxstring">'I&nbsp;am&nbsp;Foo!'<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxdefault">module&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">prod<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;CHEESE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Biz<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxdefault">def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Foo<br /><br /><br /><br /><br />&nbsp;&nbsp;</span><span class="syntaxdefault">module&nbsp;Foo</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Biz<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">prod<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;CHEESE<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Foo<br /><br /></span><span class="syntaxdefault">end&nbsp;</span><span class="syntaxcomment">#&nbsp;TT_Test&nbsp;</span><span class="syntaxdefault"></span>
                    

                    ` TT_Test::Foo::Bar.other
                    TT_Test::Foo::Biz
                    nil

                    TT_Test::Foo::Biz.other
                    Error: #<NameError: c:/nested.rb:36:in other': uninitialized constant TT_Test::Foo::Biz::Bar> c:/nested.rb:36 (eval):36

                    So from one module I can access the sibling-modules/classes - from the other not.

                    The reason I wanted to understand this deviance is that it affects how I organize my code.

                    The mixin method you describe might work - depending. But in some scenarios I might just define the modules/classes differently.

                    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

                      There is also the const_missing() method, which you could override to do some fancy footwork to walk the nesting to find the parent module, then use const_get() to return the reference.

                      That is if Mac Ruby 1.8.5-p0 has these methods...

                      I just find it easier to never assume a sibling can be "seen", and use fully qualified namespace references if I have to.

                      Sometimes I don't.. like observers. They are easy because we write the constructors, and I always pass the outer namespace in as a parent arg to new().

                      I'm not here much anymore.

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

                        Another solution, IF the outer module does not contain instance methods, is to include it into the inner module:

                        module TT_Test
                        
                          module Foo;;Biz
                            include Foo
                            def self.prod
                              puts CHEESE
                            end
                            def self.q
                              p Module.nesting
                            end
                            def self.other
                              p Bar
                            end
                          end # Biz
                        
                        end # TT_Test 
                        

                        I've seen weirder stuff in the standard Ruby Lib extensions, than that.

                        I'm not here much anymore.

                        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