Ruby元編程在野外(翻譯,簡學互動)

以前你可能讀到Ruby元編程,也許你的一些項目中使用它,但一些最流行的開源項目是如何利用這個特性?git

答案在這篇文章中!github

Rails示例

Rails大量使用元編程,這是一個開始的好地方。編程

例如,當您想要檢查當前環境,在你的Rails應用程序,你作些什麼:ruby

Rails.env.production?

但什麼是 env而且這是如何工做的呢?答案是 StringInquirer類,String這個類的一個子類。這個類使用 method_missing,讓你能夠調用 env.production?而不是 env == production.post

代碼是這樣的:學習

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

這就是說:「若是是以問號結尾的方法名稱就作比較,不然繼續祖先鏈」。網站

原始代碼可在這裏找到.ui

Sinatra委託

若是您之前使用過Sinatra你可能知道有兩種方法來定義你的路由:經過使用 get / post這種獨立於任何類之外的直接方法,或經過定義一個類繼承自 Sinatra::Application.this

Sinatra的DSL(領域特定語言)方法定義在 Sinatra::Application內,因此你如何在這個類之外使用呢?code

嗯,這裏有兩個事情:元編程和模塊的擴展。

Sinatra定義了一個 Sinatra::Delegator模塊,在base.rb,用於將方法調用委託給一個 target。默認狀況下目標設置爲 Sinatra::Application。

這是一個簡化版的定義於Sinatra::Delegator的delegate類方法:

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 Gem

Paperclip是gem,幫助您的應用程序來處理文件上傳。文件加在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對象和設置實例變量。

這是原始源代碼.

結論

如您所見,元編程是一個很是強大和靈活的技術,但當你想要使用的時候請記得這句話:「強大意味着更大的責任」。

若是你喜歡這篇文章,不要忘了訂閱個人時事通信:)

原英文連接


廣告時間:

Ruby是知識海洋的貝殼,一塊兒來撿吧。

高性價比培訓:

  • 一個月短時間培訓,自由學習無壓力

  • Rails網站開發入門,費用499

  • Ruby和Rails課程,能夠爲進入編程領域作準備

歡迎瞭解和交流

連接:簡學互動Ruby、Rails基礎培訓

相關文章
相關標籤/搜索