sub_pub 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c05979fc3b7a089c8cd4097cfc64afe78e45c47
4
- data.tar.gz: 1d9685e3e04bee5f4814ff9b6744cb1708e612f4
3
+ metadata.gz: 18b8637ba49480ffcad6eac58e51e952ca22c1b7
4
+ data.tar.gz: 7e218133a50995d898178c29d24d898a77587d9e
5
5
  SHA512:
6
- metadata.gz: d504b666e641901d31eacb9c73deee45096ffbb086ee45d89d7a332275332a71902d38e9b85cfee185ea5b5e3100d5097fe5d4728683d56f9a8098ea8b44db6f
7
- data.tar.gz: 8a93dbda5a734f57703a958f2640ce075b4593495ac340e3a33926d32ab493a32aa372ea3d1fd2196157fc4df6058ba55c72e23a15143482ed22c37d94576878
6
+ metadata.gz: 56a43c5cc8315d5cb60fcfea982d07af70059e0559af775ae1d1a2ed2dae056ce7f564bbaeef2b70a630d1b6582a3342cccb029c0d75750c983ec2f5dfbc014b
7
+ data.tar.gz: af265913220b1cd1483290c151223a9b07b1cf3c1cd409c70b67e1965dc85c66f68f8a60069440e90fb20e89b3984fad7f81a745dd1887069024a3cc1f383de9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sub_pub (0.0.14)
4
+ sub_pub (0.0.15)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -36,7 +36,7 @@ GEM
36
36
  arel (3.0.2)
37
37
  builder (3.0.4)
38
38
  coderay (1.0.8)
39
- diff-lcs (1.1.3)
39
+ diff-lcs (1.2.5)
40
40
  erubis (2.7.0)
41
41
  hike (1.2.1)
42
42
  i18n (0.6.1)
@@ -80,14 +80,14 @@ GEM
80
80
  rake (10.0.3)
81
81
  rdoc (3.12)
82
82
  json (~> 1.4)
83
- rspec (2.12.0)
84
- rspec-core (~> 2.12.0)
85
- rspec-expectations (~> 2.12.0)
86
- rspec-mocks (~> 2.12.0)
87
- rspec-core (2.12.1)
88
- rspec-expectations (2.12.0)
89
- diff-lcs (~> 1.1.3)
90
- rspec-mocks (2.12.0)
83
+ rspec (2.99.0)
84
+ rspec-core (~> 2.99.0)
85
+ rspec-expectations (~> 2.99.0)
86
+ rspec-mocks (~> 2.99.0)
87
+ rspec-core (2.99.2)
88
+ rspec-expectations (2.99.2)
89
+ diff-lcs (>= 1.1.3, < 2.0)
90
+ rspec-mocks (2.99.2)
91
91
  slop (3.3.3)
92
92
  sprockets (2.2.2)
93
93
  hike (~> 1.2)
@@ -0,0 +1,34 @@
1
+ module SubPub
2
+ module ActiveRecord
3
+ module Extensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ ['before_create', 'after_create', 'after_commit'].each do |callback|
8
+ class_eval "
9
+ #{callback} do
10
+ notify_pub_sub_of_active_record_callback('#{callback}')
11
+ end
12
+ "
13
+ end
14
+
15
+ [:create, :update, :destroy].each do |callback|
16
+ class_eval "
17
+ after_commit(on: callback) do
18
+ notify_pub_sub_of_active_record_callback('after_commit_on_#{callback.to_s}')
19
+ end
20
+ "
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def notify_pub_sub_of_active_record_callback(callback)
27
+ publisher = SubPub::ActiveRecord::Publisher.new(self, callback)
28
+ publisher.publish_callback_notification
29
+ publisher.publish_changed_attribute_notifications
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module SubPub
2
+ module ActiveRecord
3
+ class Publisher
4
+
5
+ def initialize(record, callback)
6
+ @record = record
7
+ @callback = callback
8
+ end
9
+
10
+ def publish_callback_notification
11
+ publish_notification(callback_notification)
12
+ end
13
+
14
+ def publish_changed_attribute_notifications
15
+ notification = changes_notification
16
+ publish_notification(notification) if notification
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :record, :callback
22
+
23
+ def publish_notification(message)
24
+ SubPub.publish(message, record: record)
25
+ end
26
+
27
+ def callback_notification
28
+ "active_record::#{record.class.to_s.underscore}::#{callback}"
29
+ end
30
+
31
+ def changes_notification
32
+ return unless record_changes.keys.size > 0
33
+ callback_notification.tap do |name|
34
+ record_changes.keys.sort.each { |attribute| name << "::#{attribute}" }
35
+ end
36
+ end
37
+
38
+ def record_changes
39
+ /(before|after)_create/.match(callback) ? record.changes : record.previous_changes
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,65 @@
1
+ module SubPub
2
+ module ActiveRecord
3
+ class Subscriber < ::SubPub::Subscriber
4
+ def self.subscribe_to(class_instance, callback_name, *table_attributes)
5
+ @class_instance = class_instance
6
+ @callback_name = callback_name
7
+ @table_attributes = table_attributes
8
+
9
+ super(subscription_name)
10
+ end
11
+
12
+ def self.model_name
13
+ @class_instance.to_s
14
+ end
15
+
16
+ def self.callback_name
17
+ @callback_name
18
+ end
19
+
20
+ def self.table_attributes
21
+ @table_attributes
22
+ end
23
+
24
+ def callback_name
25
+ self.class.callback_name
26
+ end
27
+
28
+ def model_name
29
+ self.class.model_name
30
+ end
31
+
32
+ def table_attributes
33
+ self.class.table_attributes
34
+ end
35
+
36
+ def record
37
+ options[:record]
38
+ end
39
+
40
+ private
41
+
42
+ def self.subscription_name
43
+ table_attributes.empty? ? string_subscription : regex_subscription
44
+ end
45
+
46
+ def self.string_subscription
47
+ subscription_basename
48
+ end
49
+
50
+ def self.regex_subscription
51
+ matcher = subscription_basename << "::"
52
+ matcher.tap do |m|
53
+ table_attributes.sort.each { |attribute| m << ".*(?:(#{attribute})(?:::|$))" }
54
+ end
55
+
56
+ Regexp.new(matcher)
57
+ end
58
+
59
+ def self.subscription_basename
60
+ "active_record::#{@class_instance.to_s.underscore}::#{@callback_name}"
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -2,7 +2,7 @@ module SubPub
2
2
  class Railtie < Rails::Railtie
