1

私はRuby1.9.2とRubyonRailsv3.2.2gemを使用しています。私はメタプログラミングを「正しい方法」で学ぼうとしています。現時点では、RoRモジュールによって提供されるブロックのインスタンスメソッドをエイリアスしています。included do ... endActiveSupport::Concern

module MyModule
  extend ActiveSupport::Concern

  included do
    # Builds the instance method name.
    my_method_name = build_method_name.to_sym # => :my_method

    # Defines the :my_method instance method in the including class of MyModule.
    define_singleton_method(my_method_name) do |*args|
      # ...
    end

    # Aliases the :my_method instance method in the including class of MyModule.
    singleton_class = class << self; self end
    singleton_class.send(:alias_method, :my_new_method, my_method_name)        
  end
end

「初心者」と言えば、Webで検索してステートメントを思いつき、変数のスコープを設定するために(ブロックsingleton_class = class << self; self endの代わりに)それを使用して、エイリアシングを動的に生成しました。class << self ... endmy_method_name

上記のコードで機能する理由方法を正確に理解しsingleton_class、同じものを実装するためのより良い方法(おそらく、より保守可能でパフォーマンスの高い方法)があるかどうか(エイリアシング、シングルトンメソッドの定義など)を理解したいと思いますが、 "そうではないと思うので。

4

1 に答える 1

7

Rubyの自己のメタプログラミングに関するYehudaKatzの投稿をお勧めします。これがあなたの質問に対する私の謙虚な要約です:

Rubyでは、すべてのオブジェクトにシングルトンクラス(メタクラスとも呼ばれます)があります。オブジェクトは、最初にシングルトンクラスから目に見えない形で継承し、次に明示的なクラスから継承します。クラスもオブジェクトであるため、Rubyクラス自体には独自のシングルトンクラスがあります。このclass <<イディオムは、オブジェクトのシングルトンクラスのスコープにアクセスするためのRubyの構文です。

 class Person
   class << self
     # self in this scope is Person's singleton class
   end
 end

 person = Person.new
 person_singleton_class = class << person; self; end

Railsのバージョンは実際にはsingleton_classショートカットとして提供されています。は使用可能なメソッドであるためsingleton_class、式の変数に割り当てる必要はありませんsingleton_class = class << self; self end

Person.singleton_class 

person = Person.new
person.singleton_class

クラスはそのシングルトンクラスから直接継承するため、メタプログラミング時にクラスメソッドを動的に追加する必要があります。Rubyは、周囲のスコープへのアクセスを維持しながら、オブジェクトのスコープを開くためのいくつかの方法を提供しclass_evalますinstance_eval。これらの動作には微妙な違いがありますが(Yehudaの投稿でこれを説明しています)、シングルトンクラスのスコープを入力するか、シングルトンクラスのメソッドを解決するか、周囲のスコープからselfアクセスできるかのいずれかを使用できます。my_method_name

そうは言っても、モジュールにいくつかの小さな変更を加えることができます。

module MyModule
  extend ActiveSupport::Concern

  included do
    # Builds the instance method name.
    my_method_name = build_method_name.to_sym # => :my_method

    # Defines the :my_method instance method in the including class of MyModule.
    define_singleton_method(my_method_name) do |*args|
      # ...
    end

    singleton_class.class_eval do
      # method resolution in scope of singleton class
      alias_method :my_new_method, my_method_name
    end

  end

end
于 2012-10-17T22:58:29.443 に答える