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 +32 -13
- data/lib/mongo_followable.rb +2 -5
- data/lib/mongo_followable/features/authorization.rb +5 -0
- data/lib/mongo_followable/features/confirmation.rb +5 -0
- data/lib/mongo_followable/features/history.rb +76 -0
- data/lib/mongo_followable/followed.rb +193 -0
- data/lib/mongo_followable/follower.rb +212 -269
- data/lib/mongo_followable/version.rb +4 -2
- data/mongo_followable.gemspec +6 -6
- data/spec/mongo/followable_spec.rb +10 -0
- data/spec/mongo/performance_spec.rb +29 -0
- data/spec/mongo_mapper/childuser.rb +3 -2
- data/spec/mongo_mapper/group.rb +2 -1
- data/spec/mongo_mapper/user.rb +3 -2
- data/spec/mongoid/childuser.rb +3 -2
- data/spec/mongoid/group.rb +2 -1
- data/spec/mongoid/user.rb +3 -2
- metadata +18 -20
- data/.idea/encodings.xml +0 -5
- data/.idea/misc.xml +0 -5
- data/.idea/modules.xml +0 -9
- data/.idea/mongo_followable.iml +0 -17
- data/.idea/vcs.xml +0 -7
- data/lib/mongo_followable/followable.rb +0 -247
- data/lib/mongo_followable/railtie.rb +0 -9
    
        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 | 
            -
             | 
| 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 |  | 
    
        data/lib/mongo_followable.rb
    CHANGED
    
    | @@ -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/ | 
| 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,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  | 
| 3 | 
            -
                 | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 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
         |