3
3
  initializer "pub sub configuration of active record extensions" do
4
4
  class ::ActiveRecord::Base
5
- include SubPub::ActiveRecordExtensions
5
+ include SubPub::ActiveRecord::Extensions
6
6
  end
7
7
 
8
8
  config.after_initialize do
@@ -1,16 +1,26 @@
1
1
  module SubPub
2
2
  class ScopedTopic
3
+ attr_reader :topic
4
+
3
5
  def initialize(topic, scope)
4
6
  @topic = topic
5
7
  @scope = scope
6
8
  end
7
9
 
8
10
  def full_topic
9
- "#{@scope}::#{@topic}"
11
+ scoped_topic
10
12
  end
11
13
 
12
- def topic
13
- @topic
14
+ private
15
+
16
+ attr_reader :scope
17
+
18
+ def scoped_topic
19
+ if topic.is_a? Regexp
20
+ /#{scope}::#{topic.source}/
21
+ else
22
+ "#{scope}::#{topic}"
23
+ end
14
24
  end
15
25
  end
16
26
  end
@@ -16,7 +16,7 @@ module SubPub
16
16
  end
17
17
 
18
18
  def unsubscribe
19
- ActiveSupport::Notifications.unsubscribe(@scoped_topic.full_topic)
19
+ ActiveSupport::Notifications.unsubscribe(@subscription)
20
20
  end
21
21
 
22
22
  def topic
@@ -1,3 +1,3 @@
1
1
  module SubPub
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.15"
3
3
  end
data/lib/sub_pub.rb CHANGED
@@ -43,13 +43,14 @@ end
43
43
 
44
44
  require "sub_pub/version"
45
45
  require "sub_pub/subscriber"
46
- require "sub_pub/register"
47
46
  require "sub_pub/subscription"
47
+ require "sub_pub/register"
48
48
  require "sub_pub/scoped_topic"
49
49
 
50
50
  require "rails"
51
51
  require "active_record"
52
52
 
53
- require "sub_pub/active_record_subscriber"
54
- require "sub_pub/active_record_extensions"
53
+ require "sub_pub/active_record/publisher"
54
+ require "sub_pub/active_record/subscriber"
55
+ require "sub_pub/active_record/extensions"
55
56
  require "sub_pub/railtie"
@@ -4,8 +4,8 @@ module SubPub
4
4
  SubscribeToModel.new(expected)
5
5
  end
6
6
 
7
- def subscribe_to_callback(expected)
8
- SubscribeToModelCallback.new(expected)
7
+ def subscribe_to_callback(*expected)
8
+ SubscribeToModelCallback.new(*expected)
9
9
  end
10
10
 
11
11
  def subscribe_to_topic(expected)
@@ -33,12 +33,13 @@ module SubPub
33
33
  end
34
34
 
35
35
  class SubscribeToModelCallback
36
- def initialize(expected)
37
- @expected = expected
36
+ def initialize(*expected)
37
+ @callback_name, *@table_attributes = *expected
38
38
  end
39
39
 
40
40
  def matches?(subject)
41
- subject.callback_name.should == @expected
41
+ subject.callback_name.should == @callback_name
42
+ subject.table_attributes.should == @table_attributes
42
43
  end
43
44
  end
44
45
  end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub do
