socialization 0.5.0.beta3 → 0.5.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.follow_model.remove_followables(self) }
16
+
15
17
  # Specifies if self can follow {Followable} objects.
16
18
  #
17
19
  # @return [Boolean]
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.like_model.remove_likeables(self) }
16
+
15
17
  # Specifies if self can like {Likeable} objects.
16
18
  #
17
19
  # @return [Boolean]
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.mention_model.remove_mentionables(self) }
16
+
15
17
  # Specifies if self can mention {Mentionable} objects.
16
18
  #
17
19
  # @return [Boolean]
@@ -98,6 +98,18 @@ module Socialization
98
98
  end
99
99
  end
100
100
 
101
+ # Remove all the followers for followable
102
+ def remove_followers(followable)
103
+ self.where(:followable_type => followable.class.name.classify).
104
+ where(:followable_id => followable.id).destroy_all
105
+ end
106
+
107
+ # Remove all the followables for follower
108
+ def remove_followables(follower)
109
+ self.where(:follower_type => follower.class.name.classify).
110
+ where(:follower_id => follower.id).destroy_all
111
+ end
112
+
101
113
  private
102
114
  def follow_for(follower, followable)
103
115
  followed_by(follower).following(followable)
@@ -98,6 +98,18 @@ module Socialization
98
98
  end
99
99
  end
100
100
 
101
+ # Remove all the likers for likeable
102
+ def remove_likers(likeable)
103
+ self.where(:likeable_type => likeable.class.name.classify).
104
+ where(:likeable_id => likeable.id).destroy_all
105
+ end
106
+
107
+ # Remove all the likeables for liker
108
+ def remove_likeables(liker)
109
+ self.where(:liker_type => liker.class.name.classify).
110
+ where(:liker_id => liker.id).destroy_all
111
+ end
112
+
101
113
  private
102
114
  def like_for(liker, likeable)
103
115
  liked_by(liker).liking( likeable)
@@ -98,6 +98,18 @@ module Socialization
98
98
  end
99
99
  end
100
100
 
101
+ # Remove all the mentioners for mentionable
102
+ def remove_mentioners(mentionable)
103
+ self.where(:mentionable_type => mentionable.class.name.classify).
104
+ where(:mentionable_id => mentionable.id).destroy_all
105
+ end
106
+
107
+ # Remove all the mentionables for mentioner
108
+ def remove_mentionables(mentioner)
109
+ self.where(:mentioner_type => mentioner.class.name.classify).
110
+ where(:mentioner_id => mentioner.id).destroy_all
111
+ end
112
+
101
113
  private
102
114
  def mention_for(mentioner, mentionable)
103
115
  mentioned_by(mentioner).mentioning(mentionable)
@@ -1,6 +1,123 @@
1
1
  module Socialization
2
2
  module RedisStores
3
3
  class Base
