lib/rubysl/observer/observer.rb in rubysl-observer-1.0.0 vs lib/rubysl/observer/observer.rb in rubysl-observer-2.0.0

- old
+ new

@@ -1,35 +1,36 @@ # -# observer.rb implements the _Observer_ object-oriented design pattern. The +# Implementation of the _Observer_ object-oriented design pattern. The # following documentation is copied, with modifications, from "Programming -# Ruby", by Hunt and Thomas; http://www.rubycentral.com/book/lib_patterns.html. +# Ruby", by Hunt and Thomas; http://www.ruby-doc.org/docs/ProgrammingRuby/html/lib_patterns.html. # -# == About -# -# The Observer pattern, also known as Publish/Subscribe, provides a simple +# See Observable for more info. + +# The Observer pattern (also known as publish/subscribe) provides a simple # mechanism for one object to inform a set of interested third-party objects # when its state changes. # # == Mechanism # -# In the Ruby implementation, the notifying class mixes in the +Observable+ +# The notifying class mixes in the +Observable+ # module, which provides the methods for managing the associated observer # objects. # -# The observers must implement the +update+ method to receive notifications. +# The observers must implement a method called +update+ to receive +# notifications. # # The observable object must: -# * assert that it has +changed+ -# * call +notify_observers+ +# * assert that it has +#changed+ +# * call +#notify_observers+ # -# == Example +# === Example # # The following example demonstrates this nicely. A +Ticker+, when run, -# continually receives the stock +Price+ for its +@symbol+. A +Warner+ is a -# general observer of the price, and two warners are demonstrated, a +WarnLow+ -# and a +WarnHigh+, which print a warning if the price is below or above their -# set limits, respectively. +# continually receives the stock +Price+ for its <tt>@symbol</tt>. A +Warner+ +# is a general observer of the price, and two warners are demonstrated, a +# +WarnLow+ and a +WarnHigh+, which print a warning if the price is below or +# above their set limits, respectively. # # The +update+ callback allows the warners to run without being explicitly # called. The system is set up with the +Ticker+ and several observers, and the # observers do their duty without the top-level code having to interfere. # @@ -106,40 +107,43 @@ # +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134 # Current price: 134 # Current price: 112 # Current price: 79 # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79 - - -# -# Implements the Observable design pattern as a mixin so that other objects can -# be notified of changes in state. See observer.rb for details and an example. -# module Observable # - # Add +observer+ as an observer on this object. +observer+ will now receive + # Add +observer+ as an observer on this object. so that it will receive # notifications. # - def add_observer(observer) - @observer_peers = [] unless defined? @observer_peers - unless observer.respond_to? :update - raise NoMethodError, "observer needs to respond to `update'" + # +observer+:: the object that will be notified of changes. + # +func+:: Symbol naming the method that will be called when this Observable + # has changes. + # + # This method must return true for +observer.respond_to?+ and will + # receive <tt>*arg</tt> when #notify_observers is called, where + # <tt>*arg</tt> is the value passed to #notify_observers by this + # Observable + 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 # - # Delete +observer+ as an observer on this object. It will no longer receive - # notifications. + # Remove +observer+ as an observer on this object so that it will no longer + # receive notifications. # + # +observer+:: An observer of this Observable def delete_observer(observer) @observer_peers.delete observer if defined? @observer_peers end # - # Delete all observers associated with this object. + # Remove all observers associated with this object. # def delete_observers @observer_peers.clear if defined? @observer_peers end @@ -156,34 +160,40 @@ # # Set the changed state of this object. Notifications will be sent only if # the changed +state+ is +true+. # + # +state+:: Boolean indicating the changed state of this Observable. + # def changed(state=true) @observer_state = state end # - # Query the changed state of this object. + # Returns true if this object's state has been changed since the last + # #notify_observers call. # def changed? if defined? @observer_state and @observer_state true else false end end # - # If this object's changed state is +true+, invoke the update method in each - # currently associated observer in turn, passing it the given arguments. The - # changed state is then set to +false+. + # Notify observers of a change in state *if* this object's changed state is + # +true+. # + # This will invoke the method named in #add_observer, passing <tt>*arg</tt>. + # The changed state is then set to +false+. + # + # <tt>*arg</tt>:: Any arguments to pass to the observers. def notify_observers(*arg) if defined? @observer_state and @observer_state if defined? @observer_peers - @observer_peers.dup.each do |i| - i.update(*arg) + @observer_peers.each do |k, v| + k.send v, *arg end end @observer_state = false end end