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
を作成します。 オブジェクトを作成し、インスタンス変数を設定します。
これが元のソースコードです。
結論
これまで見てきたように、メタプログラミングは非常に強力で柔軟な手法ですが、メタプログラミングに到達したいときはいつでも、「大きな力には大きな責任が伴う」という引用を覚えておいてください。
この投稿を楽しんだら、私のニュースレターを購読することを忘れないでください🙂
-
Ruby Mapメソッドの使用方法(例付き)
Mapは、配列、ハッシュ、範囲で使用できるRubyメソッドです。 マップの主な用途は、データを変換することです。 例 : 文字列の配列が与えられた場合、すべての文字列に目を通し、すべての文字を大文字にすることができます。 または、Userのリストがある場合 オブジェクト… 変換できます 対応するメールアドレス、電話番号、またはその他の属性のリストにそれらを追加します Userで定義 クラス。 これを行う方法を正確に見てみましょう! ルビーマップ構文 マップの構文は次のようになります: array = [a, b, c] array.map { |string| string.
-
メタプログラミングの隠れたコスト
メタプログラミングは非常に派手な言葉のように聞こえますが、それは何か良いことですか? 便利な場合もありますが、メタプログラミングの使用にはいくらかのコストがかかることに多くの人が気づいていません。 同じページにいるので… メタプログラミングとは 正確に? 私はメタプログラミングを次のような方法を使用するものとして定義しています: コードの構造を変更します(define_methodなど) ) 文字列を実際のRubyコードの一部であるかのように実行します(instance_evalなど)。 ) 何らかのイベントへの反応として何かを行います(method_missingなど) ) で