模块包装一个类方法?

d11*_*wtq 5 ruby module wrapper

是否有可能使这项工作成为可能,而不必在课程结束时包含该模块并将其包含在顶部?

module VerboseJob
  def self.included(job_class)
    class << job_class
      alias_method :original_perform, :perform
      def perform(*args)
        JobLogger.verbose { original_perform(*args) }
      end
    end
  end
end

class HelloJob
  include VerboseJob

  def self.perform(arg1, arg2)
    puts "Job invoked with #{arg1} and #{arg2}"
  end
end
Run Code Online (Sandbox Code Playgroud)

我想要发生的是HelloJob.perform实际调用VerboseJob.perform(然后调用块内的原始方法).因为此处的模块包含在类的顶部,所以这不起作用,因为perform尚未定义.移动include到最后确实有效,但是有一种方式更宽容吗?我喜欢将所有包含的模块保留在我的类定义的顶部.

我正在寻找一些被调用的方法Module或者Class它已经完全加载的方法,而不是运行时解释的方法.

Tap*_*nen 2

这是我想出的一种相当迂回/黑客的方法,将包装方法的定义推迟到原始方法被定义为止:

module A
  def self.included(base)
    base.class_eval do
      def self.singleton_method_added(name)
        @@ran||=false
        if name==:perform && !@@ran
          @@ran=true
          class<<self
            alias_method :original_perform, :perform
            def perform(*args)
              puts "Hello"
              original_perform(*args)
            end
          end
        end
      end
    end
  end
end

class B
  include A

  def self.perform
    puts "Foobar"
  end
end

B.perform
Run Code Online (Sandbox Code Playgroud)

编辑:

d11wtq 将其简化为更加清晰:

module VerboseJob
  module ClassMethods
    def wrap_perform!
      class << self
        def perform_with_verbose(*args)
          JobLogger.verbose { perform_without_verbose(*args) }
        end

        alias_method_chain :perform, :verbose \
          unless instance_method(:perform) == instance_method(:perform_with_verbose)
      end
    end

    def singleton_method_added(name)
      wrap_perform! if name == :perform
    end
  end

  def self.included(job_class)
    job_class.extend ClassMethods
    job_class.wrap_perform! if job_class.respond_to?(:perform)
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 我不确定我明白你的意思,我不是这样做的吗? (2认同)
  • 我接受了你的答案(结合这个http://pivotallabs.com/users/rolson/blog/articles/1162-redefine-a-method-from-a-module-like-a-gentleman)并想出了更多简洁 https://gist.github.com/1170661 (无论“include”在哪里完成,它都有效)。请随意编辑您的答案。无论如何我都会接受:) (2认同)