4
+ include_context "a fake active record result"
5
+ include_context "a fake active record user"
6
+
7
+ describe "after create" do
8
+ before do
9
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
10
+ subscribe_to(FakeActiveRecordUser, 'after_create', :title, :body)
11
+
12
+ def on_publish
13
+ FakeActiveRecordResult.create
14
+ end
15
+ end
16
+ end
17
+
18
+ it "successfully calls through to the subscriber" do
19
+ FakeActiveRecordResult.count.should == 0
20
+
21
+ FakeActiveRecordUser.create
22
+ FakeActiveRecordResult.count.should == 0
23
+
24
+ FakeActiveRecordUser.create(title: "hey guys")
25
+ FakeActiveRecordResult.count.should == 0
26
+
27
+ FakeActiveRecordUser.create(title: "hey guys", body: "nice talking to you")
28
+
29
+
30
+ FakeActiveRecordResult.count.should == 1
31
+ end
32
+ end
33
+
34
+ describe "after commit" do
35
+ before do
36
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
37
+ subscribe_to(FakeActiveRecordUser, 'after_commit', :title, :body)
38
+
39
+ def on_publish
40
+ FakeActiveRecordResult.create
41
+ end
42
+ end
43
+ end
44
+
45
+ it "successfully calls through to the subscriber" do
46
+ FakeActiveRecordResult.count.should == 0
47
+ fake_user = FakeActiveRecordUser.create
48
+
49
+ fake_user.update_attributes(title: "ABC")
50
+ fake_user.update_attributes(body: "XYZ")
51
+ FakeActiveRecordResult.count.should == 0
52
+
53
+ fake_user.update_attributes(body: "words", title: "blah")
54
+ FakeActiveRecordResult.count.should == 1
55
+
56
+ fake_user.update_attributes(body: "things", title: "stuff", pizza: "cheese")
57
+
58
+
59
+ FakeActiveRecordResult.count.should == 2
60
+ end
61
+ end
62
+
63
+ describe "after commit on create" do
64
+ before do
65
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
66
+ subscribe_to(FakeActiveRecordUser, 'after_commit_on_create', :title, :body)
67
+
68
+ def on_publish
69
+ FakeActiveRecordResult.create
70
+ end
71
+ end
72
+ end
73
+
74
+ it "successfully calls through to the subscriber" do
75
+ FakeActiveRecordResult.count.should == 0
76
+
77
+ FakeActiveRecordUser.create
78
+ FakeActiveRecordResult.count.should == 0
79
+
80
+ FakeActiveRecordUser.create(title: "hey guys")
81
+ FakeActiveRecordResult.count.should == 0
82
+
83
+ FakeActiveRecordUser.create(title: "hey guys", body: "nice talking to you")
84
+
85
+
86
+ FakeActiveRecordResult.count.should == 1
87
+ end
88
+ end
89
+
90
+ describe "after commit on update" do
91
+ before do
92
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
93
+ subscribe_to(FakeActiveRecordUser, 'after_commit_on_update', :title, :body)
94
+
95
+ def on_publish
96
+ FakeActiveRecordResult.create
97
+ end
98
+ end
99
+ end
100
+
101
+ it "successfully calls through to the subscriber" do
102
+ FakeActiveRecordResult.count.should == 0
103
+ fake_user = FakeActiveRecordUser.create
104
+
105
+ fake_user.update_attributes(title: "ABC")
106
+ fake_user.update_attributes(body: "XYZ")
107
+ FakeActiveRecordResult.count.should == 0
108
+
109
+ fake_user.update_attributes(body: "words", title: "blah")
110
+ FakeActiveRecordResult.count.should == 1
111
+
112
+ fake_user.update_attributes(body: "things", title: "stuff", pizza: "cheese")
113
+
114
+
115
+ FakeActiveRecordResult.count.should == 2
116
+ end
117
+ end
118
+
119
+ describe "before create" do
120
+ before do
121
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
122
+ subscribe_to(FakeActiveRecordUser, 'before_create', :title, :body)
123
+
124
+ def on_publish
125
+ record.fake_active_record_results.build(title: 'fooz')
126
+ end
127
+ end
128
+ end
129
+
130
+ it "successfully calls through to the subscriber" do
131
+ FakeActiveRecordResult.count.should == 0
132
+
133
+ FakeActiveRecordUser.create
134
+ FakeActiveRecordResult.count.should == 0
135
+
136
+ FakeActiveRecordUser.create(title: "hey guys")
137
+ FakeActiveRecordResult.count.should == 0
138
+
139
+ FakeActiveRecordUser.create(title: "hey guys", body: "nice talking to you")
140
+ FakeActiveRecordResult.count.should == 1
141
+ end
142
+ end
143
+ end
144
+
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub do
4
+ include_context "a fake active record result"
5
+ include_context "a fake active record user"
6
+
7
+ describe "subscribing to an active record callback" do
8
+ describe "after create" do
9
+ before do
10
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
11
+ subscribe_to(FakeActiveRecordUser, 'after_create')
12
+
13
+ def on_publish
14
+ FakeActiveRecordResult.create
15
+ end
16
+ end
17
+ end
18
+
19
+ it "successfully calls through to the subscriber" do
20
+ FakeActiveRecordResult.all.size.should == 0
21
+ FakeActiveRecordUser.create
22
+ FakeActiveRecordResult.all.size.should == 1
23
+ end
24
+ end
25
+
26
+ describe "after commit" do
27
+ before do
28
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
29
+ subscribe_to(FakeActiveRecordUser, 'after_commit')
30
+
31
+ def on_publish
32
+ FakeActiveRecordResult.create
33
+ end
34
+ end
35
+ end
36
+
37
+ it "successfully calls through to the subscriber" do
38
+ FakeActiveRecordResult.all.size.should == 0
39
+ FakeActiveRecordUser.create
40
+ FakeActiveRecordResult.all.size.should == 1
41
+ end
42
+ end
43
+
44
+ describe "after commit on create" do
45
+ before do
46
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
47
+ subscribe_to(FakeActiveRecordUser, 'after_commit_on_create')
48
+
49
+ def on_publish
50
+ FakeActiveRecordResult.create
51
+ end
52
+ end
53
+ end
54
+
55
+ it "successfully calls through to the subscriber" do
56
+ FakeActiveRecordResult.all.size.should == 0
57
+ FakeActiveRecordUser.create
58
+ FakeActiveRecordResult.all.size.should == 1
59
+ end
60
+ end
61
+
62
+ describe "after commit on destroy" do
63
+ before do
64
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
65
+ subscribe_to(FakeActiveRecordUser, 'after_commit_on_destroy')
66
+
67
+ def on_publish
68
+ FakeActiveRecordResult.create
69
+ end
70
+ end
71
+ end
72
+
73
+ it "successfully calls through to the subscriber" do
74
+ FakeActiveRecordResult.all.size.should == 0
75
+ FakeActiveRecordUser.create.destroy
76
+ FakeActiveRecordResult.all.size.should == 1
77
+ end
78
+ end
79
+
80
+ describe "after commit on update" do
81
+ before do
82
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
83
+ subscribe_to(FakeActiveRecordUser, 'after_commit_on_update')
84
+
85
+ def on_publish
86
+ FakeActiveRecordResult.create
87
+ end
88
+ end
89
+ end
90
+
91
+ it "successfully calls through to the subscriber" do
92
+ FakeActiveRecordResult.all.size.should == 0
93
+ fake_user = FakeActiveRecordUser.create
94
+ fake_user.update_attributes(title: "ABC")
95
+ FakeActiveRecordResult.all.size.should == 1
96
+ end
97
+ end
98
+
99
+ describe "before create" do
100
+ before do
101
+ class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
102
+ subscribe_to(FakeActiveRecordUser, 'before_create')
103
+
104
+ def on_publish
105
+ record.fake_active_record_results.build(title: 'fooz')
106
+ end
107
+ end
108
+ end
109
+
110
+ it "successfully calls through to the subscriber" do
111
+ FakeActiveRecordResult.all.size.should == 0
112
+ FakeActiveRecordUser.create
113
+ FakeActiveRecordResult.all.size.should == 1
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,31 @@
1
+
2
+ shared_context "a record with changes" do
3
+ let(:changes) do
4
+ {
5
+ zzzattribute: ["words", "blerbs"],
6
+ aaaattribute: ["spaghetti", "metallica"],
7
+ }
8
+ end
9
+
10
+ let(:expected_message) { "active_record::#{record.class.to_s.underscore}::#{callback}::aaaattribute::zzzattribute" }
11
+
12
+ before do
13
+ allow(record).to receive(:changes) { changes }
14
+ end
15
+ end
16
+
17
+ shared_context "a record with previous changes" do
18
+ let(:previous_changes) do
19
+ {
20
+ zzzattribute: ["words", "blerbs"],
21
+ aaaattribute: ["spaghetti", "metallica"],
22
+ }
23
+ end
24
+
25
+ let(:expected_message) { "active_record::#{record.class.to_s.underscore}::#{callback}::aaaattribute::zzzattribute" }
26
+
27
+ before do
28
+ allow(record).to receive(:previous_changes) { previous_changes }
29
+ end
30
+ end
31
+
@@ -0,0 +1,26 @@
1
+ shared_context "a fake active record user" do
2
+ with_model :FakeActiveRecordUser do
3
+ table do |t|
4
+ t.string :title
5
+ t.string :body
6
+ t.string :pizza
7
+ end
8
+
9
+ model do
10
+ has_many :fake_active_record_results
11
+ end
12
+ end
13
+ end
14
+
15
+ shared_context "a fake active record result" do
16
+ with_model :FakeActiveRecordResult do
17
+ table do |t|
18
+ t.string :title
19
+ t.string :body
20
+ t.string :pizza
21
+ t.integer :fake_active_record_user_id
22
+ end
23
+ end
24
+ end
25
+
26
+
@@ -1,27 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SubPub do
4
- with_model :FakeActiveRecordUser do
5
- table do |t|
6
- t.string :title
7
- end
8
-
9
- model do
10
- has_many :fake_active_record_results
11
- end
12
- end
13
-
14
- with_model :FakeActiveRecordResult do
15
- table do |t|
16
- t.string :title
17
- t.integer :fake_active_record_user_id
18
- end
19
- end
4
+ include_context "a fake active record result"
5
+ include_context "a fake active record user"
20
6
 
