amistad 0.7.5 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +4 -1
  2. data/Gemfile.lock +56 -39
  3. data/README.markdown +29 -126
  4. data/Rakefile +35 -1
  5. data/amistad.gemspec +8 -3
  6. data/lib/amistad.rb +14 -9
  7. data/lib/amistad/active_record_friend_model.rb +157 -0
  8. data/lib/amistad/active_record_friendship_model.rb +52 -0
  9. data/lib/amistad/config.rb +21 -0
  10. data/lib/amistad/friend_model.rb +10 -4
  11. data/lib/amistad/friendship_model.rb +2 -2
  12. data/lib/amistad/friendships.rb +19 -0
  13. data/lib/amistad/mongo_friend_model.rb +168 -0
  14. data/lib/amistad/mongo_mapper_friend_model.rb +58 -0
  15. data/lib/amistad/mongoid_friend_model.rb +58 -0
  16. data/lib/amistad/version.rb +1 -1
  17. data/lib/generators/amistad/install/install_generator.rb +0 -1
  18. data/lib/generators/amistad/install/templates/create_friendships.rb +2 -2
  19. data/spec/activerecord/activerecord_spec_helper.rb +11 -24
  20. data/spec/activerecord/friend_custom_model_spec.rb +17 -0
  21. data/spec/activerecord/friend_spec.rb +16 -0
  22. data/spec/activerecord/friendship_spec.rb +13 -0
  23. data/spec/activerecord/friendship_with_custom_friend_model_spec.rb +18 -0
  24. data/spec/mongo_mapper/friend_custom_model_spec.rb +27 -0
  25. data/spec/mongo_mapper/friend_spec.rb +17 -0
  26. data/spec/mongo_mapper/mongo_mapper_spec_helper.rb +9 -0
  27. data/spec/mongoid/friend_custom_model_spec.rb +27 -0
  28. data/spec/mongoid/friend_spec.rb +17 -0
  29. data/spec/mongoid/mongoid_spec_helper.rb +8 -7
  30. data/spec/spec_helper.rb +33 -4
  31. data/spec/{activerecord/activerecord_friendship_model_spec.rb → support/activerecord/friendship_examples.rb} +11 -23
  32. data/spec/support/activerecord/schema.rb +40 -0
  33. data/spec/support/friend_examples.rb +2 -12
  34. data/spec/support/parameterized_models.rb +19 -0
  35. metadata +177 -36
  36. data/lib/amistad/active_record/friend_model.rb +0 -146
  37. data/lib/amistad/active_record/friendship_model.rb +0 -50
  38. data/lib/amistad/mongoid/friend_model.rb +0 -195
  39. data/lib/generators/amistad/install/templates/friendship.rb +0 -3
  40. data/spec/activerecord/activerecord_friend_model_spec.rb +0 -13
  41. data/spec/mongoid/mongoid_friend_model_spec.rb +0 -47
@@ -0,0 +1,52 @@
1
+ module Amistad
2
+ module ActiveRecordFriendshipModel
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ belongs_to :friendable,
7
+ :class_name => Amistad.friend_model,
8
+ :foreign_key => "friendable_id"
9
+
10
+ belongs_to :friend,
11
+ :class_name => Amistad.friend_model,
12
+ :foreign_key => "friend_id"
13
+
14
+ belongs_to :blocker,
15
+ :class_name => Amistad.friend_model,
16
+ :foreign_key => "blocker_id"
17
+
18
+ validates_presence_of :friendable_id, :friend_id
19
+ validates_uniqueness_of :friend_id, :scope => :friendable_id
20
+ end
21
+
22
+ # returns true if a friendship has been approved, else false
23
+ def approved?
24
+ !self.pending
25
+ end
26
+
27
+ # returns true if a friendship has not been approved, else false
28
+ def pending?
29
+ self.pending
30
+ end
31
+
32
+ # returns true if a friendship has been blocked, else false
33
+ def blocked?
34
+ self.blocker_id.present?
35
+ end
36
+
37
+ # returns true if a friendship has not beed blocked, else false
38
+ def active?
39
+ self.blocker_id.nil?
40
+ end
41
+
42
+ # returns true if a friendship can be blocked by given friendable
43
+ def can_block?(friendable)
44
+ active? && (approved? || (pending? && self.friend_id == friendable.id && friendable.class.to_s == Amistad.friend_model))
45
+ end
46
+
47
+ # returns true if a friendship can be unblocked by given friendable
48
+ def can_unblock?(friendable)
49
+ blocked? && self.blocker_id == friendable.id && friendable.class.to_s == Amistad.friend_model
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ module Amistad
2
+ class << self
3
+ attr_accessor :friend_model
4
+
5
+ def configure
6
+ yield self
7
+ end
8
+
9
+ def friend_model
10
+ @friend_model || 'User'
11
+ end
12
+
13
+ def friendship_model
14
+ "#{self.friend_model}Friendship"
15
+ end
16
+
17
+ def friendship_class
18
+ Amistad::Friendships.const_get(self.friendship_model)
19
+ end
20
+ end
21
+ end
@@ -3,15 +3,21 @@ module Amistad
3
3
  def self.included(receiver)