4
- end
5
- end
6
- end
4
+
5
+ class << self
6
+ protected
7
+ def actors(victim, klass, options = {})
8
+ if options[:pluck]
9
+ Socialization.redis.smembers(generate_forward_key(victim)).inject([]) do |result, element|
10
+ result << element.match(/\:(\d+)$/)[1] if element.match(/^#{klass}\:/)
11
+ end
12
+ else
13
+ actors_relation(victim, klass, options).all
14
+ end
15
+ end
16
+
17
+ def actors_relation(victim, klass, options = {})
18
+ ids = actors(victim, klass, :pluck => :id)
19
+ klass.where("#{klass.table_name}.id IN (?)", ids)
20
+ end
21
+
22
+ def victims_relation(actor, klass, options = {})
23
+ ids = victims(actor, klass, :pluck => :id)
24
+ klass.where("#{klass.table_name}.id IN (?)", ids)
25
+ end
26
+
27
+ def victims(actor, klass, options = {})
28
+ if options[:pluck]
29
+ Socialization.redis.smembers(generate_backward_key(actor)).inject([]) do |result, element|
30
+ result << element.match(/\:(\d+)$/)[1] if element.match(/^#{klass}\:/)
31
+ end
32
+ else
33
+ victims_relation(actor, klass, options).all
34
+ end
35
+ end
36
+
37
+ def relation!(actor, victim, options = {})
38
+ unless options[:skip_check] || relation?(actor, victim)
39
+ Socialization.redis.sadd generate_forward_key(victim), generate_redis_value(actor)
40
+ Socialization.redis.sadd generate_backward_key(actor), generate_redis_value(victim)
41
+ call_after_create_hooks(actor, victim)
42
+ true
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ def unrelation!(actor, victim, options = {})
49
+ if options[:skip_check] || relation?(actor, victim)
50
+ Socialization.redis.srem generate_forward_key(victim), generate_redis_value(actor)
51
+ Socialization.redis.srem generate_backward_key(actor), generate_redis_value(victim)
52
+ call_after_destroy_hooks(actor, victim)
53
+ true
54
+ else
55
+ false
56
+ end
57
+ end
58
+
59
+ def relation?(actor, victim)
60
+ Socialization.redis.sismember generate_forward_key(victim), generate_redis_value(actor)
61
+ end
62
+
63
+ def remove_actor_relations(victim)
64
+ forward_key = generate_forward_key(victim)
65
+ actors = Socialization.redis.smembers forward_key
66
+ Socialization.redis.del forward_key
67
+ actors.each do |actor|
68
+ Socialization.redis.srem generate_backward_key(actor), generate_redis_value(victim)
69
+ end
70
+ true
71
+ end
72
+
73
+ def remove_victim_relations(actor)
74
+ backward_key = generate_backward_key(actor)
75
+ victims = Socialization.redis.smembers backward_key
76
+ Socialization.redis.del backward_key
77
+ victims.each do |victim|
78
+ Socialization.redis.srem generate_forward_key(victim), generate_redis_value(actor)
79
+ end
80
+ true
81
+ end
82
+
83
+
84
+ private
85
+ def key_type_to_type_names(klass)
86
+ if klass.name.match(/Follow$/)
87
+ ['follower', 'followable']
88
+ elsif klass.name.match(/Like$/)
89
+ ['liker', 'likeable']
90
+ elsif klass.name.match(/Mention$/)
91
+ ['mentioner', 'mentionable']
92
+ else
93
+ raise ArgumentError.new("Can't find matching type for #{klass}.")
94
+ end
95
+ end
96
+
97
+ def generate_forward_key(victim)
98
+ keys = key_type_to_type_names(self)
99
+ if victim.is_a?(String)
100
+ "#{keys[0].pluralize.capitalize}:#{victim}"
101
+ else
102
+ "#{keys[0].pluralize.capitalize}:#{victim.class}:#{victim.id}"
103
+ end
104
+ end
105
+
106
+ def generate_backward_key(actor)
107
+ keys = key_type_to_type_names(self)
108
+ if actor.is_a?(String)
109
+ "#{keys[1].pluralize.capitalize}:#{actor}"
110
+ else
111
+ "#{keys[1].pluralize.capitalize}:#{actor.class}:#{actor.id}"
112
+ end
113
+ end
114
+
115
+ def generate_redis_value(obj)
116
+ "#{obj.class.name}:#{obj.id}"
117
+ end
118
+
119
+ end # class << self
120
+
121
+ end # Base
122
+ end # RedisStores
123
+ end # Socialization
@@ -1,5 +1,3 @@
1
- # require File.expand_path(File.dirname(__FILE__)) + '/base'
2
-
3
1
  module Socialization
4
2
  module RedisStores
5
3
  class Follow < Socialization::RedisStores::Base
@@ -8,91 +6,16 @@ module Socialization
8
6
  extend Socialization::RedisStores::Mixins::Base
9
7
 
10
8
  class << self
11
- def follow!(follower, followable)
12
- unless follows?(follower, followable)
13
- Socialization.redis.sadd generate_followers_key(follower, followable), follower.id
14
- Socialization.redis.sadd generate_followables_key(follower, followable), followable.id
15
-
16
- call_after_create_hooks(follower, followable)
17
- true
18
- else
19
- false
20
- end
21
- end
22
-
23
- def unfollow!(follower, followable)
24
- if follows?(follower, followable)
25
- Socialization.redis.srem generate_followers_key(follower, followable), follower.id
26
- Socialization.redis.srem generate_followables_key(follower, followable), followable.id
27
-
28
- call_after_destroy_hooks(follower, followable)
29
- true
30
- else
31
- false
32
- end
33
- end
34
-
35
- def follows?(follower, followable)
36
- Socialization.redis.sismember generate_followers_key(follower, followable), follower.id
37
- end
38
-
39
- # Returns an ActiveRecord::Relation of all the followers of a certain type that are following followable
40
- def followers_relation(followable, klass, opts = {})
41
- ids = followers(followable, klass, :pluck => :id)
42
- klass.where('id IN (?)', ids)
43
- end
44
-
45
- # Returns all the followers of a certain type that are following followable
46
- def followers(followable, klass, opts = {})
47
- if opts[:pluck]
48
- Socialization.redis.smembers(generate_followers_key(klass, followable)).map { |id|
49
- id.to_i if id.is_integer?
50
- }
51
- else
52
- followers_relation(followable, klass, opts).all
53
- end
54
- end
55
-
56
- # Returns an ActiveRecord::Relation of all the followables of a certain type that are followed by follower
57
- def followables_relation(follower, klass, opts = {})
58
- ids = followables(follower, klass, :pluck => :id)
59
- klass.where('id IN (?)', ids)
60
- end
61
-
62
- # Returns all the followables of a certain type that are followed by follower
63
- def followables(follower, klass, opts = {})
64
- if opts[:pluck]
65
- Socialization.redis.smembers(generate_followables_key(follower, klass)).map { |id|
66
- id.to_i if id.is_integer?
67
- }
68
- else
69
- followables_relation(follower, klass, opts).all
70
- end
71
- end
72
-
73
- private
74
- def generate_followers_key(follower, followable)
75
- raise ArgumentError.new("`followable` needs to be an acts_as_followable objecs, not a class.") if followable.class == Class
76
- follower_class = if follower.class == Class
77
- follower
78
- else
79
- follower.class
80
- end
81
-
82
- "Followers:#{followable.class}:#{followable.id}:#{follower_class}"
83
- end
84
-
85
- def generate_followables_key(follower, followable)
86
- raise ArgumentError.new("`follower` needs to be an acts_as_follower object, not a class.") if follower.class == Class
87
- followable_class = if followable.class == Class
88
- followable
89
- else
90
- followable.class
91
- end
92
-
93
- "Followables:#{follower.class}:#{follower.id}:#{followable_class}"
94
- end
95
- end # class << self
9
+ alias_method :follow!, :relation!; public :follow!
10
+ alias_method :unfollow!, :unrelation!; public :unfollow!
11
+ alias_method :follows?, :relation?; public :follows?
12
+ alias_method :followers_relation, :actors_relation; public :followers_relation
13
+ alias_method :followers, :actors; public :followers
14
+ alias_method :followables_relation, :victims_relation; public :followables_relation
15
+ alias_method :followables, :victims; public :followables
16
+ alias_method :remove_followers, :remove_actor_relations; public :remove_followers
17
+ alias_method :remove_followables, :remove_victim_relations; public :remove_followables
18
+ end
96
19
 
97
20
  end
98
21
  end
@@ -1,5 +1,3 @@
1
- # require File.expand_path(File.dirname(__FILE__)) + '/base'
2
-
3
1
  module Socialization
4
2
  module RedisStores
5
3
  class Like < Socialization::RedisStores::Base
@@ -8,122 +6,16 @@ module Socialization
8
6
  extend Socialization::RedisStores::Mixins::Base
9
7
 
10
8
  class << self
11
- def like!(liker, likeable)
12
- unless likes?(liker, likeable)
13
- Socialization.redis.sadd generate_likers_key(liker, likeable), liker.id
14
- Socialization.redis.sadd generate_likeables_key(liker, likeable), likeable.id
15
-
16
- call_after_create_hooks(liker, likeable)
17
- liker.touch if [:all, :liker].include?(touch) && liker.respond_to?(:touch)
18
- likeable.touch if [:all, :likeable].include?(touch) && likeable.respond_to?(:touch)
19
- true
20
- else
21
- false
22
- end
23
- end
24
-
25
- def unlike!(liker, likeable)
26
- if likes?(liker, likeable)
27
- Socialization.redis.srem generate_likers_key(liker, likeable), liker.id
28
- Socialization.redis.srem generate_likeables_key(liker, likeable), likeable.id
29
-
30
- call_after_destroy_hooks(liker, likeable)
31
- liker.touch if [:all, :liker].include?(touch) && liker.respond_to?(:touch)
32
- likeable.touch if [:all, :likeable].include?(touch) && likeable.respond_to?(:touch)
33
- true
34
- else
35
- false
36
- end
37
- end
38
-
39
- def likes?(liker, likeable)
40
- Socialization.redis.sismember generate_likers_key(liker, likeable), liker.id
41
- end
42
-
43
- # Returns an ActiveRecord::Relation of all the likers of a certain type that are likeing likeable
44
- def likers_relation(likeable, klass, opts = {})
45
- ids = likers(likeable, klass, :pluck => :id)
46
- klass.where('id IN (?)', ids)
47
- end
48
-
49
- # Returns all the likers of a certain type that are likeing likeable
50
- def likers(likeable, klass, opts = {})
51
- if opts[:pluck]
52
- Socialization.redis.smembers(generate_likers_key(klass, likeable)).map { |id|
53
- id.to_i if id.is_integer?
54
- }
55
- else
56
- likers_relation(likeable, klass, opts).all
57
- end
58
- end
59
-
60
- # Returns an ActiveRecord::Relation of all the likeables of a certain type that are liked by liker
61
- def likeables_relation(liker, klass, opts = {})
62
- ids = likeables(liker, klass, :pluck => :id)
63
- klass.where('id IN (?)', ids)
64
- end
65
-
66
- # Returns all the likeables of a certain type that are liked by liker
67
- def likeables(liker, klass, opts = {})
68
- if opts[:pluck]
69
- Socialization.redis.smembers(generate_likeables_key(liker, klass)).map { |id|
70
- id.to_i if id.is_integer?
71
- }
72
- else
73
- likeables_relation(liker, klass, opts).all
74
- end
75
- end
76
-
77
- def touch(what = nil)
78
- if what.nil?
79
- @touch || false
80
- else
81
- raise ArgumentError unless [:all, :liker, :likeable, false, nil].include?(what)
82
- @touch = what
83
- end
84
- end
85
-
86
- def after_like(method)
87
- raise ArgumentError unless method.is_a?(Symbol) || method.nil?
88
- @after_create_hook = method
89
- end
90
-
91
- def after_unlike(method)
92
- raise ArgumentError unless method.is_a?(Symbol) || method.nil?
93
- @after_destroy_hook = method
94
- end
95
-
96
- private
97
- def call_after_create_hooks(liker, likeable)
98
- self.send(@after_create_hook, liker, likeable) if @after_create_hook
99
- end
100
-
101
- def call_after_destroy_hooks(liker, likeable)
102
- self.send(@after_destroy_hook, liker, likeable) if @after_destroy_hook
103
- end
104
-
105
- def generate_likers_key(liker, likeable)
106
- raise ArgumentError.new("`likeable` needs to be an acts_as_likeable objecs, not a class.") if likeable.class == Class
107
- liker_class = if liker.class == Class
108
- liker
109
- else
110
- liker.class
111
- end
112
-
113
- "Likers:#{likeable.class}:#{likeable.id}:#{liker_class}"
114
- end
115
-
116
- def generate_likeables_key(liker, likeable)
117
- raise ArgumentError.new("`liker` needs to be an acts_as_liker object, not a class.") if liker.class == Class
118
- likeable_class = if likeable.class == Class
119
- likeable
120
- else
121
- likeable.class
122
- end
123
-
124
- "Likeables:#{liker.class}:#{liker.id}:#{likeable_class}"
125
- end
126
- end # class << self
9
+ alias_method :like!, :relation!; public :like!
10
+ alias_method :unlike!, :unrelation!; public :unlike!
11
+ alias_method :likes?, :relation?; public :likes?
12
+ alias_method :likers_relation, :actors_relation; public :likers_relation
13
+ alias_method :likers, :actors; public :likers
14
+ alias_method :likeables_relation, :victims_relation; public :likeables_relation
15
+ alias_method :likeables, :victims; public :likeables
16
+ alias_method :remove_likers, :remove_actor_relations; public :remove_likers
17
+ alias_method :remove_likeables, :remove_victim_relations; public :remove_likeables
18
+ end
127
19
 
128
20
  end
129
21
  end
@@ -1,5 +1,3 @@
1
- # require File.expand_path(File.dirname(__FILE__)) + '/base'
2
-
3
1
  module Socialization
4
2
  module RedisStores
5
3
  class Mention < Socialization::RedisStores::Base
@@ -8,91 +6,16 @@ module Socialization
8
6
  extend Socialization::RedisStores::Mixins::Base
9
7
 
10
8
  class << self
11
- def mention!(mentioner, mentionable)
12
- unless mentions?(mentioner, mentionable)
13
- Socialization.redis.sadd generate_mentioners_key(mentioner, mentionable), mentioner.id
14
- Socialization.redis.sadd generate_mentionables_key(mentioner, mentionable), mentionable.id
15
-
16
- call_after_create_hooks(mentioner, mentionable)
17
- true
18
- else
19
- false
20
- end
21
- end
22
-
23
- def unmention!(mentioner, mentionable)
24
- if mentions?(mentioner, mentionable)
25
- Socialization.redis.srem generate_mentioners_key(mentioner, mentionable), mentioner.id
26
- Socialization.redis.srem generate_mentionables_key(mentioner, mentionable), mentionable.id
27
-
28
- call_after_destroy_hooks(mentioner, mentionable)
29
- true
30
- else
31
- false
32
- end
33
- end
34
-
35
- def mentions?(mentioner, mentionable)
36
- Socialization.redis.sismember generate_mentioners_key(mentioner, mentionable), mentioner.id
37
- end
38
-
39
- # Returns an ActiveRecord::Relation of all the mentioners of a certain type that are mentioning mentionable
40
- def mentioners_relation(mentionable, klass, opts = {})
41
- ids = mentioners(mentionable, klass, :pluck => :id)
42
- klass.where('id IN (?)', ids)
43
- end
44
-
45
- # Returns all the mentioners of a certain type that are mentioning mentionable
46
- def mentioners(mentionable, klass, opts = {})
47
- if opts[:pluck]
48
- Socialization.redis.smembers(generate_mentioners_key(klass, mentionable)).map { |id|
49
- id.to_i if id.is_integer?
50
- }
51
- else
52
- mentioners_relation(mentionable, klass, opts).all
53
- end
54
- end
55
-
56
- # Returns an ActiveRecord::Relation of all the mentionables of a certain type that are mentioned by mentioner
57
- def mentionables_relation(mentioner, klass, opts = {})
58
- ids = mentionables(mentioner, klass, :pluck => :id)
59
- klass.where('id IN (?)', ids)
60
- end
61
-
62
- # Returns all the mentionables of a certain type that are mentioned by mentioner
63
- def mentionables(mentioner, klass, opts = {})
64
- if opts[:pluck]
65
- Socialization.redis.smembers(generate_mentionables_key(mentioner, klass)).map { |id|
66
- id.to_i if id.is_integer?
67
- }
68
- else
69
- mentionables_relation(mentioner, klass, opts).all
70
- end
71
- end
72
-
73
- private
74
- def generate_mentioners_key(mentioner, mentionable)
75
- raise ArgumentError.new("`mentionable` needs to be an acts_as_mentionable objecs, not a class.") if mentionable.class == Class
76
- mentioner_class = if mentioner.class == Class
77
- mentioner
78
- else
79
- mentioner.class
80
- end
81
-
82
- "Mentioners:#{mentionable.class}:#{mentionable.id}:#{mentioner_class}"
83
- end
84
-
85
- def generate_mentionables_key(mentioner, mentionable)
86
- raise ArgumentError.new("`mentioner` needs to be an acts_as_mentioner object, not a class.") if mentioner.class == Class
87
- mentionable_class = if mentionable.class == Class
88
- mentionable
89
- else
90
- mentionable.class
91
- end
92
-
93
- "Mentionables:#{mentioner.class}:#{mentioner.id}:#{mentionable_class}"
94
- end
95
- end # class << self
9
+ alias_method :mention!, :relation!; public :mention!
10
+ alias_method :unmention!, :unrelation!; public :unmention!
11
+ alias_method :mentions?, :relation?; public :mentions?
12
+ alias_method :mentioners_relation, :actors_relation; public :mentioners_relation
13
+ alias_method :mentioners, :actors; public :mentioners
14
+ alias_method :mentionables_relation, :victims_relation; public :mentionables_relation
15
+ alias_method :mentionables, :victims; public :mentionables
16
+ alias_method :remove_mentioners, :remove_actor_relations; public :remove_mentioners
17
+ alias_method :remove_mentionables, :remove_victim_relations; public :remove_mentionables
18
+ end
96
19
 
97
20
  end
98
21
  end
@@ -1,3 +1,3 @@
1
1
  module Socialization
2
- VERSION = "0.5.0.beta3"
2
+ VERSION = "0.5.0.beta4"
3
3
  end
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.follow_model.remove_followers(self) }
16
+
15
17
  # Specifies if self can be followed.
16
18
  #
17
19
  # @return [Boolean]
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.like_model.remove_likers(self) }
16
+
15
17
  # Specifies if self can be liked.
