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

    Module class method defining confusion

    Scheduled Pinned Locked Moved Developers' Forum
    10 Posts 3 Posters 582 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.
    • Chris FullmerC Offline
      Chris Fullmer
      last edited by

      OK, I'm confused here. What is the right way to define modules and classes? Here is what I have:

      module MyModule
      
        def MyModule;;mod_method1
        end
      
        def MyModule;;mod_method2
        end
      
        class MyModule;;MyClass
          def class_method1
          end
      
          def class_method2
          end
      
        end #MyClass
      end #MyModule
      

      Is that correct? classes inside a module need to have the module:: in front of it to make sure it gets defined actually as part of the module? That seems to be what I'm seeing. Then methods defined loosely in the module need the same module:: in front of them to force them to be defined as inside the module. But methods inside a class do not need module::class:: or anything in front of them, they get defined inside the class automatically? That seems to be what I'm seeing, but the logic there is a bit fuzzy for my brain. Also, I have a few classes inside the module. Is there a way to share variables between those classes? I've got a @@data variable for example the gets defined in my MyModule::Import class, but I'd like to access it from my MyModule::Processing. Is there a way to access it across classes? Or probably a better way to store the data so I can access it across classes? Thanks for anyone's time who patient enough to read through all that! πŸ˜„

      Chris

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

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

        Your example is incorrect, in several ways.

        First, defining nested modules and nested classes.
        There are two ways:

        module MyModule
        
          # constant, var and methods
        
          module NestedModule
            # constant, var and methods
          end # NestedModule
        
          class NestedClass
            # constant, var and methods
          end # NestedClass
        
        end # MyModule
        

        .. or ..

        module MyModule
          # constant, var and methods
        end
        
        # the following can be in THIS file,
        # or in separate file(s).
        # If in separate file(s) a require statement is
        # needed to be sure the first file is loaded.
        
        module MyModule;;NestedModule
          # constant, var and methods
        end
        
        module MyModule;;OtherNestedModule
          # constant, var and methods
        end
        
        class MyModule;;NestedClass
          # constant, var and methods
        end
        
        class MyModule;;OtherNestedClass
          # constant, var and methods
        end
        
        
        

        I'm not here much anymore.

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

          METHODS

          @chris fullmer said:

          But methods inside a class do not need module::class:: or anything in front of them, they get defined inside the class automatically?

          NO

          To define a class method, the defintion is preceeded with the namespace qualification. You can retype the actual name, ie:
          def MyClass.method_name_1
          ... but it is better practice to use the keyword self, as in:
          def self.method_name_1
          ... that way you can easily change the class name at the top of the file, without having to edit every method definition.

          Within a class definition, AND within all class methods, the keyword self refers to the class itself, (except within any instance method.)

          Class methods must be called using namespace qualification. Every class' constructor method (usually named new,) is a public class method, and must be called qualified with the class name, and if called from outside that class' defining namespace, it must be additional qualified with the module name that wraps it, such as:
          Geom::Point3d.new(args)

          • If called from within the Geom module, then it can be called simply as Point3d.new() because Point3d is a local constant in that scope. (Remember that module and class identifiers are themselves constants.)

          Instance methods are NOT defined with any qualification:
          def instance_method_name

          Within any instance method (especially initialize,) the keyword self refers to the instance object that will be created at runtime by the constructor method.

          @chris fullmer said:

          Then methods defined loosely in the module need the same module:: in front of them to force them to be defined as inside the module.

          NO

          To define a module method, the defintion is preceeded with the namespace qualification. You can retype the actual name, ie:
          def MyModule.method_name_1
          ... but it is better practice to use the keyword self, as in:
          def self.method_name_1
          ... that way you can easily change the module name at the top of the file, without having to edit every method definition.

          Within a module definition, and all module methods, the keyword self refers to the module itself, (except within any instance method.)

          Module methods must be called using namespace qualification. These are usual what you would consider to be library methods, for use by other modules and classes. (All the methods in the Sketchup module are like this. You must call them qualified with the name of the module.)

          Because modules can be written as special "Mixin-Modules", you can also define instance methods within modules, so that when the "mixin" is added to a class using include(), those instance methods become available within the "mixee" class.
          Just as in classes, the keyword self within an instance method in a mixin module, will (eventually,) refer to the instance object, created at runtime, by the constructor method, of the class that the mixin module in "mixed into" using include().

          An example is the standard Ruby module Math, as it is a combo Library module, and Mixin module. (There are 2 copies of each of it's methods, an instance copy, and a module copy.)
          You can call it's module methods as library methods:
          Math.cos(arg)
          ... or you can mix it into your class(es) using include(Math) and all it's instance method copies are added to your class as private instance methods, and all it's constants are added to your class as local constants.

          I'm not here much anymore.

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

            TBD (making things easier with modules using an anonymous class block.)

            FYI: I explained this previously in my topic [info] Using Ruby Modules

            I'm not here much anymore.

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


              Accessing shared data / vars between nested modules and/or nested classes.


              If the data will not change, you can use a constant (just DON'T use the name DATA as it's a Ruby keyword.)

              module MyModule
              
                VALUE = 1.234
              
                class MyClass
                  attr_accessor(;value)
              
                  def initialize
                    @value = MyModule;;VALUE
                  end
                end # MyClass
              
                begin
                  @@my_instance = MyClass.new()
                end
              end # MyModule
              

              If the data will change use a module variable. Ruby 1.8.x does not contain a methods that autobuild class/module var getter and setter methods like it does for attributes (aka instance variables.)

              But you CAN define them manually:

              module MyModule
              
                @@value = 1.234
              
                def self.value
                  @@value
                end
              
                def self.value=(arg)
                  @@value = arg
                end
              
                class MyClass
                  attr_accessor(;value)
                  def initialize
                    @value = MyModule.value
                  end
                end # MyClass
              
                begin
                  @@my_instance = MyClass.new()
                end
              end # MyModule
              

              A quirk is that, in the instance of MyClass, the object refereneced initially by @value will be the same object referenced by @@value in MyModule. But if the reference @@value is reassigned to point at a different object (via the setter method MyModule.value(object) or MyModule.class_variable_set(:@@value,object),) then the two references will afterward be pointing at different objects.

              You would need to be sure the references are "in sync" if you do not wish this behaviour, usually by always calling the module's getter method for the @@var.

              One way around this, is to wrap any shared data within an object reference that will not change, such as a Hash or Array object, that still allows it's submembers to change freely.

              module MyModule
              
                @@data = {'value' => 1.234 }
              
                def self.value
                  @@data['value']
                end
              
                def self.value=(arg)
                  @@data['value']= arg
                end
              
                class MyClass
                  attr_accessor(;value)
                  def initialize
                    @value = MyModule.value
                  end
                  # override the standard getter
                  # to be sure it's in sync;
                  def value
                    @value = MyModule.value
                  end
                  # override the standard setter
                  # to be sure both are in sync;
                  def value=( arg )
                    @value = MyModule.value= arg
                  end
                end # MyClass
              
                begin
                  @@my_instance = MyClass.new()
                end
              end # MyModule
              

              Be very careful with some of the methods for Hash and Array objects that return a new Hash or Array object, for your shared data wrappers. (Try and use the "inplace" methods that have an exclamation point in the name, such as sort! instead of sort.)

              I'm not here much anymore.

              1 Reply Last reply Reply Quote 0
              • C Offline
                Cleverbeans
                last edited by

                Considering the following code, we have MyClass defined in MyModule, which can be accessed with MyModule::MyClass. You do not require the prefix, and note that class methods are differentiated by the 'self.' prefix.

                
                module MyModule
                  class MyClass
                    def self.class_method
                      return "I am a class method"
                    end
                    def instance_method
                      return "I am an instance method"
                    end
                  end
                end
                
                

                Accessing another classes variables is simply a matter of creating getter methods for them. Since you need access to a class variable, you'll want a class method like the following. Note that I've changed it to @@value instead of @@data for the reasons Dan gave.

                
                class MyClass
                  def self.value
                    return @@value
                  end
                end
                
                

                With that being said, It begs the question as to why you require access to a variable across multiple classes because global variables are really bad mojo. One of the great things about namespaces is localization, as it allows you to isolate bugs to a specific region of your code or to reuse your code without having to untangle it from other portions of your application. It's interesting to note that you can actually write every conceivable program without modifying any variables at all. This style of programming is generally called functional programming and it avoids the side effects that can crop up when you're modifying a variable.

                If you absolutely much have a global, then there are a few ways you can implement this. You can simply have a getter like the example above, or you can have a superclass which handles interaction with that global then have the classes which require access to that variable inherit from it. Note that if you want a class level variable which is isolated to a class and not accessible by it's subclasses/superclasses then you'd want a class instance variable. But once again I'd encourage you to avoid doing this at all costs, as you can likely avoid the global entirely and avoid a lot of headaches in the process.

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

                  Aha, I was confused about what a class variable vs. an instance variable was. I was really meaning to say instance variable. Now I see that there are two things here.

                  EDIT: Grr, I meant to say class methods vs instance methods. Sometimes I just can't get anything right πŸ˜„

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

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

                    Your guys's code is very helpful here, thanks for posting it. I am examining it closely.

                    Also, that variable that I wanted access to across classes and modules is really an array of objects. I've got it working just having a method in the module that returns the array. That is working perfect for what I really need at this point.

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

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

                      @chris fullmer said:

                      Aha, I was confused about what a class variable vs. an instance variable was. I was really meaning to say instance variable. Now I see that there are two things here.

                      Yes.. and there are three (3) basic kinds of methods, a class method, a module method (aka singleton method,) and an instance method.

                      Calling methods, assume ChrisCode is your module identifier.

                      Class methods:
                      ChrisCode::MyClass.class_method( args )

                      Module (singleton) method:
                      ChrisCode.singleton_method( args )

                      • note that because Module is a class, it can (and does,) have class methods of it's own, such as:
                        Module.nesting()
                        .. but these are class methods, not module methods. You cannot call, for example:
                        ChrisCode.nesting() # because ChrisCode is an instance of class Module, not actually THE class Module.
                        .. but you can call:
                        ChrisCode.class.nesting()
                        .. because ChrisCode.class would return the constant Module which points at the class defintion object, within which the class method nesting() is defined.

                      Instance method:
                      inst = ChrisCode::MyClass.new( args ) inst.instance_method( args )

                      I'm not here much anymore.

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

                        That is great Dan, thanks so much. That is very helpful, and is finally all starting to soak in and make sense. I don't entirely understand where I would use some of this, but I'm sure at some point I'll come across good reasons for things like module methods and mix-ins. I'm just not there yet in my programming needs.

                        But a big big thank you for taking the time to write this out. Its very helpful,

                        Chris

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

                        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