ruby - 检查是否调用了类方法

标签 ruby

我有以下模块和类:

module MyModule
  def self.included base
    base.extend(ClassMethods)
  end

  module ClassMethods
    attr_reader :config

    # this method MUST be called by every class which includes MyModule
    def configure &block
      @config = {}
      block.call(@config) if block
    end
  end
end

class A
  include MyModule

  configure do |config|
    # do sth with the config
  end
end

class B
  include MyModule
end

是否可以检查模块中的 configure 方法是否被调用?这意味着 A 应该没问题,但是 B 应该抛出错误,因为它从未调用过 configure

我在 self.included 回调中尝试过,但是之后调用了 configure 方法。

最佳答案

从技术上讲,@ndn 是正确的,它可以在类被评估后调用。但是,听起来您想要的是验证 configure 方法是否已在类主体定义中的某个点被调用(这也将允许任何已包含的模块完成评估,因此如果模块包含调用 configure方法,这一切都很好)。

我想出的解决这种情况的最接近的解决方案可以在这里找到:

https://github.com/jasonayre/trax_core/blob/master/lib/trax/core/abstract_methods.rb

上面的代码是 ruby​​ 的抽象方法实现,从技术上讲这不是你要的(你说的是调用方法,抽象方法是检查子类是否定义了它),但我的技巧是一样的在那里可以应用。

基本上,我使用 ruby​​ 的跟踪点库来监视要命中的类定义的末尾,此时它会触发一个事件,我检查该方法是否已定义,如果没有定义则抛出错误。因此,只要您从类中调用配置,类似的解决方案就可以为您工作。类似(未测试):

module MustConfigure
  extend ::ActiveSupport::Concern

  module ClassMethods
    def inherited(subklass)
      super(subklass)
      subklass.class_attribute :_configured_was_called
      subklass._configured_was_called = false

      trace = ::TracePoint.new(:end) do |tracepoint|
        if tracepoint.self == subklass #modules also trace end we only care about the class end
          trace.disable

          raise NotImplementedError.new("Must call configure") unless subklass._configured_was_called
        end
      end

      trace.enable

      subklass
    end

    def configure(&block)
      self._configured_was_called = true
      #do your thing
    end
  end
end

class A
  include MustConfigure
end

class B < A
  configure do
    #dowhatever
  end
end

class C < B
  #will blow up here
end

或者,您可以尝试使用我的库中的 InheritanceHooks 模块并跳过手动跟踪点处理:

class BaseClass
  include::Trax::Core::InheritanceHooks
  after_inherited do
    raise NotImplementedError unless self._configure_was_called
  end
end

请注意,虽然我目前正在生产中使用这种模式,并且在 MRI 上一切正常,因为 tracepoint 是一个为调试而构建的库,但在使用 jruby 时存在一些限制。 (现在它会中断,除非您传递 jruby 调试标志)——我前段时间打开了一个问题,试图在不必显式启用调试的情况下添加跟踪点。

https://github.com/jruby/jruby/issues/3096

关于ruby - 检查是否调用了类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34763817/

相关文章:

java - 在 Rails 应用程序中实现 Java 门面/服务概念的最佳方式

ruby - Minitest 断言在检查时失败

ruby - Heroku 应用程序崩溃,错误 H10,open.rb 中的错误文件描述符 (Errno::EBADF)

ruby - 如何在模块中动态调用实例方法

ruby - 在返回散列或 nil 的方法上使用 ruby​​ 'or equals' ||=

ruby-on-rails - 如何创建一个带有参数的 Rails 4 关注点

Bundler::GemNotFound 的 Ruby 问题

ruby - 如何从/usr/local 卸载 Ruby?

ruby-on-rails - Ruby - 查找具有相同属性的所有记录并将它们分组

ruby - 尝试使用现有 git 存储库上传 Sinatra 应用程序时出现 "Heroku push rejected, no Cedar-supported app detected"