Thursday, May 23, 2013

Experimenting Rails Notification Module

Rails ActiveSupport::Notification module offers a mechanism to launch certain behavior when certain events occur. A common instance is to send an email to user after they finished signing up. Here we will do something much easier to show you how Notification module works. The basic idea is we'll simulate a man (which we will call it mess maker) pouring water into a pitcher. Each time he will pour certain amount of water into the pitcher, and when the pitcher can no longer hold any more water, a warning is fired telling him that the water is overflowing.

So first of all, we need to create a Pitcher class and a MessMaker class.
class Pitcher
  attr_accessor :content

  VOLUME = 100

  def initialize
   @content = 0
  end

  def check_overflow(name)
   ActiveSupport::Notifications.instrument("overflow", :name => name) if content > VOLUME  end
end

class MessMaker
  attr_accessor :name

  def pour_water(pitcher, amount)
   pitcher.content += amount
   pitcher.check_overflow(name)
  end

  ActiveSupport::Notifications.subscribe("overflow") do |name, start, finsih, id, payload|     puts 'Hey, ' + payload[:name].to_s + '. Stop pouring water!'
  end
end

As we can see, each Pitcher instance has a instance variable called content which is initialized to be 0 and recalculated as the mess maker pours more water into it. When the content reaches the VOLUME, an event called "overflow" is instrumented.  Right after "overflow" event is instrumented, the block in the Notification.subscribe gets executed, asking the mess maker to stop pouring more water. Note that subscribing code is not necessarily under the MessMaker class, you can put it wherever that makes sense as long as that chunk of code is loaded when you launch the application.

Now let's do some experiments in rails console
1.9.3-p392 :001 > mm = MessMaker.new
 => # 
1.9.3-p392 :002 > mm.name = 'david'
 => "david" 
1.9.3-p392 :003 > p = Pitcher.new
 => # 
1.9.3-p392 :004 > mm.pour_water(p, 30)
 => nil 
1.9.3-p392 :005 > p.content
 => 30 
1.9.3-p392 :006 > mm.pour_water(p, 30)
 => nil 
1.9.3-p392 :007 > p.content
 => 60 
1.9.3-p392 :008 > mm.pour_water(p, 30)
 => nil 
1.9.3-p392 :009 > mm.pour_water(p, 30)
Hey, david. Stop pouring water!
 => nil 




No comments:

Post a Comment