어떻게 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

@Pyro 명확히하기 위해 그냥 가겠 singleton_class.define_method :loudly do |message|습니까?
Joshua Pinter

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하므로 쉽고 독립적 인 속기를 아는 것이 좋습니다.
Chinasaur 2009

나는 나의 원래 대답으로 가기로 결정했습니다. 내 이해는 Ruby 1.9에서 사라질 경우 send ()를 사용하여 개인 메서드에 액세스하므로 사용하기에 좋지 않은 것 같습니다. 또한 둘 이상의 메서드를 정의하는 경우 블록을 instance_evaling하는 것이 더 깨끗합니다.
Chinasaur

@Vincent Robert 메타 클래스 메서드의 마법을 설명하는 링크가 있습니까?
Amol Pujari

클래스 << self; 본인; 종료; 단순히 self 클래스 (class << self)를 다시 열고 해당 클래스 (self)를 반환하므로 실제로 self의 메타 클래스를 반환합니다.
Vincent Robert

10

이것은 Ruby 1.8+에서 가장 간단한 방법입니다.

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

1
나는 이것을 정말로 좋아한다. 작고 깔끔하며 잘 읽고 휴대가 가능합니다. 물론, 당신은 ... 2013 년에 나는 루비 1.8를 사용하고있어 어떤 질문을 할 수있어
페이더 어둡에게

8

출처 : Jay and Why , 누가 더 예쁘게 만드는 방법도 제공합니다.

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

업데이트 : 아래 VR의 기여에서; 여전히 독립형 인 더 간결한 방법 (이 방법으로 하나의 방법 만 정의하는 한) :

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.