Skip to content
Browse files

added subscriptions module

  • Loading branch information...
1 parent c4aff56 commit 0e00f5c2e98b5311004033e0481ea19f26b0a5da @oleganza committed Sep 25, 2008
Showing with 113 additions and 0 deletions.
  1. +1 −0 lib/emrpc/evented_api.rb
  2. +56 −0 lib/emrpc/evented_api/subscriptions.rb
  3. +56 −0 spec/evented_api/subscriptions_spec.rb
View
1 lib/emrpc/evented_api.rb
@@ -11,3 +11,4 @@
require 'emrpc/evented_api/timer'
require 'emrpc/evented_api/evented_wrapper'
require 'emrpc/evented_api/reconnecting_pid'
+require 'emrpc/evented_api/subscriptions'
View
56 lib/emrpc/evented_api/subscriptions.rb
@@ -0,0 +1,56 @@
+module EMRPC
+ # Enables subscribing and unsubscribing using
+ # * #subscribe(:event_name, rcvr, :callback)
+ # * #unsubscribe(:event_name, rcvr[, :callback]) (if no callback is defined, all callbacks for the current pid are removed)
+ # * #notify_subscribers(:event_name)
+ #
+ module Subscriptions
+ def initialize(*args, &blk)
+ super(*args, &blk)
+ @subscriptions = Hash.new # event_name -> array of [pid, callback]
+ end
+
+ # Subscribes +pid+ to event +event_name+ with callback +callback_name+
+ #
+ def subscribe(event_name, pid, callback_name)
+ @subscriptions[event_name] ||= Array.new
+ @subscriptions[event_name] << [pid, callback_name]
+ self
+ end
+
+ # Depending on the arguments passed:
+ # * unsubscribe(:event, pid, :on_event) -> unsubscribes the callback for the specified pid and event
+ # * unsubscribe(:event, pid) -> unsubscribes all callbacks for the pid and the event
+ # * unsubscribe(:event) -> unsubscribes all pids and callbacks for the event
+ # * unsubscribe -> unsubscribes all pids and callbacks for all events
+ # * unsubscribe(:all, pid) -> unsubscribes pid from all events
+ # * unsubscribe(:all, pid, :on_event) -> unsubscribes pid's :on_event callback from all events
+ #
+ def unsubscribe(event_name = nil, pid = nil, callback_name = nil)
+ if !event_name || event_name == :all
+ @subscriptions.each do |event, subscriptions|
+ unsubscribe(event, pid, callback_name)
+ end
+ else
+ subscriptions = @subscriptions[event_name] or return
+ subscriptions.delete_if do |pair|
+ pd, cb = pair
+ (pd == pid || !pid) && (cb == callback_name || !callback_name)
+ end
+ end
+ self
+ end
+
+ # Sends callback messages to all subscribed pids.
+ # If event is not registered, returns 0.
+ # Otherwise returns number of notifications.
+ def notify_subscribers(event_name, *args, &blk)
+ subscriptions = @subscriptions[event_name] or return 0
+ subscriptions.each do |(pid, cbk)|
+ pid.send(cbk, *args, &blk)
+ end
+ subscriptions.size
+ end
+
+ end # Subscriptions
+end # EMRPC
View
56 spec/evented_api/subscriptions_spec.rb
@@ -0,0 +1,56 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe Subscriptions do
+ extend MockDescribe
+
+ before(:all) do
+ @cls = Class.new { include Subscriptions }
+ @cafe = @cls.new
+ end
+
+ def client_mock(name)
+ m = mock(name)
+ m.stub!(:send)
+ m
+ end
+
+ mock_describe "subscribed client" do
+ oleg = client_mock("Oleg in cafe")
+ oleg.should_receive(:send).once.with(:on_open, :arg).ordered
+ oleg.should_receive(:send).once.with(:on_close).ordered
+ andrey = client_mock("Andrey in cafe")
+ andrey.should_receive(:send).once.with(:on_close).ordered
+
+ @cafe.subscribe(:open, oleg, :on_open)
+ @cafe.subscribe(:close, oleg, :on_close)
+ @cafe.subscribe(:close, andrey, :on_close)
+
+ @cafe.notify_subscribers(:open, :arg)
+ @cafe.notify_subscribers(:close)
+ end
+
+ mock_describe "unsubscribed client from event" do
+ oleg = client_mock("Oleg in cafe")
+ oleg.should_not_receive(:send).with(:on_open, :arg)
+ oleg.should_receive(:send).with(:on_close).ordered
+ andrey = client_mock("Andrey in cafe")
+ andrey.should_receive(:send).with(:on_close).ordered
+
+ @cafe.subscribe(:open, oleg, :on_open)
+ @cafe.subscribe(:close, oleg, :on_close)
+ @cafe.subscribe(:close, andrey, :on_close)
+
+ @cafe.unsubscribe(:open, oleg)
+
+ @cafe.notify_subscribers(:open, :arg)
+ @cafe.notify_subscribers(:close)
+ end
+
+
+ %{
+
+ TODO: more scenarios with special DSL
+
+
+ }
+end

0 comments on commit 0e00f5c

Please sign in to comment.
Something went wrong with that request. Please try again.