mongo_followable 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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