socialization 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +2 -1
  4. data/Appraisals +13 -1
  5. data/CHANGELOG.md +12 -0
  6. data/Guardfile +12 -0
  7. data/LICENSE +2 -2
  8. data/README.md +46 -1
  9. data/Rakefile +8 -10
  10. data/lib/socialization/stores/active_record/follow.rb +4 -0
  11. data/lib/socialization/stores/active_record/like.rb +4 -0
  12. data/lib/socialization/stores/active_record/mention.rb +4 -0
  13. data/lib/socialization/stores/active_record/mixins/base.rb +4 -0
  14. data/lib/socialization/stores/mixins/follow.rb +1 -1
  15. data/lib/socialization/version.rb +1 -1
  16. data/socialization.gemspec +5 -3
  17. data/spec/actors/follower_spec.rb +113 -0
  18. data/spec/actors/liker_spec.rb +105 -0
  19. data/spec/actors/mentioner_spec.rb +105 -0
  20. data/spec/spec_helper.rb +21 -0
  21. data/{test/test_helper.rb → spec/spec_support/data_stores.rb} +76 -81
  22. data/spec/spec_support/matchers.rb +54 -0
  23. data/spec/stores/active_record/follow_store_spec.rb +147 -0
  24. data/spec/stores/active_record/like_store_spec.rb +146 -0
  25. data/spec/stores/active_record/mention_store_spec.rb +148 -0
  26. data/spec/stores/active_record/mixins/base_spec.rb +25 -0
  27. data/spec/stores/redis/base_spec.rb +195 -0
  28. data/spec/stores/redis/config_spec.rb +28 -0
  29. data/spec/stores/redis/follow_store_spec.rb +26 -0
  30. data/spec/stores/redis/like_store_spec.rb +23 -0
  31. data/spec/stores/redis/mention_store_spec.rb +23 -0
  32. data/spec/string_spec.rb +13 -0
  33. data/spec/victims/followable_spec.rb +59 -0
  34. data/spec/victims/likeable_spec.rb +58 -0
  35. data/spec/victims/mentionable_spec.rb +59 -0
  36. data/spec/world_spec.rb +107 -0
  37. metadata +79 -42
  38. data/test/actors/follower_test.rb +0 -114
  39. data/test/actors/liker_test.rb +0 -106
  40. data/test/actors/mentioner_test.rb +0 -106
  41. data/test/stores/active_record/follow_store_test.rb +0 -138
  42. data/test/stores/active_record/like_store_test.rb +0 -139
  43. data/test/stores/active_record/mention_store_test.rb +0 -138
  44. data/test/stores/redis/base_test.rb +0 -203
  45. data/test/stores/redis/config_test.rb +0 -30
  46. data/test/stores/redis/follow_store_test.rb +0 -27
  47. data/test/stores/redis/like_store_test.rb +0 -25
  48. data/test/stores/redis/mention_store_test.rb +0 -25
  49. data/test/string_test.rb +0 -13
  50. data/test/victims/followable_test.rb +0 -60
  51. data/test/victims/likeable_test.rb +0 -60
  52. data/test/victims/mentionable_test.rb +0 -60
  53. data/test/world_test.rb +0 -112
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socialization::ActiveRecordStores::Like do
4
+ before do
5
+ @klass = Socialization::ActiveRecordStores::Like
6
+ @klass.touch nil
7
+ @klass.after_like nil
8
+ @klass.after_unlike nil
9
+ @liker = ImALiker.create
10
+ @likeable = ImALikeable.create
11
+ end
12
+
13
+ describe "data store" do
14
+ it "inherits Socialization::ActiveRecordStores::Like" do
15
+ expect(Socialization.like_model).to eq Socialization::ActiveRecordStores::Like
16
+ end
17
+ end
18
+
19
+ describe "#like!" do
20
+ it "creates a Like record" do
21
+ @klass.like!(@liker, @likeable)
22
+ expect(@liker).to match_liker @klass.last
23
+ expect(@likeable).to match_likeable @klass.last
24
+ end
25
+
26
+ it "increments counter caches" do
27
+ liker = ImALikerWithCounterCache.create
28
+ likeable = ImALikeableWithCounterCache.create
29
+ @klass.like!(liker, likeable)
30
+ expect(liker.reload.likees_count).to eq(1)
31
+ expect(likeable.reload.likers_count).to eq(1)
32
+ end
33
+
34
+ it "touches liker when instructed" do
35
+ @klass.touch :liker
36
+ expect(@liker).to receive(:touch).once
37
+ expect(@likeable).to receive(:touch).never
38
+ @klass.like!(@liker, @likeable)
39
+ end
40
+
41
+ it "touches likeable when instructed" do
42
+ @klass.touch :likeable
43
+ expect(@liker).to receive(:touch).never
44
+ expect(@likeable).to receive(:touch).once
45
+ @klass.like!(@liker, @likeable)
46
+ end
47
+
48
+ it "touches all when instructed" do
49
+ @klass.touch :all
50
+ expect(@liker).to receive(:touch).once
51
+ expect(@likeable).to receive(:touch).once
52
+ @klass.like!(@liker, @likeable)
53
+ end
54
+
55
+ it "calls after like hook" do
56
+ @klass.after_like :after_like
57
+ expect(@klass).to receive(:after_like).once
58
+ @klass.like!(@liker, @likeable)
59
+ end
60
+
61
+ it "calls after unlike hook" do
62
+ @klass.after_like :after_unlike
63
+ expect(@klass).to receive(:after_unlike).once
64
+ @klass.like!(@liker, @likeable)
65
+ end
66
+ end
67
+
68
+ describe "#unlike!" do
69
+ it "decrements counter caches" do
70
+ liker = ImALikerWithCounterCache.create
71
+ likeable = ImALikeableWithCounterCache.create
72
+ @klass.like!(liker, likeable)
73
+ @klass.unlike!(liker, likeable)
74
+ expect(liker.reload.likees_count).to eq 0
75
+ expect(likeable.reload.likers_count).to eq 0
76
+ end
77
+ end
78
+
79
+ describe "#likes?" do
80
+ it "returns true when like exists" do
81
+ @klass.create! do |f|
82
+ f.liker = @liker
83
+ f.likeable = @likeable
84
+ end
85
+ expect(@klass.likes?(@liker, @likeable)).to be true
86
+ end
87
+
88
+ it "returns false when like doesn't exist" do
89
+ expect(@klass.likes?(@liker, @likeable)).to be false
90
+ end
91
+ end
92
+
93
+ describe "#likers" do
94
+ it "returns an array of likers" do
95
+ liker1 = ImALiker.create
96
+ liker2 = ImALiker.create
97
+ liker1.like!(@likeable)
98
+ liker2.like!(@likeable)
99
+ expect(@klass.likers(@likeable, liker1.class)).to eq [liker1, liker2]
100
+ end
101
+
102
+ it "returns an array of liker ids when plucking" do
103
+ liker1 = ImALiker.create
104
+ liker2 = ImALiker.create
105
+ liker1.like!(@likeable)
106
+ liker2.like!(@likeable)
107
+ expect(@klass.likers(@likeable, liker1.class, :pluck => :id)).to eq [liker1.id, liker2.id]
108
+ end
109
+ end
110
+
111
+ describe "#likeables" do
112
+ it "returns an array of likers" do
113
+ likeable1 = ImALikeable.create
114
+ likeable2 = ImALikeable.create
115
+ @liker.like!(likeable1)
116
+ @liker.like!(likeable2)
117
+ expect(@klass.likeables(@liker, likeable1.class)).to eq [likeable1, likeable2]
118
+ end
119
+
120
+ it "returns an array of liker ids when plucking" do
121
+ likeable1 = ImALikeable.create
122
+ likeable2 = ImALikeable.create
123
+ @liker.like!(likeable1)
124
+ @liker.like!(likeable2)
125
+ expect(@klass.likeables(@liker, likeable1.class, :pluck => :id)).to eq [likeable1.id, likeable2.id]
126
+ end
127
+ end
128
+
129
+ describe "#remove_likers" do
130
+ it "deletes all likers relationships for a likeable" do
131
+ @liker.like!(@likeable)
132
+ expect(@likeable.likers(@liker.class).count).to eq 1
133
+ @klass.remove_likers(@likeable)
134
+ expect(@likeable.likers(@liker.class).count).to eq 0
135
+ end
136
+ end
137
+
138
+ describe "#remove_likeables" do
139
+ it "deletes all likeables relationships for a liker" do
140
+ @liker.like!(@likeable)
141
+ expect(@liker.likeables(@likeable.class).count).to eq 1
142
+ @klass.remove_likeables(@liker)
143
+ expect(@liker.likeables(@likeable.class).count).to eq 0
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socialization::ActiveRecordStores::Mention do
4
+ before do
5
+ @klass = Socialization::ActiveRecordStores::Mention
6
+ @klass.touch nil
7
+ @klass.after_mention nil
8
+ @klass.after_unmention nil
9
+ @mentioner = ImAMentioner.create
10
+ @mentionable = ImAMentionable.create
11
+ end
12
+
13
+ describe "data store" do
14
+ it "inherits Socialization::ActiveRecordStores::Mention" do
15
+ expect(Socialization.mention_model).to eq Socialization::ActiveRecordStores::Mention
16
+ end
17
+ end
18
+
19
+ describe "#mention!" do
20
+ it "creates a Mention record" do
21
+ @klass.mention!(@mentioner, @mentionable)
22
+ expect(@mentioner).to match_mentioner(@klass.last)
23
+ expect(@mentionable).to match_mentionable(@klass.last)
24
+ end
25
+
26
+ it "increments counter caches" do
27
+ mentioner = ImAMentionerWithCounterCache.create
28
+ mentionable = ImAMentionableWithCounterCache.create
29
+ @klass.mention!(mentioner, mentionable)
30
+ expect(mentioner.reload.mentionees_count).to eq 1
31
+ expect(mentionable.reload.mentioners_count).to eq 1
32
+ end
33
+
34
+ it "touchs mentioner when instructed" do
35
+ @klass.touch :mentioner
36
+ expect(@mentioner).to receive(:touch).once
37
+ expect(@mentionable).to receive(:touch).never
38
+ @klass.mention!(@mentioner, @mentionable)
39
+ end
40
+
41
+ it "touchs mentionable when instructed" do
42
+ @klass.touch :mentionable
43
+ expect(@mentioner).to receive(:touch).never
44
+ expect(@mentionable).to receive(:touch).once
45
+ @klass.mention!(@mentioner, @mentionable)
46
+ end
47
+
48
+ it "touchs all when instructed" do
49
+ @klass.touch :all
50
+ expect(@mentioner).to receive(:touch).once
51
+ expect(@mentionable).to receive(:touch).once
52
+ @klass.mention!(@mentioner, @mentionable)
53
+ end
54
+
55
+ it "calls after mention hook" do
56
+ @klass.after_mention :after_mention
57
+ expect(@klass).to receive(:after_mention).once
58
+ @klass.mention!(@mentioner, @mentionable)
59
+ end
60
+
61
+ it "calls after unmention hook" do
62
+ @klass.after_mention :after_unmention
63
+ expect(@klass).to receive(:after_unmention).once
64
+ @klass.mention!(@mentioner, @mentionable)
65
+ end
66
+ end
67
+
68
+ describe "#unmention!" do
69
+ it "decrements counter caches" do
70
+ mentioner = ImAMentionerWithCounterCache.create
71
+ mentionable = ImAMentionableWithCounterCache.create
72
+ @klass.mention!(mentioner, mentionable)
73
+ @klass.unmention!(mentioner, mentionable)
74
+ expect(mentioner.reload.mentionees_count).to eq 0
75
+ expect(mentionable.reload.mentioners_count).to eq 0
76
+ end
77
+ end
78
+
79
+
80
+ describe "#mentions?" do
81
+ it "returns true when mention exists" do
82
+ @klass.create! do |f|
83
+ f.mentioner = @mentioner
84
+ f.mentionable = @mentionable
85
+ end
86
+ expect(@klass.mentions?(@mentioner, @mentionable)).to be true
87
+ end
88
+
89
+ it "returns false when mention doesn't exist" do
90
+ expect(@klass.mentions?(@mentioner, @mentionable)).to be false
91
+ end
92
+ end
93
+
94
+ describe "#mentioners" do
95
+ it "returns an array of mentioners" do
96
+ mentioner1 = ImAMentioner.create
97
+ mentioner2 = ImAMentioner.create
98
+ mentioner1.mention!(@mentionable)
99
+ mentioner2.mention!(@mentionable)
100
+ expect(@klass.mentioners(@mentionable, mentioner1.class)).to eq [mentioner1, mentioner2]
101
+ end
102
+
103
+ it "returns an array of mentioner ids when plucking" do
104
+ mentioner1 = ImAMentioner.create
105
+ mentioner2 = ImAMentioner.create
106
+ mentioner1.mention!(@mentionable)
107
+ mentioner2.mention!(@mentionable)
108
+ expect(@klass.mentioners(@mentionable, mentioner1.class, :pluck => :id)).to eq [mentioner1.id, mentioner2.id]
109
+ end
110
+ end
111
+
112
+ describe "#mentionables" do
113
+ it "returns an array of mentioners" do
114
+ mentionable1 = ImAMentionable.create
115
+ mentionable2 = ImAMentionable.create
116
+ @mentioner.mention!(mentionable1)
117
+ @mentioner.mention!(mentionable2)
118
+ expect(@klass.mentionables(@mentioner, mentionable1.class)).to eq [mentionable1, mentionable2]
119
+ end
120
+
121
+ it "returns an array of mentioner ids when plucking" do
122
+ mentionable1 = ImAMentionable.create
123
+ mentionable2 = ImAMentionable.create
124
+ @mentioner.mention!(mentionable1)
125
+ @mentioner.mention!(mentionable2)
126
+ expect(@klass.mentionables(@mentioner, mentionable1.class, :pluck => :id)).to eq [mentionable1.id, mentionable2.id]
127
+ end
128
+ end
129
+
130
+ describe "#remove_mentioners" do
131
+ it "deletes all mentioners relationships for a mentionable" do
132
+ @mentioner.mention!(@mentionable)
133
+ expect(@mentionable.mentioners(@mentioner.class).count).to eq 1
134
+ @klass.remove_mentioners(@mentionable)
135
+ expect(@mentionable.mentioners(@mentioner.class).count).to eq 0
136
+ end
137
+ end
138
+
139
+ describe "#remove_mentionables" do
140
+ it "deletes all mentionables relationships for a mentioner" do
141
+ @mentioner.mention!(@mentionable)
142
+ expect(@mentioner.mentionables(@mentionable.class).count).to eq 1
143
+ @klass.remove_mentionables(@mentioner)
144
+ expect(@mentioner.mentionables(@mentionable.class).count).to eq 0
145
+ end
146
+ end
147
+ end
148
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socialization::ActiveRecordStores::Mixins::Base do
4
+ describe ".update_counter" do
5
+ it "increments counter cache if column exists" do
6
+ followable = ImAFollowableWithCounterCache.create
7
+
8
+ update_counter(followable, followers_count: +1)
9
+
10
+ expect(followable.reload.followers_count).to eq(1)
11
+ end
12
+
13
+ it "does not raise any errors if column doesn't exist" do
14
+ followable = ImAFollowable.create
15
+ update_counter(followable, followers_count: +1)
16
+ end
17
+ end
18
+
19
+ def update_counter(model, counter)
20
+ klass = Object.new
21
+ klass.extend(Socialization::ActiveRecordStores::Mixins::Base)
22
+ klass.update_counter(model, counter)
23
+ end
24
+ end
25
+
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socialization::RedisStores::Base do
4
+ # Testing through RedisStores::Follow for easy testing
5
+ before(:each) do
6
+ use_redis_store
7
+ @klass = Socialization::RedisStores::Follow
8
+ @klass.touch nil
9
+ @klass.after_follow nil
10
+ @klass.after_unfollow nil
11
+ @follower1 = ImAFollower.create
12
+ @follower2 = ImAFollower.create
13
+ @followable1 = ImAFollowable.create
14
+ @followable2 = ImAFollowable.create
15
+ end
16
+
17
+ describe "RedisStores::Base through RedisStores::Follow" do
18
+ describe "Stores" do
19
+ it "inherits Socialization::RedisStores::Follow" do
20
+ expect(Socialization.follow_model).to eq(Socialization::RedisStores::Follow)
21
+ end
22
+ end
23
+
24
+ describe "#follow!" do
25
+ it "creates follow records" do
26
+ @klass.follow!(@follower1, @followable1)
27
+ expect(Socialization.redis.smembers(forward_key(@followable1))).to match_array ["#{@follower1.class}:#{@follower1.id}"]
28
+ expect(Socialization.redis.smembers(backward_key(@follower1))).to match_array ["#{@followable1.class}:#{@followable1.id}"]
29
+
30
+ @klass.follow!(@follower2, @followable1)
31
+ expect(Socialization.redis.smembers(forward_key(@followable1))).to match_array ["#{@follower1.class}:#{@follower1.id}", "#{@follower2.class}:#{@follower2.id}"]
32
+ expect(Socialization.redis.smembers(backward_key(@follower1))).to match_array ["#{@followable1.class}:#{@followable1.id}"]
33
+ expect(Socialization.redis.smembers(backward_key(@follower2))).to match_array ["#{@followable1.class}:#{@followable1.id}"]
34
+ end
35
+
36
+ it "touches follower when instructed" do
37
+ @klass.touch :follower
38
+ expect(@follower1).to receive(:touch).once
39
+ expect(@followable1).to receive(:touch).never
40
+ @klass.follow!(@follower1, @followable1)
41
+ end
42
+
43
+ it "touches followable when instructed" do
44
+ @klass.touch :followable
45
+ expect(@follower1).to receive(:touch).never
46
+ expect(@followable1).to receive(:touch).once
47
+ @klass.follow!(@follower1, @followable1)
48
+ end
49
+
50
+ it "touches all when instructed" do
51
+ @klass.touch :all
52
+ expect(@follower1).to receive(:touch).once
53
+ expect(@followable1).to receive(:touch).once
54
+ @klass.follow!(@follower1, @followable1)
55
+ end
56
+
57
+ it "calls after follow hook" do
58
+ @klass.after_follow :after_follow
59
+ expect(@klass).to receive(:after_follow).once
60
+ @klass.follow!(@follower1, @followable1)
61
+ end
62
+
63
+ it "calls after unfollow hook" do
64
+ @klass.after_follow :after_unfollow
65
+ expect(@klass).to receive(:after_unfollow).once
66
+ @klass.follow!(@follower1, @followable1)
67
+ end
68
+ end
69
+
70
+ describe "#unfollow!" do
71
+ before(:each) do
72
+ @klass.follow!(@follower1, @followable1)
73
+ end
74
+
75
+ it "removes follow records" do
76
+ @klass.unfollow!(@follower1, @followable1)
77
+ expect(Socialization.redis.smembers(forward_key(@followable1))).to be_empty
78
+ expect(Socialization.redis.smembers(backward_key(@follower1))).to be_empty
79
+ end
80
+ end
81
+
82
+ describe "#follows?" do
83
+ it "returns true when follow exists" do
84
+ @klass.follow!(@follower1, @followable1)
85
+ expect(@klass.follows?(@follower1, @followable1)).to be true
86
+ end
87
+
88
+ it "returns false when follow doesn't exist" do
89
+ expect(@klass.follows?(@follower1, @followable1)).to be false
90
+ end
91
+ end
92
+
93
+ describe "#followers" do
94
+ it "returns an array of followers" do
95
+ follower1 = ImAFollower.create
96
+ follower2 = ImAFollower.create
97
+ follower1.follow!(@followable1)
98
+ follower2.follow!(@followable1)
99
+ expect(@klass.followers(@followable1, follower1.class)).to match_array [follower1, follower2]
100
+ end
101
+
102
+ it "returns an array of follower ids when plucking" do
103
+ follower1 = ImAFollower.create
104
+ follower2 = ImAFollower.create
105
+ follower1.follow!(@followable1)
106
+ follower2.follow!(@followable1)
107
+ expect(@klass.followers(@followable1, follower1.class, :pluck => :id)).to match_array ["#{follower1.id}", "#{follower2.id}"]
108
+ end
109
+ end
110
+
111
+ describe "#followables" do
112
+ it "returns an array of followables" do
113
+ followable1 = ImAFollowable.create
114
+ followable2 = ImAFollowable.create
115
+ @follower1.follow!(followable1)
116
+ @follower1.follow!(followable2)
117
+
118
+ expect(@klass.followables(@follower1, followable1.class)).to match_array [followable1, followable2]
119
+ end
120
+
121
+ it "returns an array of followables ids when plucking" do
122
+ followable1 = ImAFollowable.create
123
+ followable2 = ImAFollowable.create
124
+ @follower1.follow!(followable1)
125
+ @follower1.follow!(followable2)
126
+ expect(@klass.followables(@follower1, followable1.class, :pluck => :id)).to match_array ["#{followable1.id}", "#{followable2.id}"]
127
+ end
128
+ end
129
+
130
+ describe "#generate_forward_key" do
131
+ it "returns valid key when passed an object" do
132
+ expect(forward_key(@followable1)).to eq("Followers:#{@followable1.class.name}:#{@followable1.id}")
133
+ end
134
+
135
+ it "returns valid key when passed a String" do
136
+ expect(forward_key("Followable:1")).to eq("Followers:Followable:1")
137
+ end
138
+ end
139
+
140
+ describe "#generate_backward_key" do
141
+ it "returns valid key when passed an object" do
142
+ expect(backward_key(@follower1)).to eq("Followables:#{@follower1.class.name}:#{@follower1.id}")
143
+ end
144
+
145
+ it "returns valid key when passed a String" do
146
+ expect(backward_key("Follower:1")).to eq("Followables:Follower:1")
147
+ end
148
+ end
149
+
150
+ describe "#remove_followers" do
151
+ it "deletes all followers relationships for a followable" do
152
+ @follower1.follow!(@followable1)
153
+ @follower2.follow!(@followable1)
154
+ expect(@followable1.followers(@follower1.class).count).to eq(2)
155
+
156
+ @klass.remove_followers(@followable1)
157
+ expect(@followable1.followers(@follower1.class).count).to eq(0)
158
+ expect(Socialization.redis.smembers(forward_key(@followable1))).to be_empty
159
+ expect(Socialization.redis.smembers(backward_key(@follower1))).to be_empty
160
+ expect(Socialization.redis.smembers(backward_key(@follower2))).to be_empty
161
+ end
162
+ end
163
+
164
+ describe "#remove_followables" do
165
+ it "deletes all followables relationships for a follower" do
166
+ @follower1.follow!(@followable1)
167
+ @follower1.follow!(@followable2)
168
+ expect(@follower1.followables(@followable1.class).count).to eq(2)
169
+
170
+ @klass.remove_followables(@follower1)
171
+ expect(@follower1.followables(@followable1.class).count).to eq(0)
172
+ expect(Socialization.redis.smembers backward_key(@followable1)).to be_empty
173
+ expect(Socialization.redis.smembers backward_key(@follower2)).to be_empty
174
+ expect(Socialization.redis.smembers forward_key(@follower1)).to be_empty
175
+ end
176
+ end
177
+
178
+ describe "#key_type_to_type_names" do
179
+ it "returns the proper arrays" do
180
+ expect(@klass.send(:key_type_to_type_names, Socialization::RedisStores::Follow)).to eq(['follower', 'followable'])
181
+ expect(@klass.send(:key_type_to_type_names, Socialization::RedisStores::Mention)).to eq(['mentioner', 'mentionable'])
182
+ expect(@klass.send(:key_type_to_type_names, Socialization::RedisStores::Like)).to eq(['liker', 'likeable'])
183
+ end
184
+ end
185
+ end
186
+
187
+ # Helpers
188
+ def forward_key(followable)
189
+ Socialization::RedisStores::Follow.send(:generate_forward_key, followable)
190
+ end
191
+
192
+ def backward_key(follower)
193
+ Socialization::RedisStores::Follow.send(:generate_backward_key, follower)
194
+ end
195
+ end