U:RDoc::NormalModule[iI"Observable:EF@0o:RDoc::Markup::Document: @parts[o;;[o:RDoc::Markup::Paragraph;[I"NThe Observer pattern (also known as publish/subscribe) provides a simple ;TI"Pmechanism for one object to inform a set of interested third-party objects ;TI"when its state changes.;To:RDoc::Markup::BlankLineS:RDoc::Markup::Heading: leveli: textI"Mechanism;T@o; ;[I"3The notifying class mixes in the +Observable+ ;TI"Mmodule, which provides the methods for managing the associated observer ;TI" objects.;T@o; ;[I" The observable object must:;To:RDoc::Markup::List: @type: BULLET: @items[o:RDoc::Markup::ListItem: @label0;[o; ;[I""assert that it has +#changed+;To;;0;[o; ;[I"call +#notify_observers+;T@o; ;[I"QAn observer subscribes to updates using Observable#add_observer, which also ;TI"Ospecifies the method called via #notify_observers. The default method for ;TI""#notify_observers is #update.;T@S; ; i; I" Example;T@o; ;[ I"LThe following example demonstrates this nicely. A +Ticker+, when run, ;TI"Rcontinually receives the stock +Price+ for its @symbol. A +Warner+ ;TI"Mis a general observer of the price, and two warners are demonstrated, a ;TI"P+WarnLow+ and a +WarnHigh+, which print a warning if the price is below or ;TI"*above their set limits, respectively.;T@o; ;[I"NThe +update+ callback allows the warners to run without being explicitly ;TI"Tcalled. The system is set up with the +Ticker+ and several observers, and the ;TI"Lobservers do their duty without the top-level code having to interfere.;T@o; ;[ I"MNote that the contract between publisher and subscriber (observable and ;TI"Qobserver) is not declared or enforced. The +Ticker+ publishes a time and a ;TI"Mprice, and the warners receive that. But if you don't ensure that your ;TI"6contracts are correct, nothing else can warn you.;T@o:RDoc::Markup::Verbatim;[>I"require "observer" ;TI" ;TI"Aclass Ticker ### Periodically fetch a stock price. ;TI" include Observable ;TI" ;TI" def initialize(symbol) ;TI" @symbol = symbol ;TI" end ;TI" ;TI" def run ;TI" last_price = nil ;TI" loop do ;TI"( price = Price.fetch(@symbol) ;TI"- print "Current price: #{price}\n" ;TI"" if price != last_price ;TI"8 changed # notify observers ;TI" last_price = price ;TI"/ notify_observers(Time.now, price) ;TI" end ;TI" sleep 1 ;TI" end ;TI" end ;TI" end ;TI" ;TI"Oclass Price ### A mock class to fetch a stock price (60 - 140). ;TI" def self.fetch(symbol) ;TI" 60 + rand(80) ;TI" end ;TI" end ;TI" ;TI"Gclass Warner ### An abstract observer of Ticker objects. ;TI"% def initialize(ticker, limit) ;TI" @limit = limit ;TI"# ticker.add_observer(self) ;TI" end ;TI" end ;TI" ;TI"class WarnLow < Warner ;TI"= def update(time, price) # callback for observer ;TI" if price < @limit ;TI"E print "--- #{time.to_s}: Price below #@limit: #{price}\n" ;TI" end ;TI" end ;TI" end ;TI" ;TI"class WarnHigh < Warner ;TI"= def update(time, price) # callback for observer ;TI" if price > @limit ;TI"E print "+++ #{time.to_s}: Price above #@limit: #{price}\n" ;TI" end ;TI" end ;TI" end ;TI" ;TI"!ticker = Ticker.new("MSFT") ;TI"WarnLow.new(ticker, 80) ;TI"WarnHigh.new(ticker, 120) ;TI"ticker.run ;T: @format0o; ;[I"Produces:;T@o;;[I"Current price: 83 ;TI"Current price: 75 ;TI":--- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75 ;TI"Current price: 90 ;TI"Current price: 134 ;TI"<+++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134 ;TI"Current price: 134 ;TI"Current price: 112 ;TI"Current price: 79 ;TI"9--- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79;T;0: @fileI"lib/observer.rb;T:0@omit_headings_from_table_of_contents_below0;0;0[[[[[I" class;T[[: public[[:protected[[: private[[I" instance;T[[;[ [I"add_observer;FI"lib/observer.rb;T[I" changed;F@›[I" changed?;F@›[I"count_observers;F@›[I"delete_observer;F@›[I"delete_observers;F@›[I"notify_observers;F@›[;[[;[[[U:RDoc::Context::Section[i0o;;[;0;0[@†@†cRDoc::TopLevel