• Login
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
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.
  • C Offline
    Chris Fullmer
    last edited by 17 Apr 2011, 08:38

    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
    • D Offline
      Dan Rathbun
      last edited by 17 Apr 2011, 11:43

      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
      • D Offline
        Dan Rathbun
        last edited by 17 Apr 2011, 13:16

        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
        • D Offline
          Dan Rathbun
          last edited by 17 Apr 2011, 13:39

          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
          • D Offline
            Dan Rathbun
            last edited by 17 Apr 2011, 16:53


            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 21 Apr 2011, 18:58

              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
              • C Offline
                Chris Fullmer
                last edited by 30 Apr 2011, 22:21

                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
                • C Offline
                  Chris Fullmer
                  last edited by 30 Apr 2011, 23:55

                  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
                  • D Offline
                    Dan Rathbun
                    last edited by 1 May 2011, 01:30

                    @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
                    • C Offline
                      Chris Fullmer
                      last edited by 25 Jun 2011, 21:38

                      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