Search code examples
rubyclassoverriding

Is it possible to replicate the Override Annotation from Java in Ruby?


I know that in Java, the Override annotation checks if the superclass has the method:

class Animal {
  public void speak () {
    System.out.println("Hello!");
  }
}
class Dog extends Animal {
  @override
  public void eat () { //this kind of stuff
    System.out.println("omnomnom");
  }
}

is there a way to do this in Ruby (as a function or something)?


Solution

  • this works, but it's a little verbose:

    class OverrideError < StandardError
        def initialize a
            super("the superclass of `#{a[0]}`(`#{a[0].superclass}`) does not contain the method that has been attempeted to Override: `#{a[1]}`")
        end
    end
    
    #this function help the _override_ function ignore string literals
    def delQ str
        str = str.gsub(/(".*"|'.*'|\%[qQ]?\{.*\})/, "")
        while /\= ?\<\<\-?[\w\_\?\!]+ /.match?(str)
            x = /\= ?\<\<\-?[\w\_\?\!]+ /.match(str)[0]
            stopname = x.sub(/\= ?\<\<\-?/, "")
            locat = str =~ /\= ?\<\<\-?[\w\_\?\!]+ .*/
            part = str.slice(locat)
            stop = part =~ %r{stopname}
            part1 = part.sub(%r{x + ".*" + stopname}, "")
            str = str.sub(part, part1)
        end
        return str
    end
    
    def _override_
        file = File.read("./" + caller[0][/[^:]+/]).split("\n")
        loc = (caller[0].to_s.scan(/\d+/).first).to_i
        line = file[loc]
        method = /def (self(\.|::))?[\w\_\?\!]+/.match(line)[0]
        method = method.gsub(/(def|self|\.|::|\s)/, "")
        clname = ""
        file = file.join("\n")
        file = delQ(file)
        file = file.split("\n")
        while loc >= 0
            substr = file[loc].gsub(/(\t|\n)/, "")
            if substr.start_with?("class ")
                clname = file[loc].gsub(/\t/, "").sub("class ", "")
                clname = /[\w_\?\!]+/.match(clname)[0]
                break
            end
            loc -= 1
        end
        clname = Kernel.const_get(clname)
        hmm = clname.superclass.method_defined?(method.to_sym)
        unless hmm
            raise OverrideError, [clname, method]
        end
    end
    

    A demonstration on how this will be used:

    class Animal
        def initialize name
            @name = name
        end
        def speak
            puts "Hello!"
        end
    end
    class Dog < Animal
        def initialize name
            super name
        end
        _override_
        def speak
            # no error
            puts "woof!"
        end
        _override_ 
        def eat
    
    
    #Traceback (most recent call last):
    #   2: from main.rb:11:in `<main>'
    #   1: from main.rb:19:in `<class:Dog>'
    #/home/runner/Annotations/override.rb:41:in `_override_': the superclass #of `Dog`(`Animal`) does not contain the method that has been attempted #to Override: `eat` (OverrideError)
    
    
            puts "omnomnom"
        end
    end