summaryrefslogtreecommitdiff
path: root/lib/delegate.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/delegate.rb')
-rw-r--r--lib/delegate.rb100
1 files changed, 91 insertions, 9 deletions
diff --git a/lib/delegate.rb b/lib/delegate.rb
index e5943cead8..0771f2feeb 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -1,26 +1,51 @@
# Delegation class that delegates even methods defined in super class,
# which can not be covered with normal method_missing hack.
#
-# Delegater is the abstract delegation class. Need to redefine
-# `__getobj__' method in the subclass. SimpleDelegater is the
+# Delegator is the abstract delegation class. Need to redefine
+# `__getobj__' method in the subclass. SimpleDelegator is the
# concrete subclass for simple delegation.
#
# Usage:
# foo = Object.new
-# foo = SimpleDelegater.new(foo)
-# foo.type # => Object
+# foo2 = SimpleDelegator.new(foo)
+# foo.hash == foo2.hash # => true
+#
+# Foo = DelegateClass(Array)
+#
+# class ExtArray<DelegateClass(Array)
+# ...
+# end
-class Delegater
+class Delegator
def initialize(obj)
- preserved = ["id", "equal?", "__getobj__"]
+ preserved = ::Kernel.instance_methods
+ preserved -= ["to_s","to_a","inspect","==","=~","==="]
for t in self.type.ancestors
preserved |= t.instance_methods
- break if t == Delegater
+ preserved |= t.private_instance_methods
+ preserved |= t.protected_instance_methods
+ break if t == Delegator
end
for method in obj.methods
next if preserved.include? method
- eval "def self.#{method}(*args); __getobj__.send :#{method}, *args; end"
+ eval <<-EOS
+ def self.#{method}(*args, &block)
+ begin
+ __getobj__.__send__(:#{method}, *args, &block)
+ rescue Exception
+ c = -caller(0).size
+ if /:in `__getobj__'$/ =~ $@[c-1] #`
+ n = 1
+ else
+ c -= 1
+ n = 2
+ end
+ $@[c,n] = nil
+ raise
+ end
+ end
+ EOS
end
end
@@ -30,7 +55,7 @@ class Delegater
end
-class SimpleDelegater<Delegater
+class SimpleDelegator<Delegator
def initialize(obj)
super
@@ -41,4 +66,61 @@ class SimpleDelegater<Delegater
@obj
end
+ def __setobj__(obj)
+ @obj = obj
+ end
+end
+
+# backward compatibility ^_^;;;
+Delegater = Delegator
+SimpleDelegater = SimpleDelegator
+
+#
+def DelegateClass(superclass)
+ klass = Class.new
+ methods = superclass.instance_methods
+ methods -= ::Kernel.instance_methods
+ methods |= ["to_s","to_a","inspect","==","=~","==="]
+ klass.module_eval <<-EOS
+ def initialize(obj)
+ @obj = obj
+ end
+ EOS
+ for method in methods
+ klass.module_eval <<-EOS
+ def #{method}(*args, &block)
+ begin
+ @obj.__send__(:#{method}, *args, &block)
+ rescue
+ $@[0,2] = nil
+ raise
+ end
+ end
+ EOS
+ end
+ return klass;
+ end
+
+if __FILE__ == $0
+ class ExtArray<DelegateClass(Array)
+ def initialize()
+ super([])
+ end
+ end
+
+ ary = ExtArray.new
+ p ary.type
+ ary.push 25
+ p ary
+
+ foo = Object.new
+ def foo.test
+ 25
+ end
+ def foo.error
+ raise 'this is OK'
+ end
+ foo2 = SimpleDelegator.new(foo)
+ p foo.test == foo2.test # => true
+ foo2.error # raise error!
end