mongo_followable 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -9,29 +9,33 @@ In console:
9
9
  or in Gemfile:
10
10
  gem 'mongo_followable'
11
11
 
12
+ == Notice
13
+
14
+ Please read following documentation first. Since 0.3.2, some apis have been changed. Sorry for the inconvenience.
15
+
16
+ If you want to remove `follow_history` and `followed_history` fields totally from your database after you decide not to use follow/followed history feature, do this:
17
+
18
+ # in the rails console, taking user as an example:
19
+ User.all.each { |u| u.unset(:follow_history) } # this will remove the follow_history field
20
+
12
21
  == Usage
13
22
 
14
23
  To make model followable you need to include Mongo::Followable into your model; You also need to include Mongo::Follower in your follower model:
15
24
  class User
16
25
  include Mongoid::Document #for Mongo_Mapper users, this line of code should be include MongoMapper::Document
17
- include Mongo::Followable
18
- include Mongo::Follower
26
+ include Mongo::Followable::Followed
27
+ include Mongo::Followable::Follower
28
+ include Mongo::Followable::History # you have to add this line to enable follow/followed history
19
29
  end
20
30
 
21
31
  class Group
22
32
  include Mongoid::Document #for Mongo_Mapper users, this line of code should be include MongoMapper::Document
23
- include Mongo::Followable
33
+ include Mongo::Followable::Followed
34
+ include Mongo::Followable::History # you have to add this line to enable follow/followed history
24
35
  end
25
36
 
