Override method_changing class and instance methods?

I am trying to write a general purpose module to apply the method_missing template to create a dynamic method to some of my Rails models. These models have both class methods and instance methods. Although I can write a module quite simply for any class:

  module ClassVersion
    extend ActiveSupport::Concern

    module ClassMethods
      def method_missing(meth, *args, &block)
        if meth.to_s =~ /^(.+)_async$/
          Async::handle_async self, $1, *args, &block
        else
          super meth, *args, &block
        end
      end

      # Logic for this method MUST match that of the detection in method_missing
      def respond_to_missing?(method_name, include_private = false)
        Async::async?(method_name) || super
      end
    end
  end

or instance case:

  module InstanceVersion
    extend ActiveSupport::Concern

    def method_missing(meth, *args, &block)
      if meth.to_s =~ /^(.+)_async$/
        Async::handle_async self, $1, *args, &block
      else
        super meth, *args, &block
      end
    end

    # Logic for this method MUST match that of the detection in method_missing
    def respond_to_missing?(method_name, include_private = false)
      Async::async?(method_name) || super
    end
  end

... It seems that I do not support both cases in the same class. Is there a better way to override method_missing so that both cases are supported? I'm on Rails 3.2 ....

+4
source share
2 answers

, , . ActiveSupport::Concern ClassMethods, included. , .

ActiveSupport::Concern included hook :

module AsyncModule
  def method_missing(meth, *args, &block)
    if meth.to_s =~ /^(.+)_async$/
      Async::handle_async self, $1, *args, &block
    else
      super meth, *args, &block
    end
  end

  # Logic for this method MUST match that of the detection in method_missing
  def respond_to_missing?(method_name, include_private = false)
    Async::async?(method_name) || super
  end

  private

  def self.included(base)
    base.extend self
  end
end
+6

  module ClassAndInstanceVersion
    extend ActiveSupport::Concern

    def method_missing(meth, *args, &block)
      self.class.method_missing(meth, *args, &block)
    end

    def respond_to_missing?(method_name, include_private = false)
      self.class.respond_to_missing?(method_name, include_private)
    end

    module ClassMethods
      def method_missing(meth, *args, &block)
        if meth.to_s =~ /^(.+)_async$/
          Async::handle_async self, $1, *args, &block
        else
          super meth, *args, &block
        end
      end

      # Logic for this method MUST match that of the detection in method_missing
      def respond_to_missing?(method_name, include_private = false)
        Async::async?(method_name) || super
      end
    end
  end
0

Source: https://habr.com/ru/post/1534901/


All Articles