21
7
  describe "initial state" do
22
8
  it "defaults enabled to true" do
23
9
  SubPub::Register.instance.enabled = nil
24
- SubPub.enabled?.should be_true
10
+ SubPub.enabled?.should be true
25
11
  end
26
12
  end
27
13
 
@@ -29,14 +15,14 @@ describe SubPub do
29
15
  it "enables SubPub" do
30
16
  SubPub.disable
31
17
  SubPub.enable
32
- SubPub.enabled?.should be_true
18
+ SubPub.enabled?.should be true
33
19
  end
34
20
  end
35
21
 
36
22
  describe "#disable" do
37
23
  it "disables SubPub" do
38
24
  SubPub.disable
39
- SubPub.enabled?.should be_false
25
+ SubPub.enabled?.should be false
40
26
  end
41
27
  end
42
28
 
@@ -137,115 +123,4 @@ describe SubPub do
137
123
  SubPub::Register.instance.subscriptions.count.should == 1
138
124
  end
139
125
  end
140
-
141
- describe "active record configuration" do
142
- describe "after create" do
143
- before do
144
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
145
- subscribe_to(FakeActiveRecordUser, 'after_create')
146
-
147
- def on_publish
148
- FakeActiveRecordResult.create
149
- end
150
- end
151
- end
152
-
153
- it "successfully calls through to the subscriber" do
154
- FakeActiveRecordResult.all.size.should == 0
155
- FakeActiveRecordUser.create
156
- FakeActiveRecordResult.all.size.should == 1
157
- end
158
- end
159
-
160
- describe "after commit" do
161
- before do
162
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
163
- subscribe_to(FakeActiveRecordUser, 'after_commit')
164
-
165
- def on_publish
166
- FakeActiveRecordResult.create
167
- end
168
- end
169
- end
170
-
171
- it "successfully calls through to the subscriber" do
172
- FakeActiveRecordResult.all.size.should == 0
173
- FakeActiveRecordUser.create
174
- FakeActiveRecordResult.all.size.should == 1
175
- end
176
- end
177
-
178
- describe "after commit on create" do
179
- before do
180
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
181
- subscribe_to(FakeActiveRecordUser, 'after_commit_on_create')
182
-
183
- def on_publish
184
- FakeActiveRecordResult.create
185
- end
186
- end
187
- end
188
-
189
- it "successfully calls through to the subscriber" do
190
- FakeActiveRecordResult.all.size.should == 0
191
- FakeActiveRecordUser.create
192
- FakeActiveRecordResult.all.size.should == 1
193
- end
194
- end
195
-
196
- describe "after commit on destroy" do
197
- before do
198
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
199
- subscribe_to(FakeActiveRecordUser, 'after_commit_on_destroy')
200
-
201
- def on_publish
202
- FakeActiveRecordResult.create
203
- end
204
- end
205
- end
206
-
207
- it "successfully calls through to the subscriber" do
208
- FakeActiveRecordResult.all.size.should == 0
209
- FakeActiveRecordUser.create.destroy
210
- FakeActiveRecordResult.all.size.should == 1
211
- end
212
- end
213
-
214
- describe "after commit on update" do
215
- before do
216
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
217
- subscribe_to(FakeActiveRecordUser, 'after_commit_on_update')
218
-
219
- def on_publish
220
- FakeActiveRecordResult.create
221
- end
222
- end
223
- end
224
-
225
- it "successfully calls through to the subscriber" do
226
- FakeActiveRecordResult.all.size.should == 0
227
- fake_user = FakeActiveRecordUser.create
228
- fake_user.update_attributes(title: "ABC")
229
- FakeActiveRecordResult.all.size.should == 1
230
- end
231
- end
232
-
233
- describe "before create" do
234
- before do
235
- class FakeActiveRecordUserSubscriber < SubPub::ActiveRecord::Subscriber
236
- subscribe_to(FakeActiveRecordUser, 'before_create')
237
-
238
- def on_publish
239
- record.fake_active_record_results.build(title: 'fooz')
240
- end
241
- end
242
- end
243
-
244
- it "successfully calls through to the subscriber" do
245
- FakeActiveRecordResult.all.size.should == 0
246
- FakeActiveRecordUser.create
247
- FakeActiveRecordResult.all.size.should == 1
248
- end
249
- end
250
- end
251
126
  end
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,9 @@
4
4
  # loaded once.
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ Dir[File.dirname(__FILE__) + "/integration/shared_contexts/**/**.rb"].each {|f| require f}
9
+
7
10
  RSpec.configure do |config|
