Observers in the Wild
The Observer pattern is not hard to find in the Ruby code base. It is, for example, used by ActiveRecord. ActiveRecord clients that want to stay informed of the goings on as database records are created, read, written, and deleted can define observers that look like this:4
class EmployeeObserver < ActiveRecord::Observer def after_create(employee) # New employee record created end def after_update(employee) # Employee record updated end def after_destroy(employee) # Employee record deleted end end
In a nice example of the Convention Over Configuration pattern (see Chapter 18), ActiveRecord does not require you to register your observer: It just figures out that EmployeeObserver is there to observe Employees, based on the class name.
You can find an example of the code block-based observer in REXML, the XML parsing package that ships as part of the standard Ruby library. The REXML SAX2Parser class is a streaming XML parser: It will read an XML file and you are welcome to add observers that will be informed when specific XML constructs get read. While SAX2Parser supports the more formal, separate object observer style, you can also pass in code blocks that act as your observer:
require 'rexml/parsers/sax2parser' require 'rexml/sax2listener' # # Create an XML parser for our data # xml = File.read('data.xml') parser = REXML::Parsers::SAX2Parser.new( xml ) # # Add some observers to listen for start and end elements... # parser.listen( :start_element ) do |uri, local, qname, attrs| puts("start element: #{local}") end parser.listen( :end_element ) do |uri, local, qname| puts("end element #{local}") end # # Parse the XML # parser.parse
Feed the code above an XML file, and you can sit back and observe as the elements go flying by.