26
- Now you can set configuration for mongo_followable in environment/*.rb:
27
-
28
- # Note: for current version, you can only set the config once(first time the application is created).
29
- # This should be fixed in next version.
30
- config.mongo_followable = { :authorization => false, :history => false } # this is default value
31
-
32
- Now you can set authorization:
33
- current_user.set_authorization('user', 'game') # now current_user cannot follow User and Game model
34
- current_user.unset_authorization('User', 'Game')
37
+ I've decided to remove authorization because it is quite inefficient to keep this field for every record in the database.
38
+ However, it's possible that I'll add it back as a plugin in the future.
35
39
 
36
40
  And then you can follow and unfollow:
37
41
 
@@ -104,6 +108,20 @@ You can also get a model's follow/followed history:
104
108
  @user.ever_follow
105
109
  @group.ever_followed
106
110
 
111
+ or to tell if ever follow/followed by someone:
112
+
113
+ @user.ever_follow? @some_group
114
+ @group.ever_followed? @some_user
115
+
116
+ Sure you can clear the histories:
117
+
118
+ @user.clear_history!
119
+
120
+ #or more specific:
121
+
122
+ @user.clear_follow_history!
123
+ @group.clear_followed_history!
124
+
107
125
  Another feature is to get a list of models which has the most followers/followees:
108
126
 
109
127
  User.with_max_followees
@@ -126,7 +144,7 @@ And see what the common followers/followees are:
126
144
  @user.common_followers_with(@group)
127
145
 
128
146
  * Any bug or issue, please send me an email: ustc.flyingfox@gmail.com
129
-
147
+ include Mongo::Followable::History # you have to add this line to enable follow/followed history
130
148
  == TODO
131
149
 
132
150
  * inter-models followable #FINISHED#
@@ -136,6 +154,7 @@ And see what the common followers/followees are:
136
154
  * add authorization to followable models #FINISHED#
137
155
  * common followers/followees #FINISHED#
138
156
  * add support for mongo_mapper in next version #FINISHED#
157
+ * implement plugins: confirmation, authorization etc.
139
158
 
140
159
  !!If you have any advice, plese do not hesitate to tell me!!
141
160
 
@@ -1,10 +1,7 @@
1
- if defined?(Rails)
2
- require File.join(File.dirname(__FILE__), "mongo_followable/railtie")
3
- end
4
-
5
1
  if defined?(Mongoid) or defined?(MongoMapper)
6
2
  require File.join(File.dirname(__FILE__), "mongo_followable/core_ext/string")
7
- require File.join(File.dirname(__FILE__), "mongo_followable/followable")
3
+ require File.join(File.dirname(__FILE__), "mongo_followable/followed")
8
4
  require File.join(File.dirname(__FILE__), "mongo_followable/follower")
9
5
  require File.join(File.dirname(__FILE__), "../app/models/follow")
6
+ require File.join(File.dirname(__FILE__), "mongo_followable/features/history")
10
7
  end
@@ -0,0 +1,5 @@
1
+ module Mongo
2
+ module Authorization
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Mongo
2
+ module Confirmation
3
+
4
+ end
5
+ end
@@ -0,0 +1,76 @@
1
+ module Mongo
2
+ module Followable
3
+ module History
4
+ extend ActiveSupport::Concern
5
+
6
+ included do |base|
7
+ if base.include?(Mongo::Followable::Follower)
8
+ if defined?(Mongoid)
9
+ base.field :follow_history, :type => Array, :default => []
10
+ elsif defined?(MongoMapper)
11
+ base.key :follow_history, :type => Array, :default => []
12
+ end
13
+ end
14
+
15
+ if base.include?(Mongo::Followable::Followed)
16
+ if defined?(Mongoid)
17
+ base.field :followed_history, :type => Array, :default => []
18
+ elsif defined?(MongoMapper)
19
+ base.key :followed_history, :type => Array, :default => []
20
+ end
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ # def clear_history!
26
+ # self.all.each { |m| m.unset(:follow_history) }
27
+ # self.all.each { |m| m.unset(:followed_history) }
28
+ # end
29
+ end
30
+
31
+ def clear_history!
32
+ clear_follow_history!
33
+ clear_followed_histroy!
34
+ end
35
+
36
+ def clear_follow_history!
37
+ self.update_attribute(:follow_history, []) if has_follow_history?
38
+ end
39
+
40
+ def clear_followed_histroy!
41
+ self.update_attribute(:followed_history, []) if has_followed_history?
42
+ end
43
+
44
+ def ever_follow
45
+ rebuild(self.follow_history) if has_follow_history?
46
+ end
47
+
48
+ def ever_followed
49
+ rebuild(self.followed_history) if has_followed_history?
50
+ end
51
+
52
+ def ever_follow?(model)
53
+ self.follow_history.include?(model.class.name + "_" + model.id.to_s) if has_follow_history?
54
+ end
55
+
56
+ def ever_followed?(model)
57
+ self.followed_history.include?(model.class.name + "_" + model.id.to_s) if has_followed_history?
58
+ end
59
+
60
+ private
61
+ def has_follow_history?
62
+ self.respond_to? :follow_history
63
+ end
64
+
65
+ def has_followed_history?
66
+ self.respond_to? :followed_history
67
+ end
68
+
69
+ def rebuild(ary)
70
+ ary.group_by { |x| x.split("_").first }.
71
+ inject([]) { |n,(k,v)| n += k.constantize.
72
+ find(v.map { |x| x.split("_").last}) }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,193 @@
1
+ module Mongo
2
+ module Followable
3
+ module Followed
4
+ extend ActiveSupport::Concern
5
+
6
+ included do |base|
7
+ if defined?(Mongoid)
8
+ base.has_many :followers, :class_name => "Follow", :as => :followable, :dependent => :destroy
9
+ elsif defined?(MongoMapper)
10
+ base.many :followers, :class_name => "Follow", :as => :followable, :dependent => :destroy
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ # get certain model's followees of this type
17
+ #
18
+ # Example:
19
+ # >> @jim = User.new
20
+ # >> @ruby = Group.new
21
+ # >> @jim.save
22
+ # >> @ruby.save
23
+ #
24
+ # >> @jim.follow(@ruby)
25
+ # >> User.followees_of(@jim)
26
+ # => [@ruby]
27
+ #
28
+ # Arguments:
29
+ # model: instance of some followable model
30
+
31
+ def followees_of(model)
32
+ model.followees_by_type(self.name)
33
+ end
34
+
35
+ # 4 methods in this function
36
+ #
37
+ # Example:
38
+ # >> Group.with_max_followers
39
+ # => [@ruby]
40
+ # >> Group.with_max_followers_by_type('user')
41
+ # => [@ruby]
42
+
43
+ ["max", "min"].each do |s|
44
+ define_method(:"with_#{s}_followers") do
45
+ follow_array = self.all.to_a.sort! { |a, b| a.followers_count <=> b.followers_count }
46
+ num = follow_array[-1].followers_count
47
+ follow_array.select { |c| c.followers_count == num }
48
+ end
49
+
50
+ define_method(:"with_#{s}_followers_by_type") do |*args|
51
+ follow_array = self.all.to_a.sort! { |a, b| a.followers_count_by_type(args[0]) <=> b.followers_count_by_type(args[0]) }
52
+ num = follow_array[-1].followers_count_by_type(args[0])
53
+ follow_array.select { |c| c.followers_count_by_type(args[0]) == num }
54
+ end
55
+ end
56
+
57
+ #def method_missing(name, *args)
58
+ # if name.to_s =~ /^with_(max|min)_followers$/i
59
+ # follow_array = self.all.to_a.sort! { |a, b| a.followers_count <=> b.followers_count }
60
+ # if $1 == "max"
61
+ # max = follow_array[-1].followers_count
62
+ # follow_array.select { |c| c.followers_count == max }
63
+ # elsif $1 == "min"
64
+ # min = follow_array[0].followers_count
65
+ # follow_array.select { |c| c.followers_count == min }
66
+ # end
67
+ # elsif name.to_s =~ /^with_(max|min)_followers_by_type$/i
68
+ # follow_array = self.all.to_a.sort! { |a, b| a.followers_count_by_type(args[0]) <=> b.followers_count_by_type(args[0]) }
69
+ # if $1 == "max"
70
+ # max = follow_array[-1].followers_count_by_type(args[0])
71
+ # follow_array.select { |c| c.followers_count_by_type(args[0]) == max }
72
+ # elsif $1 == "min"
73
+ # min = follow_array[0].followers_count
74
+ # follow_array.select { |c| c.followers_count_by_type(args[0]) == min }
75
+ # end
76
+ # else
77
+ # super
78
+ # end
79
+ #end
80
+
81
+ end
82
+
83
+ # see if this model is followee of some model
84
+ #
85
+ # Example:
86
+ # >> @ruby.followee_of?(@jim)
87
+ # => true
88
+
89
+ def followee_of?(model)
90
+ 0 < self.followers.by_model(model).limit(1).count * model.followees.by_model(self).limit(1).count
91
+ end
92
+
93
+ # return true if self is followed by some models
94
+ #
95
+ # Example:
96
+ # >> @ruby.followed?
97
+ # => true
98
+
99
+ def followed?
100
+ 0 < self.followers.length
101
+ end
102
+
103
+ # get all the followers of this model, same with classmethod followers_of
104
+ #
105
+ # Example:
106
+ # >> @ruby.all_followers
107
+ # => [@jim]
108
+
109
+ def all_followers
110
+ rebuild_instances(self.followers)
111
+ end
112
+
113
+ def unfollowed(*models, &block)
114
+ if block_given?
115
+ models.delete_if { |model| !yield(model) }
116
+ end
117
+
118
+ models.each do |model|
119
+ unless model == self or !self.followee_of?(model) or !model.follower_of?(self)
120
+ model.followees.by_model(self).first.destroy
121
+ self.followers.by_model(model).first.destroy
122
+ end
123
+ end
124
+ end
125
+
126
+ # unfollow all
127
+
128
+ def unfollowed_all
129
+ unfollowed(*self.all_followers)
130
+ end
131
+
132
+ # get all the followers of this model in certain type
133
+ #
134
+ # Example:
135
+ # >> @ruby.followers_by_type("user")
136
+ # => [@jim]
137
+
138
+ def followers_by_type(type)
139
+ rebuild_instances(self.followers.by_type(type))
140
+ end
141
+
142
+ # get the number of followers
143
+ #
144
+ # Example:
145
+ # >> @ruby.followers_count
146
+ # => 1
147
+
148
+ def followers_count
149
+ self.followers.count
150
+ end
151
+
152
+ # get the number of followers in certain type
153
+ #
154
+ # Example:
155
+ # >> @ruby.followers_count_by_type("user")
156
+ # => 1
157
+
158
+ def followers_count_by_type(type)
159
+ self.followers.by_type(type).count
160
+ end
161
+
162
+ # return if there is any common followers
163
+ #
164
+ # Example:
165
+ # >> @ruby.common_followees?(@python)
166
+ # => true
167
+
168
+ def common_followers?(model)
169
+ 0 < (rebuild_instances(self.followers) & rebuild_instances(model.followers)).length
170
+ end
171
+
172
+ # get common followers with some model
173
+ #
174
+ # Example:
175
+ # >> @ruby.common_followers_with(@python)
176
+ # => [@jim]
177
+
178
+ def common_followers_with(model)
179
+ rebuild_instances(self.followers) & rebuild_instances(model.followers)
180
+ end
181
+
182
+ private
183
+ def rebuild_instances(follows) #:nodoc:
184
+ follows.group_by(&:f_type).inject([]) { |r, (k, v)| r += k.constantize.find(v.map(&:f_id)).to_a }
185
+ #follow_list = []
186
+ #follows.each do |follow|
187
+ # follow_list << follow.f_type.constantize.find(follow.f_id)
188
+ #end
189
+ #follow_list
190
+ end
191
+ end
192
+ end
193
+ end
@@ -1,273 +1,216 @@
1
1
  module Mongo
2
- module Follower
3
- extend ActiveSupport::Concern
4
-
5
- included do |base|
6
- if defined?(Mongoid)
7
- if CONFIG[:authorization]
8
- base.field :cannot_follow, :type => Array, :default => []
9
- end
10
-
11
- if CONFIG[:history]
12
- base.field :follow_history, :type => Array, :default => []
13
- end
14
-
15
- base.has_many :followees, :class_name => "Follow", :as => :following, :dependent => :destroy
16
- elsif defined?(MongoMapper)
17
- if CONFIG[:authorization]
18
- base.key :cannot_follow, :type => Array, :default => []
19
- end
20
-
21
- if CONFIG[:history]
22
- base.key :follow_history, :type => Array, :default => []
23
- end
24
-
25
- base.many :followees, :class_name => "Follow", :as => :following, :dependent => :destroy
26
- end
2
+ module Followable
3
+ module Follower
4
+ extend ActiveSupport::Concern
5
+
6
+ included do |base|
7
+ if defined?(Mongoid)
8
+ base.has_many :followees, :class_name => "Follow", :as => :following, :dependent => :destroy
9
+ elsif defined?(MongoMapper)
10
+ base.many :followees, :class_name => "Follow", :as => :following, :dependent => :destroy
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ # get certain model's followers of this type
17
+ #
18
+ # Example:
19
+ # >> @jim = User.new
20
+ # >> @ruby = Group.new
21
+ # >> @jim.save
22
+ # >> @ruby.save
23
+ #
24
+ # >> @jim.follow(@ruby)
25
+ # >> User.followers_of(@ruby)
26
+ # => [@jim]
27
+ #
28
+ # Arguments:
29
+ # model: instance of some followable model
30
+
31
+ def followers_of(model)
32
+ model.followers_by_type(self.name)
33
+ end
34
+
35
+ # 4 methods in this function
36
+ #
37
+ # Example:
38
+ # >> User.with_max_followees
39
+ # => [@jim]
40
+ # >> User.with_max_followees_by_type('group')
41
+ # => [@jim]
42
+
43
+ ["max", "min"].each do |s|
44
+ define_method(:"with_#{s}_followees") do
45
+ follow_array = self.all.to_a.sort! { |a, b| a.followees_count <=> b.followees_count }
46
+ num = follow_array[-1].followees_count
47
+ follow_array.select { |c| c.followees_count == num }
48
+ end
49
+
50
+ define_method(:"with_#{s}_followees_by_type") do |*args|
51
+ follow_array = self.all.to_a.sort! { |a, b| a.followees_count_by_type(args[0]) <=> b.followees_count_by_type(args[0]) }
52
+ num = follow_array[-1].followees_count_by_type(args[0])
53
+ follow_array.select { |c| c.followees_count_by_type(args[0]) == num }
54
+ end
55
+ end
56
+
57
+ #def method_missing(name, *args)
58
+ # if name.to_s =~ /^with_(max|min)_followees$/i
59
+ # follow_array = self.all.to_a.sort! { |a, b| a.followees_count <=> b.followees_count }
60
+ # if $1 == "max"
61
+ # max = follow_array[-1].followees_count
62
+ # follow_array.select { |c| c.followees_count == max }
63
+ # elsif $1 == "min"
64
+ # min = follow_array[0].followees_count
65
+ # follow_array.select { |c| c.followees_count == min }
66
+ # end
67
+ # elsif name.to_s =~ /^with_(max|min)_followees_by_type$/i
68
+ # follow_array = self.all.to_a.sort! { |a, b| a.followees_count_by_type(args[0]) <=> b.followees_count_by_type(args[0]) }
69
+ # if $1 == "max"
70
+ # max = follow_array[-1].followees_count_by_type(args[0])
71
+ # follow_array.select { |c| c.followees_count_by_type(args[0]) == max }
72
+ # elsif $1 == "min"
73
+ # min = follow_array[0].followees_count
74
+ # follow_array.select { |c| c.followees_count_by_type(args[0]) == min }
75
+ # end
76
+ # else
77
+ # super
78
+ # end
79
+ #end
80
+
81
+ end
82
+
83
+ # see if this model is follower of some model
84
+ #
85
+ # Example:
86
+ # >> @jim.follower_of?(@ruby)
87
+ # => true
88
+
89
+ def follower_of?(model)
90
+ 0 < self.followees.by_model(model).limit(1).count * model.followers.by_model(self).limit(1).count
91
+ end
92
+
93
+ # return true if self is following some models
94
+ #
95
+ # Example:
96
+ # >> @jim.following?
97
+ # => true
98
+
99
+ def following?
100
+ 0 < self.followees.length
101
+ end
102
+
103
+ # get all the followees of this model, same with classmethod followees_of
104
+ #
105
+ # Example:
106
+ # >> @jim.all_followees
107
+ # => [@ruby]
108
+
109
+ def all_followees
110
+ rebuild_instances(self.followees)
111
+ end
112
+
113
+ # get all the followees of this model in certain type
114
+ #
115
+ # Example:
116
+ # >> @ruby.followees_by_type("group")
117
+ # => [@ruby]
118
+
119
+ def followees_by_type(type)
120
+ rebuild_instances(self.followees.by_type(type))
121
+ end
122
+
123
+ # follow some model
124
+
125
+ def follow(*models, &block)
126
+ if block_given?
127
+ models.delete_if { |model| !yield(model) }
128
+ end
129
+
130
+ models.each do |model|
131
+ unless model == self or self.follower_of?(model) or model.followee_of?(self)
132
+ model.followers.create!(:f_type => self.class.name, :f_id => self.id.to_s)
133
+ self.followees.create!(:f_type => model.class.name, :f_id => model.id.to_s)
134
+
135
+ model.followed_history << self.class.name + '_' + self.id.to_s if model.respond_to? :followed_history
136
+ self.follow_history << model.class.name + '_' + model.id.to_s if self.respond_to? :follow_history
137
+
138
+ model.save
139
+ self.save
140
+ end
141
+ end
142
+ end
143
+
144
+ # unfollow some model
145
+
146
+ def unfollow(*models, &block)
147
+ if block_given?
148
+ models.delete_if { |model| !yield(model) }
149
+ end
150
+
151
+ models.each do |model|
152
+ unless model == self or !self.follower_of?(model) or !model.followee_of?(self)
153
+ model.followers.by_model(self).first.destroy
154
+ self.followees.by_model(model).first.destroy
155
+ end
156
+ end
157
+ end
158
+
159
+ # unfollow all
160
+
161
+ def unfollow_all
162
+ unfollow(*self.all_followees)
163
+ end
164
+
165
+ # get the number of followees
166
+ #
167
+ # Example:
168
+ # >> @jim.followers_count
169
+ # => 1
170
+
171
+ def followees_count
172
+ self.followees.count
173
+ end
174
+
175
+ # get the number of followers in certain type
176
+ #
177
+ # Example:
178
+ # >> @ruby.followers_count_by_type("user")
179
+ # => 1
180
+
181
+ def followees_count_by_type(type)
182
+ self.followees.by_type(type).count
183
+ end
184
+
185
+ # return if there is any common followees
186
+ #
187
+ # Example:
188
+ # >> @jim.common_followees?(@tom)
189
+ # => true
190
+
191
+ def common_followees?(model)
192
+ 0 < (rebuild_instances(self.followees) & rebuild_instances(model.followees)).length
193
+ end
194
+
195
+ # get common followees with some model
196
+ #
197
+ # Example:
198
+ # >> @jim.common_followees_with(@tom)
199
+ # => [@ruby]
200
+
201
+ def common_followees_with(model)
202
+ rebuild_instances(self.followees) & rebuild_instances(model.followees)
203
+ end
204
+
205
+ private
206
+ def rebuild_instances(follows) #:nodoc:
207
+ follows.group_by(&:f_type).inject([]) { |r, (k, v)| r += k.constantize.find(v.map(&:f_id)).to_a }
208
+ #follow_list = []
209
+ #follows.each do |follow|
210
+ # follow_list << follow.f_type.constantize.find(follow.f_id)
211
+ #end
212
+ #follow_list
213
+ end
27
214
  end
28
-
29
- module ClassMethods
30
-
31
- # get certain model's followers of this type
32
- #
33
- # Example:
34
- # >> @jim = User.new
35
- # >> @ruby = Group.new
36
- # >> @jim.save
37
- # >> @ruby.save
38
- #
39
- # >> @jim.follow(@ruby)
40
- # >> User.followers_of(@ruby)
41
- # => [@jim]
42
- #
43
- # Arguments:
44
- # model: instance of some followable model
45
-
46
- def followers_of(model)
47
- model.followers_by_type(self.name)
48
- end
49
-
50
- # 4 methods in this function
51
- #
52
- # Example:
53
- # >> User.with_max_followees
54
- # => [@jim]
55
- # >> User.with_max_followees_by_type('group')
56
- # => [@jim]
57
-
58
- ["max", "min"].each do |s|
59
- define_method(:"with_#{s}_followees") do
60
- follow_array = self.all.to_a.sort! { |a, b| a.followees_count <=> b.followees_count }
61
- num = follow_array[-1].followees_count
62
- follow_array.select { |c| c.followees_count == num }
63
- end
64
-
65
- define_method(:"with_#{s}_followees_by_type") do |*args|
66
- follow_array = self.all.to_a.sort! { |a, b| a.followees_count_by_type(args[0]) <=> b.followees_count_by_type(args[0]) }
67
- num = follow_array[-1].followees_count_by_type(args[0])
68
- follow_array.select { |c| c.followees_count_by_type(args[0]) == num }
69
- end
70
- end
71
-
72
- #def method_missing(name, *args)
73
- # if name.to_s =~ /^with_(max|min)_followees$/i
74
- # follow_array = self.all.to_a.sort! { |a, b| a.followees_count <=> b.followees_count }
75
- # if $1 == "max"
76
- # max = follow_array[-1].followees_count
77
- # follow_array.select { |c| c.followees_count == max }
78
- # elsif $1 == "min"
79
- # min = follow_array[0].followees_count
80
- # follow_array.select { |c| c.followees_count == min }
81
- # end
82
- # elsif name.to_s =~ /^with_(max|min)_followees_by_type$/i
83
- # follow_array = self.all.to_a.sort! { |a, b| a.followees_count_by_type(args[0]) <=> b.followees_count_by_type(args[0]) }
84
- # if $1 == "max"
85
- # max = follow_array[-1].followees_count_by_type(args[0])
86
- # follow_array.select { |c| c.followees_count_by_type(args[0]) == max }
87
- # elsif $1 == "min"
88
- # min = follow_array[0].followees_count
89
- # follow_array.select { |c| c.followees_count_by_type(args[0]) == min }
90
- # end
91
- # else
92
- # super
93
- # end
94
- #end
95
-
96
- end
97
-
98
- # set which mongoid user cannot follow
99
- #
100
- # Example:
101
- # >> @jim.set_authorization('group', 'user')
102
- # => true
103
-
104
- if CONFIG[:authorization]
105
- define_method(:set_authorization) do |*models|
106
- models.each do |model|
107
- self.cannot_follow << model.safe_capitalize
108
- end
109
- self.save
110
- end
111
-
112
- #unset which mongoid user cannot follow
113
-
114
- define_method(:unset_authorization) do |*models|
115
- models.each do |model|
116
- self.cannot_follow -= [model.safe_capitalize]
117
- end
118
- self.save
119
- end
120
- end
121
-
122
- # see if this model is follower of some model
123
- #
124
- # Example:
125
- # >> @jim.follower_of?(@ruby)
126
- # => true
127
-
128
- def follower_of?(model)
129
- 0 < self.followees.by_model(model).limit(1).count * model.followers.by_model(self).limit(1).count
130
- end
131
-
132
- # return true if self is following some models
133
- #
134
- # Example:
135
- # >> @jim.following?
136
- # => true
137
-
138
- def following?
139
- 0 < self.followees.length
140
- end
141
-
142
- # get all the followees of this model, same with classmethod followees_of
143
- #
144
- # Example:
145
- # >> @jim.all_followees
146
- # => [@ruby]
147
-
148
- def all_followees
149
- rebuild_instances(self.followees)
150
- end
151
-
152
- # get all the followees of this model in certain type
153
- #
154
- # Example:
155
- # >> @ruby.followees_by_type("group")
156
- # => [@ruby]
157
-
158
- def followees_by_type(type)
159
- rebuild_instances(self.followees.by_type(type))
160
- end
161
-
162
- # follow some model
163
-
164
- def follow(*models, &block)
165
- if block_given?
166
- models.delete_if { |model| !yield(model) }
167
- end
168
-
169
- models.each do |model|
170
- term = CONFIG[:authorization] ? (self.cannot_follow.include?(model.class.name) or model.cannot_followed.include?(self.class.name)) : false
171
-
172
- unless model == self or self.follower_of?(model) or model.followee_of?(self) or term
173
- model.followers.create!(:f_type => self.class.name, :f_id => self.id.to_s)
174
- self.followees.create!(:f_type => model.class.name, :f_id => model.id.to_s)
175
-
176
- if CONFIG[:history]
177
- model.followed_history << self.class.name + '_' + self.id.to_s
178
- self.follow_history << model.class.name + '_' + model.id.to_s
179
- end
180
-
181
- model.save
182
- self.save
183
- end
184
- end
185
- end
186
-
187
- # unfollow some model
188
-
189
- def unfollow(*models, &block)
190
- if block_given?
191
- models.delete_if { |model| !yield(model) }
192
- end
193
-
194
- models.each do |model|
195
- unless model == self or !self.follower_of?(model) or !model.followee_of?(self) or self.cannot_follow.include?(model.class.name) or model.cannot_followed.include?(self.class.name)
196
- model.followers.by_model(self).first.destroy
197
- self.followees.by_model(model).first.destroy
198
- end
199
- end
200
- end
201
-
202
- # unfollow all
203
-
204
- def unfollow_all
205
- unfollow(*self.all_followees)
206
- end
207
-
208
- # get the number of followees
209
- #
210
- # Example:
211
- # >> @jim.followers_count
212
- # => 1
213
-
214
- def followees_count
215
- self.followees.count
216
- end
217
-
218
- # get the number of followers in certain type
219
- #
220
- # Example:
221
- # >> @ruby.followers_count_by_type("user")
222
- # => 1
223
-
224
- def followees_count_by_type(type)
225
- self.followees.by_type(type).count
226
- end
227
-
228
- # see user's follow history
229
- #
230
- # Example:
231
- # >> @jim.ever_follow
232
- # => [@ruby]
233
-
234
- if CONFIG[:history]
235
- define_method(:ever_follow) do
236
- follow = []
237
- self.follow_history.each do |h|
238
- follow << h.split('_')[0].constantize.find(h.split('_')[1])
239
- end
240
- follow
241
- end
242
- end
243
-
244
- # return if there is any common followees
245
- #
246
- # Example:
247
- # >> @jim.common_followees?(@tom)
248
- # => true
249
-
250
- def common_followees?(model)
251
- 0 < (rebuild_instances(self.followees) & rebuild_instances(model.followees)).length
252
- end
253
-
254
- # get common followees with some model
255
- #
256
- # Example:
257
- # >> @jim.common_followees_with(@tom)
258
- # => [@ruby]
259
-
260
- def common_followees_with(model)
261
- rebuild_instances(self.followees) & rebuild_instances(model.followees)
262
- end
263
-
264
- private
265
- def rebuild_instances(follows)
266
- follow_list = []
267
- follows.each do |follow|
268
- follow_list << follow.f_type.constantize.find(follow.f_id)
269
- end
270
- follow_list
271
- end
272
215
  end
273
216
  end