8
11
  config.treat_symbols_as_metadata_keys_with_true_values = true
9
12
  config.run_all_when_everything_filtered = true
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub::ActiveRecord::Publisher do
4
+ let(:record) { double(:record) }
5
+ let(:callback) { "some_callback" }
6
+
7
+ subject(:publisher) { SubPub::ActiveRecord::Publisher.new(record, callback) }
8
+
9
+ before do
10
+ stub_const("SomeClassName", Class.new)
11
+ allow(record).to receive(:class) { SomeClassName }
12
+ allow(SubPub).to receive(:publish)
13
+ end
14
+
15
+ describe "publish_callback_notification" do
16
+ let(:expected_message) { "active_record::some_class_name::some_callback" }
17
+
18
+ it "publishes a message" do
19
+ publisher.publish_callback_notification
20
+ expect(SubPub).to have_received(:publish).with(expected_message, record: record)
21
+ end
22
+ end
23
+
24
+ describe "publish_changed_attribute_notifications" do
25
+ context "a before_create callback" do
26
+ let(:callback) { 'before_create' }
27
+
28
+ context "with attribute changes" do
29
+ include_context "a record with changes"
30
+
31
+ it "publishes a message" do
32
+ publisher.publish_changed_attribute_notifications
33
+ expect(SubPub).to have_received(:publish).with(expected_message, record: record)
34
+ end
35
+ end
36
+
37
+ context "without attribute changes" do
38
+ include_context "a record with changes"
39
+ let(:changes) { {} }
40
+
41
+ it "does not publish a message" do
42
+ publisher.publish_changed_attribute_notifications
43
+ expect(SubPub).to_not have_received(:publish)
44
+ end
45
+ end
46
+ end
47
+
48
+ context "an after_create callback" do
49
+ let(:callback) { 'after_create' }
50
+
51
+ context "with attribute changes" do
52
+ include_context "a record with changes"
53
+
54
+ it "publishes a message" do
55
+ publisher.publish_changed_attribute_notifications
56
+ expect(SubPub).to have_received(:publish).with(expected_message, record: record)
57
+ end
58
+ end
59
+
60
+ context "without attribute changes" do
61
+ include_context "a record with changes"
62
+ let(:changes) { {} }
63
+
64
+ it "does not publish a message" do
65
+ publisher.publish_changed_attribute_notifications
66
+ expect(SubPub).to_not have_received(:publish)
67
+ end
68
+ end
69
+ end
70
+
71
+ context "any other type of callback" do
72
+ let(:callback) { 'after_commit' }
73
+
74
+ context "with attribute changes" do
75
+ include_context "a record with previous changes"
76
+
77
+ it "publishes a message" do
78
+ publisher.publish_changed_attribute_notifications
79
+ expect(SubPub).to have_received(:publish).with(expected_message, record: record)
80
+ end
81
+ end
82
+
83
+ context "without attribute changes" do
84
+ include_context "a record with previous changes"
85
+ let(:previous_changes) { {} }
86
+
87
+ it "does not publish a message" do
88
+ publisher.publish_changed_attribute_notifications
89
+ expect(SubPub).to_not have_received(:publish)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub::ActiveRecord::Subscriber do
4
+ with_model :FooBar do
5
+ table do |t|
6
+ t.string :title
7
+ end
8
+ end
9
+
10
+ before do
11
+ class Fooz < SubPub::ActiveRecord::Subscriber
12
+ subscribe_to(FooBar, 'after_create')
13
+ end
14
+
15
+ class Blooz < SubPub::ActiveRecord::Subscriber
16
+ subscribe_to(FooBar, 'after_create', :title)
17
+ end
18
+ end
19
+
20
+ describe ".model_name" do
21
+ specify { expect(Fooz.model_name).to eq('FooBar') }
22
+ end
23
+
24
+ describe ".callback_name" do
25
+ specify { expect(Fooz.callback_name).to eq('after_create') }
26
+ end
27
+
28
+ describe ".table_attributes" do
29
+ context "with table attributes" do
30
+ specify { expect(Blooz.table_attributes).to eq([:title]) }
31
+ end
32
+
33
+ context "without table attributes" do
34
+ specify { expect(Fooz.table_attributes).to eq([]) }
35
+ end
36
+ end
37
+
38
+ describe 'matchers' do
39
+ specify { expect(Fooz).to subscribe_to_model(FooBar) }
40
+ specify { expect(Fooz).to subscribe_to_callback("after_create") }
41
+
42
+ specify { expect(Blooz).to subscribe_to_model(FooBar) }
43
+ specify { expect(Blooz).to subscribe_to_callback("after_create", :title) }
44
+ end
45
+ end
46
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub::ScopedTopic do
4
+ let(:scope) { "cool_domain" }
5
+
6
+ subject(:scoped_topic) { SubPub::ScopedTopic.new(topic, scope) }
7
+
8
+ describe "#full_topic" do
9
+ context "the topic is a Regexp" do
10
+ let(:topic) { /cool_topic/ }
11
+ specify { expect(scoped_topic.full_topic).to eq(/cool_domain::cool_topic/) }
12
+ end
13
+
14
+ context "the topic is not a Regexp" do
15
+ let(:topic) { "cool_topic" }
16
+ specify { expect(scoped_topic.full_topic).to eq("cool_domain::cool_topic") }
17
+ end
18
+ end
19
+
20
+ describe "topic" do
21
+ let(:topic) { "cool_topic" }
22
+ specify { expect(scoped_topic.topic).to eq(topic) }
23
+ end
24
+
25
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubPub::Subscription do
4
+ let(:scoped_topic) { double(:scoped_topic) }
5
+ let(:topic) { double(:topic) }
6
+ let(:action) { double(:action) }
7
+ let(:active_support_subscription) { double(:active_support_subscription) }
8
+ let(:options) do
9
+ {
10
+ scoped_topic: scoped_topic,
11
+ action: action
12
+ }
13
+ end
14
+
15
+ let(:subscription) { SubPub::Subscription.new(options) }
16
+
17
+ before do
18
+ allow(scoped_topic).to receive(:topic) { topic }
19
+ end
20
+
21
+ shared_context "a subscribable subscription" do
22
+ let(:full_topic) { double(:full_topic) }
23
+
24
+ before do
25
+ allow(scoped_topic).to receive(:full_topic) { full_topic }
26
+ allow(ActiveSupport::Notifications).to receive(:subscribe) { active_support_subscription }
27
+ end
28
+ end
29
+
30
+ shared_examples "a method which adds a subscription" do
31
+ specify do
32
+ SubPub::Subscription.subscribe(options)
33
+ expect(ActiveSupport::Notifications).to have_received(:subscribe).
34
+ with(full_topic, action) { active_support_subscription }
35
+ end
36
+ end
37
+
38
+ describe ".subscribe" do
39
+ include_context "a subscribable subscription"
40
+ it_behaves_like "a method which adds a subscription"
41
+ specify do
42
+ returned_object = SubPub::Subscription.subscribe(options)
43
+ expect(returned_object.is_a? SubPub::Subscription).to be true
44
+ end
45
+ end
46
+
47
+ describe "#subscribe" do
48
+ include_context "a subscribable subscription"
49
+ it_behaves_like "a method which adds a subscription"
50
+ specify { expect(subscription.subscribe).to eq(active_support_subscription) }
51
+ end
52
+
53
+ describe "#unsubscribe" do
54
+ include_context "a subscribable subscription"
55
+
56
+ before do
57
+ allow(ActiveSupport::Notifications).to receive(:unsubscribe)
58
+ end
59
+
60
+ specify do
61
+ subscription.subscribe
62
+ subscription.unsubscribe
63
+
64
+ expect(ActiveSupport::Notifications).to have_received(:unsubscribe).
65
+ with(active_support_subscription)
66
+ end
67
+ end
68
+
69
+ describe "#topic" do
70
+ specify { expect(subscription.topic).to eq(topic) }
71
+ end
72
+
73
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sub_pub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - zephyr-dev@googlegroups.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-08 00:00:00.000000000 Z
11
+ date: 2014-10-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: In process publish/subscribe for Ruby
14
14
  email:
