是否可以在Ruby中复制Java中的JavaScript注解?

ao218c7q  于 2023-10-17  发布在  Ruby
关注(0)|答案(4)|浏览(78)

我知道在Java中,注解检查超类是否有方法:

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");
  }
}

在Ruby中有没有办法做到这一点(作为一个函数或其他东西)?

8wigbo56

8wigbo561#

这将是相对容易的一个类方法定义的顶级特征类。

class Animal
  def speak; :ok; end

  def self.override *ms
    ms = ms - Animal.instance_methods
    puts "⚠️ #{ms.inspect} method(s) missing " \
         "in #{self}’s ancestors" unless ms.empty?
  end
end

class Dog < Animal
  override :speak
  def speak; :ok; end

  override :eat
  def eat; :ok; end
end

上面将打印

# ⚠️ [:eat] method(s) missing in Dog’s ancestors

这里对override的调用类似于对Module#module_function的带参数调用,可以放置在代码中的任何位置,并根据需要接受任意多个方法名。
它也可以用eigenclass示例变量来完成,使它看起来更像java版本。

class Animal
  def speak
    :ok
  end

  def self.inherited(base)
    base.instance_variable_set(:@override, ->(*ms) {
      ms = ms - Animal.instance_methods
      puts "⚠️ #{ms.inspect} method(s) without super" \
        unless ms.empty?
    })
  end
end

class Dog < Animal
  @override[:speak]
  def speak; :ok; end

  @override[:eat]
  def eat; :ok; end
end

TracePoint和/或Module#method_added的帮助下,也可以 * 完全 * 复制Java语法,但我发现它不太明确,并且会避免直接传递方法名,如上所示。

sbtkgmzw

sbtkgmzw2#

这是可行的,但它有点冗长:

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

演示如何使用它:

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
z8dt9xmd

z8dt9xmd3#

只是要抛出这个旧的要点(我的),实现的行为:
https://gist.github.com/kares/7434811
可以与参数override :foo一起使用,也可以简单地作为next方法的标记:

class Bar
    include Override

    def foo(msg); end
  end

  class Baz < Bar
    override
    def foo(msg); super; end
  end
p4rjhz4m

p4rjhz4m4#

answer of Aleksei Matiushkin为例,您可以通过将其移动到模块中来提高其可重用性。

module Overridable
  def override(*methods)
    diff = methods - superclass.instance_methods
    return if diff.empty?
    puts "⚠ #{diff.inspect} method(s) missing from #{superclass}"
  end
end

可以在基类Animal中扩展模块,这样所有从Animal继承的子类都有override方法。或者你可以选择只扩展一个特定的子类。

class Animal
  # make :override available in all subclasses
  extend Overridable
end

或者假设上面没有设置。

class Dog < Animal
  # make :override available in only this subclass
  extend Overridable
end

相关问题