define_methodを使用してクラスメソッドを作成するにはどうすればよいですか?


108

これは、クラスメソッドをメタプログラムで作成しようとしている場合に役立ちます。

def self.create_methods(method_name)
    # To create instance methods:
    define_method method_name do
      ...
    end

    # To create class methods that refer to the args on create_methods:
    ???
end

フォローする私の答え...

回答:


196

Ruby 1.9ではこれができると思います:

class A
  define_singleton_method :loudly do |message|
    puts message.upcase
  end
end

A.loudly "my message"

# >> MY MESSAGE

4
またsingleton_class.define_method
Pyro 2013

@Pyro明確にするために、あなたはsingleton_class.define_method :loudly do |message|他に行きますか?
ジョシュアピンター

25

sendを使用してdefine_methodを呼び出すことを好み、メタクラスにアクセスするためのメタクラスメソッドも作成します。

class Object
  def metaclass
    class << self
      self
    end
  end
end

class MyClass
  # Defines MyClass.my_method
  self.metaclass.send(:define_method, :my_method) do
    ...
  end
end

2
ありがとう!間違いなく、これを自分にとってもっと良くする方法があります。しかし、たとえば、オープンソースプラグインで作業している場合は、で名前空間を詰まらせない方がいいと思うmetaclassので、簡単なスタンドアロンの省略形を知っておくと便利です。
チャイナサウル2009

私は元の答えで行くことにしました。Ruby 1.9で廃止された場合、send()を使用してプライベートメソッドにアクセスするため、これを使用するのは適切ではないようです。さらに、複数のメソッドを定義している場合は、ブロックのinstance_evalingの方がきれいです。
チャイナサウル2009年

@Vincent Robertメタクラスメソッドの魔法を説明するリンクはありますか?
Amol Pujari 2012

クラス<<自己; 自己; 終わり; 単に自分自身のクラス(クラス<<自分)を再度開き、そのクラス(自分)を返すので、実際には自分自身のメタクラスを返します。
Vincent Robert

10

これはRuby 1.8以降で最も簡単な方法です。

class A
  class << self
    def method_name
      ...
    end
  end
end

1
私はこれが本当に好きです。小さく、すっきりとしていて、読みやすく、持ち運びも簡単です。もちろん、2013年にルビー1.8を使って何をしているのかを質問することもできます...
フェーダーダークリー

8

由来:JayWhyは、この美しさを高める方法も提供しています。

self.create_class_method(method_name)
  (class << self; self; end).instance_eval do
    define_method method_name do
      ...
    end
  end
end

更新:以下のVRの貢献による。まだスタンドアロンであるより簡潔なメソッド(この方法で1つのメソッドのみを定義している場合):

self.create_class_method(method_name)
  (class << self; self; end).send(:define_method, method_name) do
    ...
  end
end

ただし、send()を使用してdefine_method()のようなプライベートメソッドにアクセスすることは必ずしも良い考えではないことに注意してください(Ruby 1.9では廃止されることを理解しています)。


より良い(?)代替手段は、物事をモジュールに入れて、create_class_methodでモジュールをクラスに拡張することです??? 参照:blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
Chinasaur

6

関係するクラスのメソッドを動的に定義したい場合にRailsで使用するには:

module Concerns::Testable
  extend ActiveSupport::Concern

  included do 
    singleton_class.instance_eval do
      define_method(:test) do
        puts 'test'
      end
    end
  end
end

-1

define_methodに依存せずに、次のようなこともできます。

A.class_eval do
  def self.class_method_name(param)
    puts param
  end
end

A.class_method_name("hello") # outputs "hello" and returns nil
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.