@@ -27,8 +27,9 @@ files:
27
27
  - Rakefile
28
28
  - db/.gitkeep
29
29
  - lib/sub_pub.rb
30
- - lib/sub_pub/active_record_extensions.rb
31
- - lib/sub_pub/active_record_subscriber.rb
30
+ - lib/sub_pub/active_record/extensions.rb
31
+ - lib/sub_pub/active_record/publisher.rb
32
+ - lib/sub_pub/active_record/subscriber.rb
32
33
  - lib/sub_pub/railtie.rb
33
34
  - lib/sub_pub/register.rb
34
35
  - lib/sub_pub/scoped_topic.rb
@@ -36,13 +37,20 @@ files:
36
37
  - lib/sub_pub/subscription.rb
37
38
  - lib/sub_pub/version.rb
38
39
  - lib/sub_pub_matchers.rb
40
+ - spec/integration/active_record_subscription/subscribing_to_callbacks_and_attributes_spec.rb
41
+ - spec/integration/active_record_subscription/subscribing_to_callbacks_spec.rb
42
+ - spec/integration/shared_contexts/changing_records_includes.rb
43
+ - spec/integration/shared_contexts/fake_active_record_includes.rb
39
44
  - spec/integration/sub_pub_spec.rb
40
45
  - spec/spec_helper.rb
