mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
1057902ac7
rb_io_fread() by freezing it temporarily. [ruby-dev:24479] * dir.c (rb_push_glob): block call at once the end of method. [ruby-dev:24487] * ext/enumerator/enumerator.c (enum_each_slice): remove rb_gc_force_recycle() to prevent potential SEGV. [ruby-dev:24499] * ext/zlib/zlib.c (zstream_expand_buffer): hide internal string buffer by clearing klass. [ruby-dev:24510] * ext/socket/socket.c (sock_s_getservbyaname): protocol string might be altered. [ruby-dev:24503] * string.c (rb_str_upto): check if return value from succ is a string. [ruby-dev:24504] * io.c (rb_io_popen): get mode string via rb_io_flags_mode() to avoid mode string modification. [ruby-dev:24454] * io.c (rb_io_getline_fast): should take delim as unsigned char to distinguish EOF and '\377'. [ruby-dev:24460] * io.c (rb_io_getline): add check for RS modification. [ruby-dev:24461] * enum.c (enum_sort_by): use qsort() directly instead using rb_iterate(). [ruby-dev:24462] * enum.c (enum_each_with_index): remove rb_gc_force_recycle() to prevent access to recycled object (via continuation for example). [ruby-dev:24463] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7071 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
157 lines
3.3 KiB
Ruby
157 lines
3.3 KiB
Ruby
# Delegation class that delegates even methods defined in super class,
|
|
# which can not be covered with normal method_missing hack.
|
|
#
|
|
# 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
|
|
# foo2 = SimpleDelegator.new(foo)
|
|
# foo.hash == foo2.hash # => false
|
|
#
|
|
# Foo = DelegateClass(Array)
|
|
#
|
|
# class ExtArray<DelegateClass(Array)
|
|
# ...
|
|
# end
|
|
|
|
class Delegator
|
|
|
|
def initialize(obj)
|
|
preserved = ::Kernel.public_instance_methods(false)
|
|
preserved -= ["to_s","to_a","inspect","==","=~","==="]
|
|
for t in self.class.ancestors
|
|
preserved |= t.public_instance_methods(false)
|
|
preserved |= t.private_instance_methods(false)
|
|
preserved |= t.protected_instance_methods(false)
|
|
break if t == Delegator
|
|
end
|
|
preserved << "singleton_method_added"
|
|
for method in obj.methods
|
|
next if preserved.include? method
|
|
begin
|
|
eval <<-EOS
|
|
def self.#{method}(*args, &block)
|
|
begin
|
|
__getobj__.__send__(:#{method}, *args, &block)
|
|
rescue Exception
|
|
$@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
|
|
$@.delete_if{|s| /^\\(eval\\):/ =~ s}
|
|
::Kernel::raise
|
|
end
|
|
end
|
|
EOS
|
|
rescue SyntaxError
|
|
raise NameError, "invalid identifier %s" % method, caller(4)
|
|
end
|
|
end
|
|
end
|
|
alias initialize_methods initialize
|
|
|
|
def __getobj__
|
|
raise NotImplementedError, "need to define `__getobj__'"
|
|
end
|
|
|
|
def marshal_dump
|
|
__getobj__
|
|
end
|
|
def marshal_load(obj)
|
|
initialize_methods(obj)
|
|
end
|
|
end
|
|
|
|
class SimpleDelegator<Delegator
|
|
|
|
def initialize(obj)
|
|
super
|
|
@_sd_obj = obj
|
|
end
|
|
|
|
def __getobj__
|
|
@_sd_obj
|
|
end
|
|
|
|
def __setobj__(obj)
|
|
@_sd_obj = obj
|
|
end
|
|
|
|
def initialize_copy(obj)
|
|
super
|
|
__setobj__(obj.__getobj__.clone)
|
|
end
|
|
end
|
|
|
|
# backward compatibility ^_^;;;
|
|
Delegater = Delegator
|
|
SimpleDelegater = SimpleDelegator
|
|
|
|
#
|
|
def DelegateClass(superclass)
|
|
klass = Class.new
|
|
methods = superclass.public_instance_methods(true)
|
|
methods -= ::Kernel.public_instance_methods(false)
|
|
methods |= ["to_s","to_a","inspect","==","=~","==="]
|
|
klass.module_eval {
|
|
def initialize(obj)
|
|
@_dc_obj = obj
|
|
end
|
|
def method_missing(m, *args)
|
|
unless @_dc_obj.respond_to?(m)
|
|
super(m, *args)
|
|
end
|
|
@_dc_obj.__send__(m, *args)
|
|
end
|
|
def __getobj__
|
|
@_dc_obj
|
|
end
|
|
def __setobj__(obj)
|
|
@_dc_obj = obj
|
|
end
|
|
def initialize_copy(obj)
|
|
super
|
|
__setobj__(obj.__getobj__.clone)
|
|
end
|
|
}
|
|
for method in methods
|
|
begin
|
|
klass.module_eval <<-EOS, __FILE__, __LINE__+1
|
|
def #{method}(*args, &block)
|
|
begin
|
|
@_dc_obj.__send__(:#{method}, *args, &block)
|
|
rescue
|
|
$@[0,2] = nil
|
|
raise
|
|
end
|
|
end
|
|
EOS
|
|
rescue SyntaxError
|
|
raise NameError, "invalid identifier %s" % method, caller(3)
|
|
end
|
|
end
|
|
return klass
|
|
end
|
|
|
|
if __FILE__ == $0
|
|
class ExtArray<DelegateClass(Array)
|
|
def initialize()
|
|
super([])
|
|
end
|
|
end
|
|
|
|
ary = ExtArray.new
|
|
p ary.class
|
|
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
|