まず、短いバージョンの場合:
メソッド定義は単なるブロックではありませんか?なぜ私は次のようなことができないのですか?
obj.instance_exec(&other_obj.method(:my_method))
別のクラスのインスタンスのコンテキストでモジュールメソッドを実行することを目的としていますか?このメソッドは呼び出されますが、「instance_exec」呼び出しにもかかわらず、「obj」のコンテキストでは実行されていないようです。
これを実現する方法を理解する唯一の方法は、「my_method」のすべてのコードをprocでラップし、代わりに次の方法で呼び出すことです。
obj.instance_eval(&other_obj.my_method)
ただし、すべてのモジュールメソッドをprocsにカプセル化することは避けたいと思います。
さて、長いバージョンの場合:
モジュール化された外部プロバイダーシステムを作成しようとしています。ここで、特定のクラス/メソッド(通常はコントローラーメソッド)に対して、特定のプロバイダー(Facebookなど)の対応するメソッドを呼び出すことができます。
複数のプロバイダーが存在する可能性があるため、プロバイダーメソッドには名前空間を付ける必要がありますが、たとえば「facebook_invitation_create」のような一連のメソッドを単に含めるのではなく、InvitationsControllerインスタンスにcreateメソッドを含むfacebookメンバーを持たせたいです-例えば
class InvitationsController < ApplicationController
def create
...
# e.g. self.facebook.create
self.send(params[:provider]).create
...
end
end
さらに、プロバイダーメソッドは、コントローラー自体の一部であるかのように機能するだけでなく、コントローラーインスタンス変数、パラメーター、セッションなどにアクセスできる必要があります。また、(ほとんどの場合)記述される必要があります。それらがコントローラー自体の一部であるかのように-モジュール化された結果として複雑な追加コードがないことを意味します。
以下に簡単な例を作成しました。この例では、MyClassにgreetメソッドがあり、有効なプロバイダー名(この場合は:facebook)で呼び出されると、代わりにそのプロバイダーのgreetメソッドが呼び出されます。次に、プロバイダーgreetメソッドは、クラス自体の一部であるかのように、インクルードクラスのメッセージメソッドにアクセスします。
module Providers
def facebook
@facebook ||= FacebookProvider
end
module FacebookProvider
class << self
def greet
proc {
"#{message} from facebook!"
}
end
end
end
end
class MyClass
include Providers
attr_accessor :message
def initialize(message="hello")
self.message = message
end
def greet(provider=nil)
(provider.nil? or !self.respond_to?(provider)) ? message : instance_exec(&self.send(provider).greet)
end
end
これにより、以前に述べたほとんどすべてが実際に実行されますが、プロバイダー関数をprocにカプセル化する必要があるという事実に悩まされています。代わりに、メソッドでinstance_execを呼び出すだけでよいと思いました(procカプセル化を削除した後)。
instance_exec(&self.send(provider).method(:greet))
...しかし、エラーが発生したため、instance_execは無視されているようです。
NameError: undefined local variable or method `message' for Providers::FacebookProvider:Module
定義されたメソッドでinstance_execを呼び出す方法はありますか?
(これをより適切に実装する方法についての提案も受け付けています...)