module TeamUtil # Get all matching method names out of definition. # A definition is a # * simple string # * regular expression # * array of strings or regular expressions # * symbol # _[String|Regexp|Array|Symbol]*_ def get_all_method_names(baseclass, definition) #return value result = nil if (definition.instance_of?(Array)) #array of definitions? => concat all subsets result = Array.new #list of methods given definition.each { |methoddef| result.concat(get_all_method_names(baseclass, methoddef)) } elsif (definition.instance_of?(String)) #simple string? => result = get_method_names(baseclass, /^#{Regexp.escape(definition)}$/) elsif (definition.instance_of?(Regexp)) result = get_method_names(baseclass, definition) elsif (definition.instance_of?(Symbol)) result = get_method_names(baseclass, /^#{Regexp.escape(definition.id2name)}$/) else raise ObjectTeam::TeamException, "How to handle type >#{definition.class.name}< in #{baseclass.name} callin source?", caller end return result end # Get all matching method names out of definition. # A definition is a string or a regexp. def get_method_names(baseclass, methodfilter) result = Hash.new #methodfilter = /^#{methodfilter}$/ delegatefilter = /^#{Interceptor::PREFIX}/ #use all methodnames defined by the class and by callin-bindings while (baseclass!=Object) #baseclass.public_instance_methods(false).concat(baseclass.callins.keys).each { |m| baseclass.public_instance_methods(false).each { |m| if (!delegatefilter.match(m) and methodfilter.match(m)) result[m] = true end } baseclass = baseclass.superclass end #check for ctor #result["initialize"]=true if (methodfilter.match("initialize")) return result.keys end end class WeakReferenceError < StandardError end class WeakReference # the object id of the reference attr :oid # Construct a weak ref: reference by id not by pointer def initialize(obj) @oid = obj.__id__ ObjectSpace.define_finalizer(obj, @@final) OIDS[@oid] = true end # Indicates, if this reference is alive. def alive? return OIDS[@oid] end # Get reference by pointer. def ref if alive? return ObjectSpace._id2ref(@oid) else raise WeakReferenceError, "Already recycled Object" end end # Static map of all weak reference. # GC will remove the relation. OIDS = {} @@final = lambda{ |id| old_status = Thread.critical Thread.critical = true begin OIDS.delete(id) ensure Thread.critical = old_status end } end # This class is an ordinary hash where no direct references are hold to the key. # An entry in a WeakHash will automatically be removed when its key is no # longer in ordinary use and finalized by the garbage collector. class WeakHash # encapsulate a real hash attr :hash # Create a new Weak hash. def initialize() @hash = {} # GC will remove the relation. @final = lambda{ |id| old_status = Thread.critical Thread.critical = true begin self.hash.delete(id) ensure Thread.critical = old_status end } end #Return len of hash. def length @hash.length end alias_method(:size, :length) # Iterate over all valid key, value pairs. # [block] the block to execute def each(&block) @hash.each{ |key, val| block.call(ObjectSpace._id2ref(key), val) } end # Get value of the given key # [key] the key to lookup for a value # [return] the stored value or nil, if not found. def fetch(key) @hash[key.__id__] end alias_method(:[], :fetch) # Store a key => value pair. # This hash do not hold a direct reference to the key. # The pair gets lost, if the key gets finalized. # [key] the key to lookup the stored value # [value] the value to store def store(key, value) ObjectSpace.define_finalizer(key, @final) @hash.store(key.__id__, value) end alias_method(:[]=, :store) # Implement equality operator. def ==(other) if (other.instance_of?(WeakHash)) return (@hash == other.hash) else return (@hash == other) end end end if (__FILE__ == $0) def test(whash) whash.each { |key, val| puts "Have key #{key} => #{val}" } end weakhash = WeakHash.new #create some keys key1 = "One Test" key2 = "Another Test" key3 = "The ultimate Test" #fill hash weakhash[key1] = "check" weakhash[key2] = "check" weakhash[key3] = "check" #first check => behave as usual hash ObjectSpace.garbage_collect print "\n\nthree items should be visible:\n" test(weakhash) #second check => perhaps three items should be visible key1 = nil key2 = nil key3 = nil print "\n\n__perhaps__! three items could be visible (with respect to GC):\n" test(weakhash) #third check => no item should be visible! ObjectSpace.garbage_collect print "\n\nall items should be finalized!\n" test(weakhash) end