3

クラス メソッドとインスタンス メソッドの両方を含めたい Ruby クラスがあります。hereで説明されているパターンに従って、現在次のものを使用しています。

class SomeObject

  include SomeObject::Ability

  def self.some_builder_method(params)
    # use some_class_method ...
  end

end

module SomeObject::Ability

  module ClassMethods

    def some_class_method(param)
      # ...
    end

  end

  def self.included(klass)
    klass.extend(ClassMethods)
  end

  def some_instance_method
    # ...
  end

end

モジュール内のすべてのメソッドが論理的に適合するため、2 つの別個のモジュール (1 つは組み込み、もう 1 つは拡張) を作成したくありません。一方、このパターンでは、a) 追加のClassMethodsモジュールを定義する必要があり、b) すべてのモジュールに対してボイラープレートself.includedメソッドを記述する必要があります。

これを行うより良い方法はありますか?

編集 1 : 別の方法を見つけましたが、これが最初の方法よりも優れているかどうかはわかりません。

module Concern

  def included(base)

    # Define instance methods.
    instance_methods.each do |m|
      defn = instance_method(m)
      base.class_eval { define_method(m, defn) }
    end

    # Define class methods.
    (self.methods - Module.methods).each do |m|
      unless m == __method__
        base.define_singleton_method(m, &method(m))
      end
    end

  end

end

module SomeModule

  extend Concern

  def self.class_m
    puts "Class"
  end

  def instance_m
    puts "Instance"
  end

end

class Allo

  include SomeModule

end


Allo.class_m          # => "Class"
Allo.new.instance_m   # => "Instance"
4

1 に答える 1

4

私があなたを正しく理解していれば、あなたは本当に使いたいだけですActiveSupport::Concern

module PetWorthy
  extend ActiveSupport::Concern

  included do
    validates :was_pet, inclusion: [true, 'yes']
  end

  def pet #instance method
  end

  module ClassMethods
    def find_petworthy_animal
      # ...
    end
  end
end

class Kitty
  include PetWorthy
end

Kitty.find_petworthy_animal.pet

includedインクルード時にトリガーする動作がない場合は(できれば明らかに) メソッドを使用する必要はありませんが、デモ用に入れました。

于 2013-03-08T23:53:36.537 に答える