From 48653d5ef0ed47469d64170d70c8c2a9f21f159e Mon Sep 17 00:00:00 2001 From: matz Date: Mon, 5 Sep 2005 08:29:52 +0000 Subject: * lib/ostruct.rb: a patch from Florian Gross merged to allow recursive inspect (and to_s) for OpenStruct. [ruby-core:05532] * lib/observer.rb: a patch from nornagon merged to allow arbitrary names for update methods. [ruby-core:05416] * eval.c (rb_f_fcall): new method to avoid inefficiency of obj.instance_eval{send(...)} tricks. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9081 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/find.rb | 3 +-- lib/monitor.rb | 12 ++++++------ lib/observer.rb | 19 ++++++++++--------- lib/ostruct.rb | 41 ++++++++++++++++++++++++++++++----------- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/lib/find.rb b/lib/find.rb index 52efde81fd..08a3908c5b 100644 --- a/lib/find.rb +++ b/lib/find.rb @@ -33,10 +33,9 @@ module Find # See the +Find+ module documentation for an example. # def find(*paths) # :yield: path - paths.collect!{|d| d.dup} + paths.collect!{|d| open(d){}; d.dup} while file = paths.shift catch(:prune) do - next unless File.exist? file yield file.dup.taint begin if File.lstat(file).directory? then diff --git a/lib/monitor.rb b/lib/monitor.rb index 6bd14d0789..c1ce7815ea 100644 --- a/lib/monitor.rb +++ b/lib/monitor.rb @@ -87,11 +87,11 @@ module MonitorMixin class Timeout < Exception; end def wait(timeout = nil) - @monitor.instance_eval {mon_check_owner()} + @monitor.fcall(:mon_check_owner) timer = create_timer(timeout) Thread.critical = true - count = @monitor.instance_eval {mon_exit_for_cond()} + count = @monitor.fcall(:mon_exit_for_cond) @waiters.push(Thread.current) begin @@ -107,7 +107,7 @@ module MonitorMixin if @waiters.include?(Thread.current) # interrupted? @waiters.delete(Thread.current) end - @monitor.instance_eval {mon_enter_for_cond(count)} + @monitor.fcall(:mon_enter_for_cond, count) Thread.critical = false end end @@ -125,7 +125,7 @@ module MonitorMixin end def signal - @monitor.instance_eval {mon_check_owner()} + @monitor.fcall(:mon_check_owner) Thread.critical = true t = @waiters.shift t.wakeup if t @@ -134,7 +134,7 @@ module MonitorMixin end def broadcast - @monitor.instance_eval {mon_check_owner()} + @monitor.fcall(:mon_check_owner) Thread.critical = true for t in @waiters t.wakeup @@ -172,7 +172,7 @@ module MonitorMixin def self.extend_object(obj) super(obj) - obj.instance_eval {mon_initialize()} + obj.fcall(:mon_initialize) end # diff --git a/lib/observer.rb b/lib/observer.rb index 64c7d81351..472a154395 100644 --- a/lib/observer.rb +++ b/lib/observer.rb @@ -118,14 +118,15 @@ module Observable # # Add +observer+ as an observer on this object. +observer+ will now receive - # notifications. + # notifications. The second optional argument specifies a method to notify + # updates, of which default value is +update+. # - def add_observer(observer) - @observer_peers = [] unless defined? @observer_peers - unless observer.respond_to? :update - raise NoMethodError, "observer needs to respond to `update'" + def add_observer(observer, func=:update) + @observer_peers = {} unless defined? @observer_peers + unless observer.respond_to? func + raise NoMethodError, "observer does not respond to `#{func.to_s}'" end - @observer_peers.push observer + @observer_peers[observer] = func end # @@ -181,9 +182,9 @@ module Observable def notify_observers(*arg) if defined? @observer_state and @observer_state if defined? @observer_peers - for i in @observer_peers.dup - i.update(*arg) - end + @observer_peers.each { |k, v| + k.send v, *arg + } end @observer_state = false end diff --git a/lib/ostruct.rb b/lib/ostruct.rb index b30ae640c5..6af5bbdac0 100644 --- a/lib/ostruct.rb +++ b/lib/ostruct.rb @@ -47,7 +47,7 @@ class OpenStruct @table = {} if hash for k,v in hash - @table[k.to_sym] = v + @table[k.to_sym] = v new_ostruct_member(k) end end @@ -68,11 +68,11 @@ class OpenStruct end def new_ostruct_member(name) + name = name.to_sym unless self.respond_to?(name) - self.instance_eval %{ - def #{name}; @table[:#{name}]; end - def #{name}=(x); @table[:#{name}] = x; end - } + meta = class << self; self; end + meta.send(:define_method, name) { @table[name] } + meta.send(:define_method, :"#{name}=") { |x| @table[name] = x } end end @@ -81,14 +81,14 @@ class OpenStruct len = args.length if mname =~ /=$/ if len != 1 - raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) + raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) end if self.frozen? - raise TypeError, "can't modify frozen #{self.class}", caller(1) + raise TypeError, "can't modify frozen #{self.class}", caller(1) end mname.chop! - @table[mname.intern] = args[0] self.new_ostruct_member(mname) + @table[mname.intern] = args[0] elsif len == 0 @table[mid] else @@ -103,16 +103,35 @@ class OpenStruct @table.delete name.to_sym end + InspectKey = :__inspect_key__ # :nodoc: + # # Returns a string containing a detailed summary of the keys and values. # def inspect - str = "<#{self.class}" - for k,v in @table - str << " #{k}=#{v.inspect}" + str = "#<#{self.class}" + + Thread.current[InspectKey] ||= [] + if Thread.current[InspectKey].include?(self) then + str << " ..." + else + first = true + for k,v in @table + str << "," unless first + first = false + + Thread.current[InspectKey] << v + begin + str << " #{k}=#{v.inspect}" + ensure + Thread.current[InspectKey].pop + end + end end + str << ">" end + alias :to_s :inspect attr_reader :table # :nodoc: protected :table -- cgit v1.2.3