From 7077b1743b67d2dd6a3e6a21376a7566132c77ad Mon Sep 17 00:00:00 2001
From: Piotr Banasik <piotr.banasik@gmail.com>
Date: Wed, 20 Jul 2016 11:35:59 -0700
Subject: [PATCH 1/3] Fixing issue with abstract errors

---
 lib/webhook_system/base_event.rb | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/webhook_system/base_event.rb b/lib/webhook_system/base_event.rb
index c371355..06b9e28 100644
--- a/lib/webhook_system/base_event.rb
+++ b/lib/webhook_system/base_event.rb
@@ -13,12 +13,12 @@ def initialize(*args, &block)
 
     def event_name
       mesg = "class #{self.class.name} must implement abstract method `#{self.class.name}#event_name()'."
-      raise RuntimeError.new(mesg).tap { |err| err.backtrace = caller }
+      raise with_caller_backtrace(RuntimeError.new(mesg), 2)
     end
 
     def payload_attributes
       mesg = "class #{self.class.name} must implement abstract method `#{self.class.name}#payload_attributes()'."
-      raise RuntimeError.new(mesg).tap { |err| err.backtrace = caller }
+      raise with_caller_backtrace(RuntimeError.new(mesg), 2)
     end
 
     def as_json
@@ -39,6 +39,11 @@ def self.key_is_reserved?(key)
 
     private
 
+    def with_caller_backtrace(exception, backtrack=2)
+      exception.set_backtrace(caller[backtrack..-1])
+      exception
+    end
+
     def validate_attribute_name(key)
       if self.class.key_is_reserved?(key)
         message = "#{self.class.name} should not be defining an attribute named #{key} since its reserved"

From 9652279bbd8f57f2f2b03c43bc903e35fefa4664 Mon Sep 17 00:00:00 2001
From: Piotr Banasik <piotr.banasik@gmail.com>
Date: Wed, 20 Jul 2016 11:08:43 -0700
Subject: [PATCH 2/3] Changing the main dispatch interface to call of a
 relation, enabling filtering of the subscriptions being considered

---
 README.md                                     | 36 ++++++++++++++++++-
 lib/webhook_system.rb                         |  4 ---
 lib/webhook_system/dispatcher.rb              | 16 ---------
 lib/webhook_system/subscription.rb            | 10 ++++++
 ...tch_spec.rb => dispatching_events_spec.rb} |  8 ++---
 spec/integration_spec.rb                      |  2 +-
 6 files changed, 50 insertions(+), 26 deletions(-)
 delete mode 100644 lib/webhook_system/dispatcher.rb
 rename spec/{dispatch_spec.rb => dispatching_events_spec.rb} (93%)

diff --git a/README.md b/README.md
index 5580881..9890752 100644
--- a/README.md
+++ b/README.md
@@ -203,12 +203,46 @@ more suitable for the actual notification payload.
 The general API for this is via:
 
 ```ruby
-WebhookSystem.dispatch(event_object)
+WebhookSystem::Subscription.dispatch(event_object)
 ```
 
 This is meant to be fairly fire and forget. Internally this will create an ActiveJob for each subscription
 interested in the event.
 
+### Dispatching to Selected Subscriptions
+
+There may be scenarios where you extended the Subscription model, and may need to only dispatch to a subset of subs.
+For example, if you attached a relation to say Account. The `dispatch` method is actually defined to work with any
+subscription relation. eg:
+
+```ruby
+account = Account.find(1) # assume we have some model called Account
+subs = account.webhook_subscriptions # and we added a column to webhook_subscriptions to accomodate this extra relation
+subs.dispatch(some_event) # you can dispatch to just those subscriptions (it will filter for the specific ones)
+                          # that are actually interested in the event
+```
+
+### Checking if any sub is interested
+
+There may scenarios, where you really don't want to do some additional work unless you really have an event to dispatch.
+You can check pretty quickly if there is any topics interested liks so:
+
+```ruby
+if WebhookSystem::Subscription.interested_in_topic('some_topic').present?
+  # do some stuff
+end
+```
+
+This also works with selected subscriptions like in the example above:
+
+```ruby
+account = Account.find(1) # assume we have some model called Account
+subs = account.webhook_subscriptions # and we added a column to webhook_subscriptions to accomodate this extra relation
+if subs.interested_in_topic('some_topic').present?
+  subs.dispatch(SomeEvent.build(some_expensive_function()))
+end
+```
+
 # Payload Format
 
 Payloads can either be plain json or encrypted. On top of that, they're also signed. The format for the signature
