Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby 메타프로그래밍:실제 사례

이전에 Ruby 메타프로그래밍에 대해 읽은 적이 있을 것입니다.

하지만…

몇 가지 구체적인 예가 없으면 약간 혼란스러울 수 있습니다.

그래서 이 기사에서 :

Ruby 메타프로그래밍을 사용하는 몇 가지 인기 있는 오픈 소스 프로젝트를 살펴보겠습니다.

다음과 같은 프로젝트 :

  • 레일
  • 시나트라
  • 종이 클립 보석

그들 모두는 일종의 메타프로그래밍을 사용합니다. .

코드를 살펴보고 정확히 무엇을 하는지 알아봅시다!

레일 예

Rails는 메타프로그래밍을 많이 사용하므로 처음부터 살펴보는 것이 좋습니다.

예를 들어 :

Rails 앱에서 현재 환경을 확인하려면 다음과 같이 하면 됩니다.

Rails.env.production?

하지만 env는 무엇입니까? ? 어떻게 작동합니까?

답변은 StringInquirer에 있습니다. String의 하위 클래스인 클래스 . 이 클래스는 method_missing을 사용합니다. env.production?을 호출할 수 있도록 env == production 대신 .

코드는 다음과 같습니다. :

def method_missing(method_name, *arguments)
  if method_name[-1] == '?'
    self == method_name[0..-2]
  else
    super
  end
end

이것은 :

"메소드 이름이 물음표로 끝나면 비교를 수행하고, 그렇지 않으면 상위 체인으로 계속 이동하십시오."

원본 코드는 여기에서 찾을 수 있습니다.

시나트라 대표단

이전에 Sinatra를 사용한 적이 있다면 경로를 정의하는 데 두 가지 방법이 있음을 알 수 있습니다.

  • get 사용 / post 클래스 외부에서 직접 메서드를 사용할 수 있습니다.
  • Sinatra::Application에서 상속하는 클래스 정의 .

Sinatra DSL(Domain-Specific Language) 메서드는 Sinatra::Application 내부에 정의되어 있습니다. , 그러면 이 클래스 외부에서 어떻게 사용할 수 있습니까?

여기에는 두 가지 일이 있습니다. :

  • 메타프로그래밍
  • 모듈 확장

Sinatra는 Sinatra::Delegator를 정의합니다. target에 메소드 호출을 위임하는 데 사용되는 base.rb 내부의 모듈 .

대상은 Sinatra::Application으로 설정됩니다. 기본적으로.

이것은 delegate의 단순화된 버전입니다. Sinatra::Delegator에 정의된 클래스 메서드 :

def self.delegate(*methods)
  methods.each do |method_name|
   define_method(method_name) do |*args, &block|
     Delegator.target.send(method_name, *args, &block)
   end
  end
end

delegate :get, :patch, :put, :post, :delete

이 코드는 메소드 세트를 생성합니다(define_method 사용). ) 메소드 호출을 Sinatra::Application으로 전달합니다. (Delegator.target의 기본값 ).

그런 다음 main 객체는 Sinatra::Delegator에 정의된 메소드로 확장됩니다. , Sinatra DSL을 Sinatra::Application 외부에서 사용할 수 있도록 합니다. 수업.

Ruby에는 필요한 경우를 대비하여 메서드 위임을 위한 두 가지 내장 클래스가 있습니다. Delegator 및 Forwardable입니다.

종이 클립의 보석

Paperclip은 애플리케이션이 파일 업로드를 처리할 수 있게 해주는 보석입니다. 파일은 ActiveRecord와 연결되어 있습니다. 모델.

has_attached_file을 사용하여 모델에 첨부 파일을 정의할 수 있습니다. 방법.

좋아요 :

class User
  has_attached_file :avatar, :styles => { :normal => "100x100#" }
end

이 메서드는 paperclip.rb에 정의되어 있으며 메타프로그래밍을 사용하여 모델에 메서드를 정의합니다.

이 메소드는 첨부 파일에 액세스하는 데 사용할 수 있습니다(Paperclip::Attachment 수업).

예를 들어 첨부 파일이 :avatar인 경우 , Paperclip avatar를 정의합니다. 모델에 대한 방법입니다.

다음은 define_instance_getter입니다. 그 책임이 있는 메소드:

# @name  => The name of the attachment
# @klass => The ActiveRecord model where this method is being defined

def define_instance_getter
  name    = @name
  options = @options

  @klass.send :define_method, @name do |*args|
    ivar = "@attachment_#{name}"
    attachment = instance_variable_get(ivar)

    if attachment.nil?
      attachment = Attachment.new(name, self, options)
      instance_variable_set(ivar, attachment)
    end
  end
end

이 코드에서 첨부 개체가 @attachment_#{name} 아래에 저장되어 있음을 알 수 있습니다. 인스턴스 변수.

이 예에서는 @attachment_avatar가 됩니다. .

그런 다음 이 첨부 파일이 이미 있는지 확인하고 없으면 새 Attachment을 만듭니다. 개체 및 인스턴스 변수를 설정합니다.

다음은 원본 소스 코드입니다.

결론

이미 보았듯이 메타프로그래밍은 매우 강력하고 유연한 기술이지만, "큰 힘에는 큰 책임이 따른다"라는 문구를 기억하고 싶을 때마다 이를 기억하십시오.

이 게시물이 마음에 드셨다면 제 뉴스레터 구독을 잊지 마세요 🙂