41
- - spec/unit/active_record_matchers_spec.rb
42
- - spec/unit/active_record_subscriber_spec.rb
46
+ - spec/unit/active_record/matchers_spec.rb
47
+ - spec/unit/active_record/publisher_spec.rb
48
+ - spec/unit/active_record/subscriber_spec.rb
43
49
  - spec/unit/matchers_spec.rb
44
50
  - spec/unit/register_spec.rb
51
+ - spec/unit/scoped_topic_spec.rb
45
52
  - spec/unit/subscriber_spec.rb
53
+ - spec/unit/subscription_spec.rb
46
54
  - sub_pub.gemspec
47
55
  homepage: ''
48
56
  licenses: []
@@ -63,16 +71,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
71
  version: '0'
64
72
  requirements: []
65
73
  rubyforge_project:
66
- rubygems_version: 2.1.11
74
+ rubygems_version: 2.0.3
67
75
  signing_key:
68
76
  specification_version: 4
69
77
  summary: SubPub is a thin wrapper around ActiveSupport::Notifications, which provides
70
78
  an implementation of the Publish/Subscribe pattern.
71
79
  test_files:
80
+ - spec/integration/active_record_subscription/subscribing_to_callbacks_and_attributes_spec.rb
81
+ - spec/integration/active_record_subscription/subscribing_to_callbacks_spec.rb
82
+ - spec/integration/shared_contexts/changing_records_includes.rb
83
+ - spec/integration/shared_contexts/fake_active_record_includes.rb
72
84
  - spec/integration/sub_pub_spec.rb
