이전에 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
을 만듭니다. 개체 및 인스턴스 변수를 설정합니다.
다음은 원본 소스 코드입니다.
결론
이미 보았듯이 메타프로그래밍은 매우 강력하고 유연한 기술이지만, "큰 힘에는 큰 책임이 따른다"라는 문구를 기억하고 싶을 때마다 이를 기억하십시오.
이 게시물이 마음에 드셨다면 제 뉴스레터 구독을 잊지 마세요 🙂