diff --git a/lib/webhook_system.rb b/lib/webhook_system.rb
index 219f5f4..5e563b5 100644
--- a/lib/webhook_system.rb
+++ b/lib/webhook_system.rb
@@ -20,8 +20,4 @@ module WebhookSystem
   # Error raised when there is an issue with decoding the payload
   class DecodingError < RuntimeError
   end
-
-  class << self
-    delegate :dispatch, to: :'WebhookSystem::Dispatcher'
-  end
 end
diff --git a/lib/webhook_system/dispatcher.rb b/lib/webhook_system/dispatcher.rb
deleted file mode 100644
index b989a1b..0000000
--- a/lib/webhook_system/dispatcher.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module WebhookSystem
-
-  # Main code that handles dispatching of events out to subscribers
-  class Dispatcher
-    class << self
-
-      # @param [WebhookSystem::BaseEvent] event The Event Object
-      def dispatch(event)
-        WebhookSystem::Subscription.interested_in_topic(event.event_name).each do |subscription|
-          WebhookSystem::Job.perform_later subscription, event.as_json
-        end
-      end
-
-    end
-  end
-end
diff --git a/lib/webhook_system/subscription.rb b/lib/webhook_system/subscription.rb
index ec1a419..45d822b 100644
--- a/lib/webhook_system/subscription.rb
+++ b/lib/webhook_system/subscription.rb
@@ -19,6 +19,16 @@ class Subscription < ActiveRecord::Base
 
     scope :interested_in_topic, -> (topic) { active.for_topic(topic) }
 
+    # Main invocation point for dispatching events, can either be called on the class
+    # or on a relation (ie a scoped down list of subs), will find applicable subs and dispatch to them
+    #
+    # @param [WebhookSystem::BaseEvent] event The Event Object
+    def self.dispatch(event)
+      interested_in_topic(event.event_name).each do |subscription|
+        WebhookSystem::Job.perform_later subscription, event.as_json
+      end
+    end
+
     # Just a helper to get a nice representation of the subscription
     def url_domain
       URI.parse(url).host
diff --git a/spec/dispatch_spec.rb b/spec/dispatching_events_spec.rb
similarity index 93%
rename from spec/dispatch_spec.rb
rename to spec/dispatching_events_spec.rb
index 4621db7..4cdd6ab 100644
--- a/spec/dispatch_spec.rb
+++ b/spec/dispatching_events_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe WebhookSystem, aggregate_failures: true, db: true do
+describe 'dispatching events', aggregate_failures: true, db: true do
   describe 'dispatching' do
     let!(:subscription1) do
       create(:webhook_subscription, :active, :encrypted, :with_topics, url: 'http://lvh.me/hook1', topics: ['other_event'])
@@ -45,7 +45,7 @@ def payload_attributes
 
         expect {
           perform_enqueued_jobs do
-            described_class.dispatch event
+            WebhookSystem::Subscription.dispatch event
           end
         }.to change { subscription1.event_logs.count }.by(1)
 
@@ -68,7 +68,7 @@ def payload_attributes
         expect {
           expect {
             perform_enqueued_jobs do
-              described_class.dispatch event
+              WebhookSystem::Subscription.dispatch event
             end
           }.to change { subscription1.event_logs.count }.by(1)
         }.to raise_exception(WebhookSystem::Job::RequestFailed, 'request failed with code: 400')
@@ -90,7 +90,7 @@ def payload_attributes
         expect {
           expect {
             perform_enqueued_jobs do
-              described_class.dispatch event
+              WebhookSystem::Subscription.dispatch event
             end
           }.to change { subscription1.event_logs.count }.by(1)
         }.to raise_exception(WebhookSystem::Job::RequestFailed, 'request failed with code: 0')
diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb
index 89ac0e2..c2472d2 100644
--- a/spec/integration_spec.rb
+++ b/spec/integration_spec.rb
@@ -70,7 +70,7 @@ def handle_webhook(to:)
     end
 
     perform_enqueued_jobs do
-      WebhookSystem.dispatch event
+      WebhookSystem::Subscription.dispatch event
     end
 
     expect(hooks_called).to match_array([:hook1, :hook2])

From 8d5843fdbecff57ae764631804bd910a4985218a Mon Sep 17 00:00:00 2001
From: Piotr Banasik <piotr.banasik@gmail.com>
Date: Wed, 20 Jul 2016 11:14:48 -0700
Subject: [PATCH 3/3] Bump to 2.1.0

---
 lib/webhook_system/version.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/webhook_system/version.rb b/lib/webhook_system/version.rb
index 7591714..19a1b3e 100644
--- a/lib/webhook_system/version.rb
+++ b/lib/webhook_system/version.rb
@@ -1,3 +1,3 @@
 module WebhookSystem
-  VERSION = '2.0.0'
+  VERSION = '2.1.0'
 end