73
85
  - spec/spec_helper.rb
74
- - spec/unit/active_record_matchers_spec.rb
75
- - spec/unit/active_record_subscriber_spec.rb
86
+ - spec/unit/active_record/matchers_spec.rb
87
+ - spec/unit/active_record/publisher_spec.rb
88
+ - spec/unit/active_record/subscriber_spec.rb
76
89
  - spec/unit/matchers_spec.rb
77
90
  - spec/unit/register_spec.rb
91
+ - spec/unit/scoped_topic_spec.rb
78
92
  - spec/unit/subscriber_spec.rb
93
+ - spec/unit/subscription_spec.rb
@@ -1,30 +0,0 @@
1
- module SubPub
2
- module ActiveRecordExtensions
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- ['before_create', 'after_create', 'after_commit'].each do |callback|
7
- class_eval "
8
- #{callback} do
9
- notify_pub_sub_of_active_record_callback('#{callback}')
10
- end
11
- "
12
- end
13
-
14
- [:create, :update, :destroy].each do |callback|
15
- class_eval "
16
- after_commit(on: callback) do
17
- notify_pub_sub_of_active_record_callback('after_commit_on_#{callback.to_s}')
18
- end
19
- "
20
- end
21
- end
22
-
23
- private
24
-
25
- def notify_pub_sub_of_active_record_callback(callback)
26
- message = "active_record::#{self.class.to_s.underscore}::#{callback}"
27
- SubPub.publish(message, record: self)
28
- end
29
- end
30
- end
@@ -1,31 +0,0 @@
1
- module SubPub
2
- module ActiveRecord
3
- class Subscriber < SubPub::Subscriber
4
- def self.subscribe_to(class_instance, callback_name)
5
- @class_instance = class_instance
6
- @callback_name = callback_name
7
- super("active_record::#{@class_instance.to_s.underscore}::#{@callback_name}")
8
- end
9
-
10
- def self.model_name
11
- @class_instance.to_s
12
- end
13
-
14
- def self.callback_name
15
- @callback_name
16
- end
17
-
18
- def callback_name
19
- self.class.callback_name
20
- end
21
-
22
- def model_name
23
- self.class.model_name
24
- end
25
-
26
- def record
27
- options[:record]
28
- end
29
- end
30
- end
31
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe SubPub::ActiveRecord::Subscriber do
4
- with_model :FooBar do
5
- table do |t|
6
- t.string :title
7
- end
8
- end
9
-
10
- before do
11
- class Fooz < SubPub::ActiveRecord::Subscriber
12
- subscribe_to(FooBar, 'after_create')
13
- end
14
-
15
- class Bazz < SubPub::ActiveRecord::Subscriber
16
- subscribe_to(FooBar, 'after_create')
17
- end
18
- end
19
-
20
- it "returns the model name observed" do
21
- Fooz.model_name.should == 'FooBar'
22
- end
23
-
24
- it "returns the callback observed" do
25
- Bazz.callback_name.should == 'after_create'
26
- end
27
-
28
- context 'matchers' do
29
- subject do
30
- Fooz
31
- end
32
-
33
- it { should subscribe_to_model(FooBar) }
34
- it { should subscribe_to_callback("after_create") }
35
- end
36
- end
37
-