16
18
  #
17
19
  # @return [Boolean]
@@ -12,6 +12,8 @@ module Socialization
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
+ after_destroy { Socialization.mention_model.remove_mentioners(self) }
16
+
15
17
  # Specifies if self can be mentioned.
16
18
  #
17
19
  # @return [Boolean]
@@ -98,5 +98,17 @@ class FollowerTest < Test::Unit::TestCase
98
98
  end
99
99
  end
100
100
 
101
+ context "deleting a follower" do
102
+ setup do
103
+ @follower = ImAFollower.create
104
+ @follower.follow!(@followable)
105
+ end
106
+
107
+ should "remove follow relationships" do
108
+ Socialization.follow_model.expects(:remove_followables).with(@follower)
109
+ @follower.destroy
110
+ end
111
+ end
112
+
101
113
  end
102
114
  end
@@ -98,5 +98,9 @@ class LikerTest < Test::Unit::TestCase
98
98
  end
99
99
  end
100
100
 
101
+ should "remove like relationships" do
102
+ Socialization.like_model.expects(:remove_likeables).with(@liker)
103
+ @liker.destroy
104
+ end
101
105
  end
102
106
  end
@@ -97,5 +97,10 @@ class MentionerTest < Test::Unit::TestCase
97
97
  @mentioner.mentionees_relation(@mentionable.class, { :foo => :bar })
98
98
  end
99
99
  end
100
+
101
+ should "remove mention relationships" do
102
+ Socialization.mention_model.expects(:remove_mentionables).with(@mentioner)
103
+ @mentioner.destroy
104
+ end
100
105
  end
101
106
  end
@@ -108,6 +108,23 @@ class ActiveRecordFollowStoreTest < Test::Unit::TestCase
108
108
  end
109
109
  end
110
110
 
111
+ context "#remove_followers" do
112
+ should "delete all followers relationships for a followable" do
113
+ @follower.follow!(@followable)
114
+ assert_equal 1, @followable.followers(@follower.class).count
115
+ @klass.remove_followers(@followable)
116
+ assert_equal 0, @followable.followers(@follower.class).count
117
+ end
118
+ end
119
+
120
+ context "#remove_followables" do
121
+ should "delete all followables relationships for a follower" do
122
+ @follower.follow!(@followable)
123
+ assert_equal 1, @follower.followables(@followable.class).count
124
+ @klass.remove_followables(@follower)
125
+ assert_equal 0, @follower.followables(@followable.class).count
126
+ end
127
+ end
111
128
  end
112
129
 
113
130
  # Helpers