Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyメタプログラミング:実際の例

以前にRubyメタプログラミングについて読んだことがあるかもしれません。

しかし…

具体的な例がいくつかない場合は、少し混乱する可能性があります。

そのため、この記事では

Rubyメタプログラミングを使用した人気のあるオープンソースプロジェクトをいくつか見ていきます。

次のようなプロジェクト

  • レール
  • シナトラ
  • ペーパークリップの宝石

それらはすべて、何らかの形式のメタプログラミングを使用しています 。

コードを調べて、彼らが何をしているのかを正確に調べましょう!

Railsの例

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

これは言っています

「メソッド名が疑問符で終わっている場合は、比較を行います。それ以外の場合は、祖先チェーンを上っていきます。」

元のコードはここにあります。

シナトラ代表団

ルートを定義する方法が2つあることを知っている前に、シナトラを使用したことがある場合:

  • getを使用する /post クラス外のメソッド。
  • Sinatra::Applicationから継承するクラスを定義する 。

Sinatra DSL(ドメイン固有言語)メソッドは、Sinatra::Application内で定義されています。 、では、このクラスの外でどのように使用できますか?

ここでは2つのことが起こっています

  • メタプログラミング
  • モジュール拡張

SinatraはSinatra::Delegatorを定義します base.rb内のモジュール。これは、メソッド呼び出しをtargetに委任するために使用されます。 。

ターゲットは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で定義されたメソッドで拡張されます 、これにより、SinatraDSLがSinatra::Applicationの外部で利用可能になります クラス。

Rubyには、必要に応じて、メソッド委任用の2つの組み込みクラス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を作成します。 オブジェクトを作成し、インスタンス変数を設定します。

これが元のソースコードです。

結論

これまで見てきたように、メタプログラミングは非常に強力で柔軟な手法ですが、メタプログラミングに到達したいときはいつでも、「大きな力には大きな責任が伴う」という引用を覚えておいてください。

この投稿を楽しんだら、私のニュースレターを購読することを忘れないでください🙂


  1. Ruby Mapメソッドの使用方法(例付き)

    Mapは、配列、ハッシュ、範囲で使用できるRubyメソッドです。 マップの主な用途は、データを変換することです。 例 : 文字列の配列が与えられた場合、すべての文字列に目を通し、すべての文字を大文字にすることができます。 または、Userのリストがある場合 オブジェクト… 変換できます 対応するメールアドレス、電話番号、またはその他の属性のリストにそれらを追加します Userで定義 クラス。 これを行う方法を正確に見てみましょう! ルビーマップ構文 マップの構文は次のようになります: array = [a, b, c] array.map { |string| string.

  2. メタプログラミングの隠れたコスト

    メタプログラミングは非常に派手な言葉のように聞こえますが、それは何か良いことですか? 便利な場合もありますが、メタプログラミングの使用にはいくらかのコストがかかることに多くの人が気づいていません。 同じページにいるので… メタプログラミングとは 正確に? 私はメタプログラミングを次のような方法を使用するものとして定義しています: コードの構造を変更します(define_methodなど) ) 文字列を実際のRubyコードの一部であるかのように実行します(instance_evalなど)。 ) 何らかのイベントへの反応として何かを行います(method_missingなど) ) で