1

サブクラスの各メソッドの後に 1 つのメソッド呼び出しをラップする、ある種のモジュールまたはスーパークラスを作成しようとしています。ただし、いくつかの制約があります。initialize() が呼び出された後や、選択した他のいくつかのメソッドが呼び出された後にメソッドを実行したくありません。もう 1 つの制約は、フラグ@check_ecが true に設定されている場合にのみ、そのメソッドを実行することです。私は 60 以上のメソッドを持つクラスを持っており、あちこちに貼り付けられたのと同じコードをハードコーディングしました。クラスメソッドのメソッドを自動的に実行するラッパーを作成する方法はありますか?

したがって、アイデアは次のとおりです。

class Abstract
  def initialize(check_ec)
    @check_ec = check_ec
  end
  def after(result) # this is the method that I'd like to be added to most methods
    puts "ERROR CODE: #{result[EC]}"
  end
  def methods(method) # below each method it would execute after
    result = method() # execute the given method normally
    after(result) if @check_ec and method != :initialize and method != :has_valid_params
  end
end

class MyClass < Abstract
  def initialize(name, some_stuff, check_error_code)
   # do some stuff...
    @name = name
    super(check_error_code)
  end
  def my_method_a() # execute after() after this method
    return {EC: 0}
  end   
  def my_method_b() # execute after() after this method
    return {EC: 7}
  end
  def has_valid_params() # don't execute after() on this method
    return true
  end

end
4

3 に答える 3

0

これはどうですか?を呼び出す前にメソッドを定義しておく必要があるという大きな欠点がありcheck_error_codeますが、ニーズに合う場合があります。Rails コールバックでより良い解決策のヒントを探すか、method_addedフックを使用してそのメソッドが追加されるまで各メソッドの再定義を延期することができます。

エラーコードを確認したい各クラスにインクルードErrorCodeCheckerして呼び出します (スニペットの最後の行のように)。check_error_code

module ErrorCodeChecker
  def self.included(base)
    base.send(:extend, ClassMethods)
  end

  def after(result) # this is the method that I'd like to be added to most methods
    puts "ERROR CODE: #{result[:ec]}"
  end

  module ClassMethods
    def check_error_code(options = {})
      check_on = instance_methods(false) - Array(options[:except])
      check_on &= Array(options[:only]) if options[:only]
      class_eval do
        check_on.each do |method|
          alias_method "#{ method }_without_ec", method
          define_method(method) do |*args, &block|
            send("#{ method }_without_ec", *args, &block).tap { |result| after(result) if @check_ec }

            #if you want to actually return the return value of calling after:
            #result = send("#{ method }_without_ec")
            #@check_ec ? after(result) : result
          end
        end
      end
    end
  end
 end

class Abstract
  include ErrorCodeChecker

  def initialize(check_ec)
    @check_ec = check_ec
  end
end

class MyClass < Abstract

  def initialize(name, some_stuff, check_error_code)
    # do some stuff...
    @name = name
    super(check_error_code)
  end
  def my_method_a # execute after() after this method
    {ec: 0}
  end   
  def my_method_b # execute after() after this method
    {ec: 7}
  end
  def has_valid_params # don't execute after() on this method
    true
  end

  check_error_code except: :has_valid_params
  #or whitelisting:
  #check_error_code only: [:my_method_a, :my_method_b]
  #or both:
  #check_error_code only: :my_method_a, except: [:has_valid_params, dont_check_this_one]
end 
于 2013-08-22T00:33:49.783 に答える