sub_pub 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
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
-