rubyinheritancedrycomposite

Ruby: why doesn't calling super.method work from subclass


I apologize up front. I'm going to struggle articulating this question.

TL;DR - I have an object I'm using to call a method in the subclass. That method needs access to a method in a parent class (forcing inheritance...read below). I'm thinking this won't work because I'm instantiating the subclass, so the inheritance won't work right, but I'm not sure. I'm still seeking out documentation. Basically, the method in the parent class is not "seen" the way I'm doing this - NoMethodError is the exception.

I prefer DRY code, as most people do. I usually use compositing in lieu of inheritance in my code, but I think I'm at a point where if I want to keep this DRY, I have to use inheritance (though I could be wrong, so I'm open to suggestions), and so I'm trying it out, which leads me to this question.

Given the following Ruby "pseudo" code or example to kind of demonstrate what I'm trying to accomplish:

module SomeModule
  class ParentClass
    def initialize
    end

    def method_i_want_to_use(arg1, *args)
      # does all the things
    end

    def self.method_i_want_to_use(arg1, *args)
      arg = args.first unless args.empty?
      self.class.method_i_want_to_use(arg1, arg)
    end
  end
end

And then in a different file, same module

module SomeModule
  class SubClass < ParentClass
    def initialize
    end

    # this isn't working
    def my_other_method
      # things get done and then
      method_i_want_to_use(arg1, args)  ## <<=== fails
    end
  end
end

Yet in another file

module SomeModule
  class Thing
    def initialize
      @my_obj = SubClass.new
    end

    def my_method
      @my_obj.my_other_method
    end
  end
end

So one important thing I missed. The method method_i_want_to_use is a method that is used all over the place in my code. It just so happens that in this one class, inheritance was NOT originally used because this class is basically atomic with the exception of this one method. So my problem is either I copy the method into this class and use it (but that kinda breaks the DRY principle sorta) or I find a way to share this method between classes.

This gets into OOP design pretty heavily and I am aware of that. One could ask: well, is the inheritance as it currently sits even relevant to the objects in question? Yes...and no. They can be. In short, principally, it works, but frankly, I don't like it. TBH, I almost prefer to just copy the method into the "subclass" and remove the inheritance and be done with it, but DRY -- unless I'm going a little too wild with DRY in this context and I kinda think I am.

Anyway, just curious what folks with more knowledge than I have for me on this. This really is the first time I've dabbled this deeply into inheritance. :) I'd love pointers on how I can keep from implementing


Solution

  • After fixing some of the syntax errors and changing the call self.class.method_i_want_to_use to self.new.method_i_want_to_use as Adam also mentioned in his answer, this code seems to work fine.

    I did not get any undefined methods until I tried to call SomeModule::ParentClass.method_i_want_to_use(3,4) and that was fixed by the change from class to new. Are you sure your undefined method error was not related to that?

    module SomeModule
      class ParentClass
        def initialize
        end
    
        def method_i_want_to_use(arg1, *args)
          # does all the things
          puts "here #{arg1} , #{args}"
        end
    
        def self.method_i_want_to_use(arg1, *args)
          arg = args.first unless args.empty?
          self.new.method_i_want_to_use(arg1, arg)
        end
      end
    end
    
    
    module SomeModule
      class SubClass < ParentClass
        def initialize
        end
    
        # this isn't working
        def my_other_method(arg1, arg2)
          # things get done and then
          method_i_want_to_use(arg1, arg2)  ## <<=== fails
        end
      end
    end
    
    module SomeModule
      class Thing
        def initialize
          @my_obj = SubClass.new
        end
    
        def my_method(arg1,arg2)
          @my_obj.my_other_method(arg1, arg2)
        end
      end
    end
    
    
    SomeModule::Thing.new.my_method(1,2)
    SomeModule::ParentClass.method_i_want_to_use(3,4)
    
    
    prints:
    here 1 , [2]
    here 3 , [4]