4
4
  if receiver.ancestors.map(&:to_s).include?("ActiveRecord::Base")
5
5
  receiver.class_exec do
6
- include Amistad::ActiveRecord::FriendModel
6
+ include Amistad::ActiveRecordFriendModel
7
7
  end
8
8
  elsif receiver.ancestors.map(&:to_s).include?("Mongoid::Document")
9
9
  receiver.class_exec do
10
- include Amistad::Mongoid::FriendModel
10
+ include Amistad::MongoidFriendModel
11
+ include Amistad::MongoFriendModel
12
+ end
13
+ elsif receiver.ancestors.map(&:to_s).include?("MongoMapper::Document")
14
+ receiver.class_exec do
15
+ include Amistad::MongoMapperFriendModel
16
+ include Amistad::MongoFriendModel
11
17
  end
12
18
  else
13
- raise "Amistad only supports ActiveRecord and Mongoid"
19
+ raise "Amistad only supports ActiveRecord, Mongoid and MongoMapper"
14
20
  end
15
21
  end
16
22
  end
17
- end
23
+ end
@@ -3,11 +3,11 @@ module Amistad
3
3
  def self.included(receiver)
4
4
  if receiver.ancestors.map(&:to_s).include?("ActiveRecord::Base")
5
5
  receiver.class_exec do
6
- include Amistad::ActiveRecord::FriendshipModel
6
+ include Amistad::ActiveRecordFriendshipModel
7
7
  end
8
8
  else
