Skip to content

Instantly share code, notes, and snippets.

@pasberth
Created December 10, 2011 16:56
Show Gist options
  • Select an option

  • Save pasberth/1455584 to your computer and use it in GitHub Desktop.

Select an option

Save pasberth/1455584 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
# Ruby では動的プロクシオブジェクトがよく使われます。
# 利用例は
# - https://gist.github.com/1436624
# - https://gist.github.com/1263663
# - https://github.com/pasberth/Dam/blob/master/src/dam.rb
# gems では lazy などが使っています。
# ============================================================
#
# ぼくは動的プロクシをダックタイピングの代表だと思っています。
# 簡単に説明すると、動的プロクシというのは、要はすべてのメッセージを別のオブジェクトに転送する事によって、そのオブジェクトがあたかもそのオブジェクトであるかのように偽装するオブジェクトです。
# 転送の前後に、別の処理をはさむことで、もともともオブジェクトの動作をまったく変えずに、処理を変えたりできます。
class OriginObject
def hello!
"hello, this is #{self.class}"
end
end
class DynamicProxy < BasicObject
# BasicObjectはObjectを継承しない、非常に限られたメソッドしか持たない事を保証された、動的プロクシのためのオブジェクトです。
# 具体的には、Objectが
# :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize .. :__send__ など大量のメソッドを持つのに対し、
# BasicObject は
# :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__
# しかメソッドを持ちません。
#
# 動的プロクシは通常、できるだけ多くのメソッドを別オブジェクトに転送したいので、BasicObjectを継承します。
#
# もし、これだけでなく、BasicObjectが持つメソッドですら別のオブジェクトに転送したいならば、
# 全メソッドを
# private *instance_methods
# などで隠す必要があります。
# ============================================================
def initialize entity
@entity = entity
end
# method_missingは、存在しないメソッドまたはプライベートなメソッドが
# 呼び出された場合に、そのメソッドの呼び出しに使用された名前、引数を
# 代わりに渡され呼び出されるメソッドです。
def method_missing funcname, *args, &blk
@entity.send(funcname, *args, &blk).tap do |result|
$stdout.puts "logging to: #{funcname}(#{args.join ', '}) # => #{result}"
end
end
end
origin = OriginObject.new
puts origin.hello!
# hello, this is OriginObject
proxy = DynamicProxy.new origin
puts proxy.hello!
# logging to: hello!() # => hello, this is OriginObject
# hello, this is OriginObject
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment