From: Ethan Rowe <[email protected]>

Stubbed out the skeleton for new event classes/modules:
* Puppet::Events - global event subscriber/publisher
* Puppet::Events::Publisher - publisher base behavior

The tests should illustrate the intended behavior for these,
to be implemented in a subsequent step.
---
 lib/puppet/events.rb           |   53 +++++++++
 lib/puppet/events/publisher.rb |   44 --------
 spec/unit/events.rb            |  239 ++++++++++++++++++++++++++++++++++++++++
 spec/unit/events/publisher.rb  |  105 ------------------
 4 files changed, 292 insertions(+), 149 deletions(-)
 create mode 100644 lib/puppet/events.rb
 delete mode 100644 lib/puppet/events/publisher.rb
 create mode 100644 spec/unit/events.rb
 delete mode 100755 spec/unit/events/publisher.rb

diff --git a/lib/puppet/events.rb b/lib/puppet/events.rb
new file mode 100644
index 0000000..4d179ed
--- /dev/null
+++ b/lib/puppet/events.rb
@@ -0,0 +1,53 @@
+require 'puppet'
+
+module Puppet::Events
+    module Publisher
+        module ClassMethods
+            def private_publisher(flag = true)
+                @private_publisher = flag
+            end
+
+            def private_publisher?
+                ! ! @private_publisher
+            end
+
+            def create_subscriber_entry(subscriber, method = nil, &block)
+            end
+        end
+
+        def self.included(target_class)
+            target_class.extend ClassMethods
+        end
+
+        def subscriber_callbacks
+        end
+
+        def subscribe(subscriber, method = nil, &block)
+        end
+
+        def raise_event(event)
+        end
+
+        def unsubscribe(subscriber)
+        end
+
+        def private_publisher?
+            self.class.private_publisher?
+        end
+    end
+
+    class << self
+        include Publisher
+
+        # force this to always be private
+        def private_publisher?
+            true
+        end
+
+        def propagate_event(event, callbacks, options = {})
+        end
+
+        def notify_global_subscribers(event)
+        end
+    end
+end
diff --git a/lib/puppet/events/publisher.rb b/lib/puppet/events/publisher.rb
deleted file mode 100644
index 20ed1e3..0000000
--- a/lib/puppet/events/publisher.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require 'weakref'
-
-module Puppet
-  module Events
-    module Publisher
-      def subscribe(consumer, *method, &callback)
-        consumer = WeakRef.new(consumer)
-        subscription = [consumer]
-        if method.size > 0
-          method = method.first
-          subscription << Proc.new {|*e| consumer.__send__(method, *e)}
-        end
-
-        if block_given?
-          raise 'subscribe() cannot specify both a method and a block!' if 
subscription.size > 1
-          subscription << callback
-        end
-
-        subscriptions << subscription
-        self
-      end
-
-      def unsubscribe(consumer)
-        subscriptions.reject! do |subscription|
-          subscription[0] == consumer
-        end
-        self
-      end
-
-      def raise_event(event)
-        subscriptions.each do |subscription|
-          subscription[1].call(event) if subscription[0].weakref_alive?
-        end
-        self
-      end
-
-      def subscriptions
-        @subscriptions ||= []
-      end
-
-      private :subscriptions
-    end
-  end
-end
diff --git a/spec/unit/events.rb b/spec/unit/events.rb
new file mode 100644
index 0000000..7bd7744
--- /dev/null
+++ b/spec/unit/events.rb
@@ -0,0 +1,239 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../spec_helper.rb'
+require 'puppet/events'
+
+def silent
+    flag = $VERBOSE
+    $VERBOSE = false
+    yield
+    $VERBOSE = flag
+end
+
+describe Puppet::Events do
+    before do
+        @target = Puppet::Events
+    end
+
+    it 'should implement the Puppet::Events::Publisher interface' do
+        @target.respond_to?(:subscribe).should be_true
+        @target.respond_to?(:unsubscribe).should be_true
+        @target.respond_to?(:raise_event).should be_true
+        @target.respond_to?(:private_publisher?).should be_true
+    end
+
+    it 'should be a private publisher' do
+        @target.private_publisher?.should be_true
+    end
+
+    describe 'propagate_event' do
+        before do
+            @event = stub 'event'
+        end
+
+        it 'should raise an exception if no event is provided' do
+            lambda { @target.propagate_event }.should raise_error {|e| 
e.message ~ 'provide an event'}
+        end
+
+        it 'should pass event to each callback in sequence' do
+            listener = mock 'listener'
+            callback_seq = sequence 'callbacks'
+            listener.expects(:one).with(@event).in_sequence(callback_seq)
+            listener.expects(:two).with(@event).in_sequence(callback_seq)
+            listener.expects(:three).with(@event).in_sequence(callback_seq)
+
+            callbacks = [:one, :two, :three].collect do |sym|
+                Proc.new {|e| listener.send(sym, e)}
+            end
+
+            @target.propagate_event(@event, callbacks)
+        end
+
+        it 'should notify global subscribers by default' do
+            @target.expects(:notify_global_subscribers).with(@event)
+            @target.propagate_event @event, []
+        end
+
+        it 'should notify global subscribers if :no_global is false' do
+            @target.expects(:notify_global_subscribers).with(@event)
+            @target.propagate_event @event, [], :no_global => false
+        end
+
+        it 'should not notify global subscribers if :no_global is true' do
+            @target.expects(:notify_global_subscribers).never
+            @target.propagate_event @event, [], :no_global => true
+        end
+    end
+
+    describe 'notify_global_subscribers' do
+        it 'should invoke raise_event with the provided event' do
+            event = stub 'event'
+            @target.expects(:raise_event).with(event)
+            @target.notify_global_subscribers(event)
+        end
+    end
+end
+
+describe Puppet::Events::Publisher do
+    before :each do
+        @class = Class.new do
+            include Puppet::Events::Publisher
+        end
+
+        @publisher = @class.new
+    end
+
+    describe 'private publisher flag' do
+        it 'should be false by default' do
+            @publisher.private_publisher?.should be_false
+        end
+
+        it 'should be true if :private_publisher class method is invoked' do
+            @class.private_publisher
+            @publisher.private_publisher?.should be_true
+        end
+
+        it 'should be false if :private_publisher explicitly set at class 
level' do
+            @class.private_publisher false
+            @publisher.private_publisher?.should be_false
+        end
+    end
+
+    describe 'raise_event' do
+        before do
+            @callbacks = [:a, :b, :c]
+            @event = stub 'event'
+            @publisher.stubs(:subscriber_callbacks).returns(@callbacks)
+        end
+
+        it 'should invoke Puppet::Events.propagate_event with subscriber 
callbacks' do
+            Puppet::Events.expects(:propagate_event).with(@event, @callbacks)
+            @publisher.raise_event(@event)
+        end
+
+        it 'should provide propagate_event with :no_global flag if the 
publisher is private' do
+            @publisher.stubs(:private_publisher?).returns(true)
+            Puppet::Events.expects(:propagate_events).with(@event, @callbacks, 
{:no_global => true})
+            @publisher.raise_event(@event)
+        end
+    end
+
+    describe 'creating subscriber entry' do
+        before do
+            @subscriber = stub 'subscriber'
+        end
+
+        describe 'with a callback block' do
+            it 'should pass block through unaltered' do
+                block = Proc.new {|e| e}
+                entry = @publisher.class.create_subscriber_entry(@subscriber, 
&block)
+                entry.size.should == 2
+                entry[1].should == block
+            end
+
+            it 'should have a weak reference to the subscriber' do
+                entry = @publisher.class.create_subscriber_entry(@subscriber) 
{|e| e}
+                entry.size.should == 2
+                entry[0].should == @subscriber
+                entry[0].respond_to?(:weakref_alive?).should be_true
+            end
+        end
+
+        describe 'with a method name' do
+            it 'should create a block that invokes the method name on a weak 
ref to the subscriber' do
+                class << @subscriber
+                    attr_accessor :weakref, :last_received
+
+                    def callback(e)
+                        self.last_received = e
+                        self.weakref = self.respond_to(:weakref_alive?)
+                    end
+                end
+
+                entry = @publisher.class.create_subscriber_entry(@subscriber, 
:callback)
+                entry.size.should == 2
+                event = stub 'event'
+                entry[1].call(event)
+                @publisher.last_received.should == event
+                @publisher.weakref.should be_true
+            end
+
+            it 'should have a weak reference to the subscriber' do
+                entry = @publisher.class.create_subscriber_entry(@subscriber, 
:callback)
+                entry.size.should == 2
+                entry[0].should == @publisher
+                entry[0].respond_to(:weakref_alive?).should be_true
+            end
+        end
+    end
+
+    describe 'subscribe and unsubscribe' do
+        it 'should return publisher upon success' do
+            @consumer = Object.new
+
+            result = @publisher.subscribe(@consumer) do |event|
+                [self.object_id, event.object_id]
+            end
+            result.should == @publisher
+
+            @publisher.unsubscribe(@consumer).should == @publisher
+        end
+    end
+
+    describe 'subscribe' do
+        it 'should throw an exception if subscribe invoked with both symbol 
and block' do
+            lambda { @publisher.subscribe(Object.new, :some_method) {|x| 
x.object_id} }.should raise_error() {|error|
+                error.message.should =~ /specify both a method and a block/
+            }
+        end
+
+        it 'should get subscription entry via class.create_subscription_entry' 
do
+            sub_a = stub 'sub_a'
+            sub_b = stub 'sub_b'
+            sub_seq = sequence 'sub_seq'
+            a_block = Proc.new {|e| e}
+            @class.expects(:create_subscription_entry).with(sub_a, 
a_block).in_sequence(sub_seq)
+            @class.expects(:create_subscription_entry).with(sub_b, 
:foo).in_sequence(sub_seq)
+            @publisher.subscribe(sub_a, &a_block)
+            @publisher.subscribe(sub_b, :foo)
+        end
+
+        it 'should put subscription entry for method in subscriber_callbacks' 
do
+            subscriber = mock 'subscriber'
+            subscriber.expects(:foo)
+            @publisher.subscribe(subscriber, :foo)
+            @publisher.subscriber_callbacks.each {|cb| cb.call}
+        end
+
+        it 'should put subscription entry for block in subscriber_callbacks' do
+            subscriber = mock 'subscriber'
+            subscriber.expects(:in_block)
+            @publisher.subscribe(subscriber) { subscriber.in_block }
+            @publisher.subscriber_callbacks.each {|cb| cb.call}
+        end
+
+        it 'should put subscriber_callbacks in order of subscription' do
+            callbacks = (1..5).collect do |x|
+                p = Proc.new {|e| e}
+                @publisher.subscribe(p, &p)
+                p
+            end
+            
+            @publisher.subscriber_callbacks.should == callbacks
+        end
+
+        it 'should remove subscriber_callbacks for subscribers who 
unsubscribed' do
+            consumers = (1..3).collect {|x| Proc.new {|e| e} }
+            consumers.each {|c| @publisher.subscribe(c, &c) }
+            @publisher.unsubscribe(consumers[1])
+            @publisher.subscriber_callbacks.should == [0,2].collect {|c| 
consumers[c]}
+        end
+
+        it 'should remove subscriber_callbacks for subscribers who passed on' 
do
+            consumers = (1..3).collect {|x| Proc.new {|e| e} }
+            consumers.each {|c| @publisher.subscribe(c, &c) }
+            consumers.first.stubs(:weakref_alive?).returns(false)
+            @publisher.subscriber_callbacks.should == [1,2].collect {|c| 
consumers[c]}
+        end
+    end
+end
diff --git a/spec/unit/events/publisher.rb b/spec/unit/events/publisher.rb
deleted file mode 100755
index 1c1b974..0000000
--- a/spec/unit/events/publisher.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../spec_helper'
-require 'puppet/events/publisher'
-
-describe Puppet::Events::Publisher do
-  before :each do
-    @class = Class.new do
-      include Puppet::Events::Publisher
-    end
-
-    @publisher = @class.new
-  end
-
-  describe 'subscribe and unsubscribe' do
-    it 'should return publisher upon success' do
-        @consumer = Object.new
-
-        result = @publisher.subscribe(@consumer) do |event|
-          [self.object_id, event.object_id]
-        end
-        result.should == @publisher
-
-        @publisher.unsubscribe(@consumer).should == @publisher
-    end
-
-    it 'should throw an exception if subscribe invoked with both symbol and 
block' do
-      lambda { @publisher.subscribe(Object.new, :some_method) {|x| 
x.object_id} }.should raise_error() {|error|
-        error.message.should =~ /specify both a method and a block/
-      }
-    end
-  end
-
-  describe 'raise_event' do
-    it 'should pass event to a subscriber block when subscription performed 
with block rather than method symbol' do
-      consumer = Object.new
-      stack = []
-      @publisher.subscribe(consumer) do |event|
-        stack << [consumer.object_id, event.object_id]
-      end
-      e = Object.new
-      @publisher.raise_event(e)
-      
-      stack.size.should == 1
-      stack.first.should == [consumer.object_id, e.object_id]
-    end
-
-    it 'should pass event to subscriber method when method specified' do
-      consumer = Object.new
-      stack = []
-      class << consumer
-        attr_accessor :stack
-        def handle_event(event)
-          stack << [event, self]
-        end
-      end
-      consumer.stack = stack
-      @publisher.subscribe(consumer, :handle_event)
-      e = Object.new
-      @publisher.raise_event(e)
-      stack.size.should == 1
-      stack.first.should == [e, consumer]
-    end
-
-    it 'should broadcast in order of subscription' do
-      consumer = Object.new
-      stack = []
-      @publisher.subscribe(consumer) {|e| stack << :first}
-      @publisher.subscribe(consumer) {|e| stack << :second}
-      @publisher.subscribe(consumer) {|e| stack << :third}
-      @publisher.raise_event(Object.new)
-      stack.size.should == 3
-      stack.should == [:first, :second, :third]
-    end
-
-    it 'should skip subscribers who have unsubscribed' do
-      stack = []
-      consumers = (1..3).collect {|x| Object.new}
-      consumers.each {|c| @publisher.subscribe(c) {|e| stack << c.object_id} }
-      @publisher.unsubscribe(consumers[1])
-      @publisher.raise_event(Object.new)
-      stack.should == [0,2].collect {|i| consumers[i].object_id}
-    end
-
-    it 'should gracefully handle subscribers that have passed on' do
-      gc = GC.enable
-      stack = []
-      consumer_class = Class.new do
-        attr_accessor :stack
-        def handle_event(event)
-          puts "Handling event!"
-          stack << object_id
-        end
-      end
-      consumers = (1..3).collect {|x| consumer_class.new}
-      consumers.each {|c| c.stack = stack; @publisher.subscribe(c, 
:handle_event)}
-      consumers.delete_at(1)
-      ObjectSpace.garbage_collect
-      @publisher.raise_event(Object.new)
-      stack.size.should == 2
-      stack.should == consumers.collect {|c| c.object_id}
-      GC.disable if gc
-    end
-  end
-end
-- 
1.6.3.3


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to