9
9
  raise "Amistad only supports ActiveRecord and Mongoid"
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Amistad
2
+ module Friendships
3
+ if Object.const_defined? :ActiveRecord
4
+ const_set Amistad.friendship_model, Class.new(ActiveRecord::Base)
5
+ const_get(Amistad.friendship_model.to_sym).class_exec do
6
+ include Amistad::FriendshipModel
7
+ self.table_name = 'friendships'
8
+ end
9
+ elsif Object.const_defined? :Mongoid
10
+ Friendship = Class.new
11
+ Friendship.class_exec do
12
+ include Mongoid::Document
13
+ include Amistad::FriendshipModel
14
+ end
15
+ else
16
+ raise "Amistad only supports ActiveRecord and Mongoid"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,168 @@
1
+ module Amistad
2
+ module MongoFriendModel
3
+ # suggest a user to become a friend. If the operation succeeds, the method returns true, else false
4
+ def invite(user)
5
+ return false if friendshiped_with?(user) or user == self or blocked?(user)
6
+ pending_friend_ids << user.id
7
+ user.pending_inverse_friend_ids << self.id
8
+ self.save && user.save
9
+ end
10
+
11
+ # approve a friendship invitation. If the operation succeeds, the method returns true, else false
12
+ def approve(user)
13
+ return false unless pending_inverse_friend_ids.include?(user.id) && user.pending_friend_ids.include?(self.id)
14
+ pending_inverse_friend_ids.delete(user.id)
15
+ user.pending_friend_ids.delete(self.id)
16
+ inverse_friend_ids << user.id
17
+ user.friend_ids << self.id
18
+ self.save && user.save
19
+ end
20
+
21
+ # returns the list of approved friends
22
+ def friends
23
+ self.invited + self.invited_by
24
+ end
25
+
26
+ # total # of invited and invited_by without association loading
27
+ def total_friends
28
+ (friend_ids + inverse_friend_ids).count
29
+ end
30
+
31
+ # return the list of invited friends
32
+ def invited
33
+ self.class.find(friend_ids)
34
+ end
35
+
36
+ # return the list of friends who invited
37
+ def invited_by
38
+ self.class.find(inverse_friend_ids)
39
+ end
40
+
41
+ # return the list of pending invited friends
42
+ def pending_invited
43
+ self.class.find(pending_friend_ids)
44
+ end
45
+
46
+ # return the list of pending friends who invited
47
+ def pending_invited_by
48
+ self.class.find(pending_inverse_friend_ids)
49
+ end
50
+
51
+ # return the list of the ones among its friends which are also friend with the given use
52
+ def common_friends_with(user)
53
+ self.friends & user.friends
54
+ end
55
+
56
+ # checks if a user is a friend
57
+ def friend_with?(user)
58
+ return false if user == self
59
+ (friend_ids + inverse_friend_ids).include?(user.id)
60
+ end
61
+
62
+ # checks if a current user is connected to given user
63
+ def connected_with?(user)
64
+ friendshiped_with?(user)
65
+ end
66
+
67
+ # checks if a current user received invitation from given user
68
+ def invited_by?(user)
69
+ user.friend_ids.include?(self.id) or user.pending_friend_ids.include?(self.id)
70
+ end
71
+
72
+ # checks if a current user invited given user
73
+ def invited?(user)
74
+ self.friend_ids.include?(user.id) or self.pending_friend_ids.include?(user.id)
75
+ end
76
+
77
+ # deletes a friendship
78
+ def remove_friendship(user)
79
+ friend_ids.delete(user.id)
80
+ user.inverse_friend_ids.delete(self.id)
81
+ inverse_friend_ids.delete(user.id)
82
+ user.friend_ids.delete(self.id)
83
+ pending_friend_ids.delete(user.id)
84
+ user.pending_inverse_friend_ids.delete(self.id)
85
+ pending_inverse_friend_ids.delete(user.id)
86
+ user.pending_friend_ids.delete(self.id)
87
+ self.save && user.save
88
+ end
89
+
90
+ # blocks a friendship
91
+ def block(user)
92
+ if inverse_friend_ids.include?(user.id)
93
+ inverse_friend_ids.delete(user.id)
94
+ user.friend_ids.delete(self.id)
95
+ blocked_inverse_friend_ids << user.id
96
+ elsif pending_inverse_friend_ids.include?(user.id)
97
+ pending_inverse_friend_ids.delete(user.id)
98
+ user.pending_friend_ids.delete(self.id)
99
+ blocked_pending_inverse_friend_ids << user.id
100
+ elsif friend_ids.include?(user.id)
101
+ friend_ids.delete(user.id)
102
+ user.inverse_friend_ids.delete(user.id)
103
+ blocked_friend_ids << user.id
104
+ else
105
+ return false
106
+ end
107
+
108
+ self.save
109
+ end
110
+
111
+ # unblocks a friendship
112
+ def unblock(user)
113
+ if blocked_inverse_friend_ids.include?(user.id)
114
+ blocked_inverse_friend_ids.delete(user.id)
115
+ user.blocked_friend_ids.delete(self.id)
116
+ inverse_friend_ids << user.id
117
+ user.friend_ids << self.id
118
+ elsif blocked_pending_inverse_friend_ids.include?(user.id)
119
+ blocked_pending_inverse_friend_ids.delete(user.id)
120
+ pending_inverse_friend_ids << user.id
121
+ user.pending_friend_ids << self.id
122
+ elsif blocked_friend_ids.include?(user.id)
123
+ blocked_friend_ids.delete(user.id)
124
+ user.blocked_inverse_friend_ids.delete(self.id)
125
+ friend_ids << user.id
126
+ user.inverse_friend_ids << self.id
127
+ else
128
+ return false
129
+ end
130
+
131
+ self.save && user.save
132
+ end
133
+
134
+ # returns the list of blocked friends
135
+ def blocked
136
+ blocked_ids = blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids
137
+ self.class.find(blocked_ids)
138
+ end
139
+
140
+ # total # of blockades and blockedes_by without association loading
141
+ def total_blocked
142
+ (blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids).count
143
+ end
144
+
145
+ # checks if a user is blocked
146
+ def blocked?(user)
147
+ (blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids).include?(user.id) or user.blocked_pending_inverse_friend_ids.include?(self.id)
148
+ end
149
+
150
+ # check if any friendship exists with another user
151
+ def friendshiped_with?(user)
152
+ (friend_ids + inverse_friend_ids + pending_friend_ids + pending_inverse_friend_ids + blocked_friend_ids).include?(user.id)
153
+ end
154
+
155
+ # deletes all the friendships
156
+ def delete_all_friendships
157
+ friend_ids.clear
158
+ inverse_friend_ids.clear
159
+ pending_friend_ids.clear
160
+ pending_inverse_friend_ids.clear
161
+ blocked_friend_ids.clear
162
+ blocked_inverse_friend_ids.clear
163
+ blocked_pending_friend_ids.clear
164
+ blocked_pending_inverse_friend_ids.clear
165
+ self.save
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,58 @@
1
+ module Amistad
2
+ module MongoMapperFriendModel
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ key :friend_ids,
7
+ Array,
8
+ :default => []
9
+
10
+ key :inverse_friend_ids,
11
+ Array,
12
+ :default => []
13
+
14
+ key :pending_friend_ids,
15
+ Array,
16
+ :default => []
17
+
18
+ key :pending_inverse_friend_ids,
19
+ Array,
20
+ :default => []
21
+
22
+ key :blocked_friend_ids,
23
+ Array,
24
+ :default => []
25
+
26
+ key :blocked_inverse_friend_ids,
27
+ Array,
28
+ :default => []
29
+
30
+ key :blocked_pending_friend_ids,
31
+ Array,
32
+ :default => []
33
+
34
+ key :blocked_pending_inverse_friend_ids,
35
+ Array,
36
+ :default => []
37
+
38
+ attr_accessible(
39
+ :friend_ids,
40
+ :inverse_friend_ids,
41
+ :pending_friend_ids,
42
+ :pending_inverse_friend_ids,
43
+ :blocked_friend_ids,
44
+ :blocked_inverse_friend_ids,
45
+ :blocked_pending_friend_ids,
46
+ :blocked_pending_inverse_friend_ids,
47
+ )
48
+
49
+ %w(friend_ids inverse_friend_ids pending_friend_ids pending_inverse_friend_ids blocked_friend_ids blocked_inverse_friend_ids blocked_pending_friend_ids blocked_pending_inverse_friend_ids).each do |attribute|
50
+ define_method(attribute.to_sym) do
51
+ value = read_attribute(attribute)
52
+ write_attribute(attribute, value = []) if value.nil?
53
+ value
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,58 @@
1
+ module Amistad
2
+ module MongoidFriendModel
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ field :friend_ids,
7
+ :type => Array,
8
+ :default => []
9
+
10
+ field :inverse_friend_ids,
11
+ :type => Array,
12
+ :default => []
13
+
14
+ field :pending_friend_ids,
15
+ :type => Array,
16
+ :default => []
17
+
18
+ field :pending_inverse_friend_ids,
19
+ :type => Array,
20
+ :default => []
21
+
22
+ field :blocked_friend_ids,
23
+ :type => Array,
24
+ :default => []
25
+
26
+ field :blocked_inverse_friend_ids,
27
+ :type => Array,
28
+ :default => []
29
+
30
+ field :blocked_pending_friend_ids,
31
+ :type => Array,
32
+ :default => []
33
+
34
+ field :blocked_pending_inverse_friend_ids,
35
+ :type => Array,
36
+ :default => []
37
+
38
+ attr_accessible(
39
+ :friend_ids,
40
+ :inverse_friend_ids,
41
+ :pending_friend_ids,
42
+ :pending_inverse_friend_ids,
43
+ :blocked_friend_ids,
44
+ :blocked_inverse_friend_ids,
45
+ :blocked_pending_friend_ids,
46
+ :blocked_pending_inverse_friend_ids,
47
+ )
48
+
49
+ %w(friend_ids inverse_friend_ids pending_friend_ids pending_inverse_friend_ids blocked_friend_ids blocked_inverse_friend_ids blocked_pending_friend_ids blocked_pending_inverse_friend_ids).each do |attribute|
50
+ define_method(attribute.to_sym) do
51
+ value = read_attribute(attribute)
52
+ write_attribute(attribute, value = []) if value.nil?
53
+ value
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,3 +1,3 @@
1
1
  module Amistad
2
- VERSION = "0.7.5"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -16,7 +16,6 @@ module Amistad
16
16
 
17
17
  desc "This generator creates a friendship model and its migration file"
18
18
  def create_friendship_model_files
19
- template 'friendship.rb', 'app/models/friendship.rb'
20
19
  template 'create_friendships.rb', "db/migrate/#{self.class.next_migration_number}_create_friendships.rb"
21
20
  end
22
21
  end
@@ -1,13 +1,13 @@
1
1
  class CreateFriendships < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :friendships do |t|
4
- t.integer :user_id
4
+ t.integer :friendable_id
5
5
  t.integer :friend_id
6
6
  t.integer :blocker_id
7
7
  t.boolean :pending, :default => true
8
8
  end
9
9
 
10
- add_index :friendships, [:user_id, :friend_id], :unique => true
10
+ add_index :friendships, [:friendable_id, :friend_id], :unique => true
11
11
  end
12
12
 
13
13
  def self.down