has_friends 0.0.1
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/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +133 -0
- data/Rakefile +1 -0
- data/bin/has_friends +3 -0
- data/has_friends.gemspec +26 -0
- data/lib/friendship.rb +46 -0
- data/lib/has_friends/cli.rb +22 -0
- data/lib/has_friends/generators/friends_counter.rb +28 -0
- data/lib/has_friends/generators/install.rb +25 -0
- data/lib/has_friends/generators/templates/add_friends_counter.rb +9 -0
- data/lib/has_friends/generators/templates/create_friendships.rb +13 -0
- data/lib/has_friends/version.rb +3 -0
- data/lib/has_friends.rb +100 -0
- data/log/test.log +0 -0
- data/spec/lib/has_friends_spec.rb +224 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/data.rb +3 -0
- data/spec/support/models.rb +3 -0
- data/spec/support/schema.rb +25 -0
- metadata +156 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Nando Vieira
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
has_friends
|
2
|
+
===========
|
3
|
+
|
4
|
+
**ATTENTION:** This is a new simpler implementation. If you want to use the previous version,
|
5
|
+
get the 1.0 tag.
|
6
|
+
|
7
|
+
Instalation
|
8
|
+
-----------
|
9
|
+
|
10
|
+
Install the plugin with
|
11
|
+
|
12
|
+
script/plugin install git://github.com/fnando/has_friends.git
|
13
|
+
|
14
|
+
Then generate a migration with `script/generate migration create_friendships` and add the following code:
|
15
|
+
|
16
|
+
class CreateFriendships < ActiveRecord::Migration
|
17
|
+
def self.up
|
18
|
+
create_table :friendships do |t|
|
19
|
+
t.references :user, :friend
|
20
|
+
t.datetime :requested_at, :accepted_at, :null => true, :default => nil
|
21
|
+
t.string :status
|
22
|
+
end
|
23
|
+
|
24
|
+
add_index :friendships, :user_id
|
25
|
+
add_index :friendships, :friend_id
|
26
|
+
add_index :friendships, :status
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.down
|
30
|
+
drop_table :friendships
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Finally, run the migrations with `rake db:migrate`
|
35
|
+
|
36
|
+
Usage
|
37
|
+
-----
|
38
|
+
|
39
|
+
Add the method call `has_friends` to your model.
|
40
|
+
|
41
|
+
class User < ActiveRecord::Base
|
42
|
+
has_friends
|
43
|
+
end
|
44
|
+
|
45
|
+
john = User.find_by_login 'john'
|
46
|
+
mary = User.find_by_login 'mary'
|
47
|
+
paul = User.find_by_login 'paul'
|
48
|
+
|
49
|
+
# john wants to be friend with mary
|
50
|
+
# always return a friendship object
|
51
|
+
john.be_friends_with(mary)
|
52
|
+
|
53
|
+
# are they friends?
|
54
|
+
john.friends?(mary)
|
55
|
+
|
56
|
+
# get the friendship object
|
57
|
+
john.friendship_for(mary)
|
58
|
+
|
59
|
+
# mary accepts john's request if it exists;
|
60
|
+
# makes a friendship request otherwise.
|
61
|
+
mary.be_friends_with(john)
|
62
|
+
|
63
|
+
# check if paul is mary's friend
|
64
|
+
mary.friends?(paul)
|
65
|
+
|
66
|
+
# check if an user is the current user, so it can
|
67
|
+
# be differently presented
|
68
|
+
mary.friends.each {|friend| friend.is?(current_user) }
|
69
|
+
|
70
|
+
# if you're dealing with a friendship object,
|
71
|
+
# the following methods are available
|
72
|
+
friendship.accept!
|
73
|
+
|
74
|
+
# if you're using has_paginate plugin, you can use it:
|
75
|
+
mary.friends.paginate(:page => 3, :limit => 10)
|
76
|
+
|
77
|
+
# the be_friends_with method returns 2 params: friendship object and status.
|
78
|
+
# the friendship object will be present only when the friendship is created
|
79
|
+
# (that is, when is requested for the first time)
|
80
|
+
# STATUS_ALREADY_FRIENDS # => users are already friends
|
81
|
+
# STATUS_ALREADY_REQUESTED # => user has already requested friendship
|
82
|
+
# STATUS_IS_YOU # => user is trying add himself as friend
|
83
|
+
# STATUS_FRIEND_IS_REQUIRED # => friend argument is missing
|
84
|
+
# STATUS_FRIENDSHIP_ACCEPTED # => friendship has been accepted
|
85
|
+
# STATUS_REQUESTED # => friendship has been requested
|
86
|
+
|
87
|
+
friendship, status = mary.be_friends_with(john)
|
88
|
+
|
89
|
+
if status == Friends::STATUS_REQUESTED
|
90
|
+
# the friendship has been requested
|
91
|
+
Mailer.deliver_friendship_request(friendship)
|
92
|
+
elsif status == Friends::STATUS_ALREADY_FRIENDS
|
93
|
+
# they're already friends
|
94
|
+
else
|
95
|
+
# ...
|
96
|
+
end
|
97
|
+
|
98
|
+
NOTE: You should have a User model. You should also have a `friends_count` column
|
99
|
+
on your model. Otherwise, this won't work! Create a new migration with `script/generate migration add_friends_count_to_user`:
|
100
|
+
|
101
|
+
class AddFriendsCountToUser < ActiveRecord::Migration
|
102
|
+
def self.up
|
103
|
+
add_column :users, :friends_count, :integer, :default => 0, :null => false
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.down
|
107
|
+
remove_column :users, :friends_count
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
LICENSE:
|
112
|
+
--------
|
113
|
+
|
114
|
+
(The MIT License)
|
115
|
+
|
116
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
117
|
+
a copy of this software and associated documentation files (the
|
118
|
+
'Software'), to deal in the Software without restriction, including
|
119
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
120
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
121
|
+
permit persons to whom the Software is furnished to do so, subject to
|
122
|
+
the following conditions:
|
123
|
+
|
124
|
+
The above copyright notice and this permission notice shall be
|
125
|
+
included in all copies or substantial portions of the Software.
|
126
|
+
|
127
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
128
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
129
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
130
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
131
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
132
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
133
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/has_friends
ADDED
data/has_friends.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "has_friends/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "has_friends"
|
7
|
+
s.version = HasFriends::VERSION
|
8
|
+
s.authors = ["embs"]
|
9
|
+
s.email = ["embs@cin.ufpe.br"]
|
10
|
+
s.homepage = "http://cin.ufpe.br/~embs"
|
11
|
+
s.summary = %q{Add has_friends functionality to your ActiveRecord models}
|
12
|
+
s.description = %q{This gem is based on homonym plugin from fnando https://github.com/fnando/has_friends}
|
13
|
+
|
14
|
+
s.rubyforge_project = "has_friends"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "thor"
|
22
|
+
s.add_dependency "activerecord"
|
23
|
+
s.add_dependency "rails3-generators"
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
s.add_development_dependency "sqlite3"
|
26
|
+
end
|
data/lib/friendship.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Friendship < ActiveRecord::Base
|
2
|
+
# constants
|
3
|
+
STATUS_ALREADY_FRIENDS = 1
|
4
|
+
STATUS_ALREADY_REQUESTED = 2
|
5
|
+
STATUS_IS_YOU = 3
|
6
|
+
STATUS_FRIEND_IS_REQUIRED = 4
|
7
|
+
STATUS_FRIENDSHIP_ACCEPTED = 5
|
8
|
+
STATUS_REQUESTED = 6
|
9
|
+
STATUS_FRIENDSHIP_DECLINED = 7
|
10
|
+
|
11
|
+
# scopes
|
12
|
+
scope :pending, where(:status => 'pending')
|
13
|
+
scope :accepted, where(:status => 'accepted')
|
14
|
+
scope :requested, where(:status => 'requested')
|
15
|
+
scope :declined, where(:status => 'declined')
|
16
|
+
|
17
|
+
# associations
|
18
|
+
belongs_to :user
|
19
|
+
belongs_to :friend, :class_name => 'User', :foreign_key => 'friend_id'
|
20
|
+
|
21
|
+
# callback
|
22
|
+
after_destroy do |f|
|
23
|
+
user = User.find(f.user_id)
|
24
|
+
unless user.friends_count == 0
|
25
|
+
User.decrement_counter(:friends_count, f.user_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def pending?
|
31
|
+
status == 'pending'
|
32
|
+
end
|
33
|
+
|
34
|
+
def accepted?
|
35
|
+
status == 'accepted'
|
36
|
+
end
|
37
|
+
|
38
|
+
def requested?
|
39
|
+
status == 'requested'
|
40
|
+
end
|
41
|
+
|
42
|
+
def accept!
|
43
|
+
User.increment_counter(:friends_count, user_id) unless accepted?
|
44
|
+
update_attribute(:status, 'accepted')
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'has_friends'
|
3
|
+
|
4
|
+
require 'has_friends/generators/install'
|
5
|
+
require 'has_friends/generators/friends_counter'
|
6
|
+
|
7
|
+
module HasFriends
|
8
|
+
class CLI < Thor
|
9
|
+
include Thor::Actions
|
10
|
+
|
11
|
+
desc "install", "Generates friendship migration"
|
12
|
+
def install
|
13
|
+
HasFriends::Generators::Install.start
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "counter", "Adds friends_count column to friendly table"
|
17
|
+
def counter(tableName = 'User')
|
18
|
+
HasFriends::Generators::FriendsCounter.start([tableName])
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
module HasFriends
|
6
|
+
module Generators
|
7
|
+
class FriendsCounter < Thor::Group
|
8
|
+
include Thor::Actions
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
argument :tableName, :type => :string
|
12
|
+
|
13
|
+
desc "Generates friendships migration"
|
14
|
+
def self.source_root
|
15
|
+
@source_root ||= File.dirname(__FILE__) + "/templates"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.next_migration_number(path)
|
19
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_migration_file
|
23
|
+
migration_template "add_friends_counter.rb",
|
24
|
+
File.join('db','migrate', "add_friends_count_to_#{tableName.downcase}.rb")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
module HasFriends
|
6
|
+
module Generators
|
7
|
+
class Install < Thor::Group
|
8
|
+
include Thor::Actions
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
desc "Generates friendships migration"
|
12
|
+
def self.source_root
|
13
|
+
@source_root ||= File.dirname(__FILE__) + "/templates"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.next_migration_number(path)
|
17
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_migration_file
|
21
|
+
migration_template 'create_friendships.rb', File.join('db','migrate', 'create_friendships.rb')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class AddFriendsCountTo<%= tableName.capitalize %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :<%= tableName.downcase %>, :friends_count, :integer, :default => 0, :null => false
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.down
|
7
|
+
remove_column :<%= tableName.downcase %>, :friends_count
|
8
|
+
end
|
9
|
+
end
|
data/lib/has_friends.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'has_friends/version'
|
2
|
+
require 'active_record'
|
3
|
+
require 'friendship'
|
4
|
+
|
5
|
+
module HasFriends
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def has_friends
|
9
|
+
include HasFriends::InstanceMethods
|
10
|
+
|
11
|
+
has_many :friendships
|
12
|
+
has_many :friends, :through => :friendships, :source => :friend, :conditions => "friendships.status = 'accepted'"
|
13
|
+
has_many :friends_pending, :through => :friendships, :source => :friend, :conditions => "friendships.status = 'pending'"
|
14
|
+
|
15
|
+
before_destroy :destroy_all_friendships
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
def be_friends_with(friend)
|
21
|
+
# no user object
|
22
|
+
return nil, Friendship::STATUS_FRIEND_IS_REQUIRED unless friend
|
23
|
+
|
24
|
+
# should not create friendship if user is trying to add himself
|
25
|
+
return nil, Friendship::STATUS_IS_YOU if is?(friend)
|
26
|
+
|
27
|
+
# should not create friendship if users are already friends
|
28
|
+
return nil, Friendship::STATUS_ALREADY_FRIENDS if friends?(friend)
|
29
|
+
|
30
|
+
# retrieve the friendship request
|
31
|
+
friendship = self.friendship_for(friend)
|
32
|
+
|
33
|
+
# let's check if user has already a friendship request or have removed
|
34
|
+
request = friend.friendship_for(self)
|
35
|
+
|
36
|
+
# friendship has already been requested
|
37
|
+
return nil, Friendship::STATUS_ALREADY_REQUESTED if friendship && friendship.requested?
|
38
|
+
|
39
|
+
# friendship is pending so accept it
|
40
|
+
if friendship && friendship.pending?
|
41
|
+
friendship.accept!
|
42
|
+
request.accept!
|
43
|
+
|
44
|
+
return friendship, Friendship::STATUS_FRIENDSHIP_ACCEPTED
|
45
|
+
end
|
46
|
+
|
47
|
+
# we didn't find a friendship, so let's create one!
|
48
|
+
friendship = self.friendships.create(:friend_id => friend.id, :status => 'requested')
|
49
|
+
|
50
|
+
# we didn't find a friendship request, so let's create it!
|
51
|
+
request = friend.friendships.create(:friend_id => id, :status => 'pending')
|
52
|
+
|
53
|
+
return friendship, Friendship::STATUS_REQUESTED
|
54
|
+
end
|
55
|
+
|
56
|
+
def friends?(friend)
|
57
|
+
friendship = friendship_for(friend)
|
58
|
+
friendship && friendship.accepted?
|
59
|
+
end
|
60
|
+
|
61
|
+
def friendship_for(friend)
|
62
|
+
friendships.first :conditions => {:friend_id => friend.id}
|
63
|
+
end
|
64
|
+
|
65
|
+
def is?(friend)
|
66
|
+
self.id == friend.id
|
67
|
+
end
|
68
|
+
|
69
|
+
def friends_in_common_with(user)
|
70
|
+
self.friends.select { |friend| user.friends.include?(friend) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def friends_not_in_common_with(user)
|
74
|
+
self.friends.reject { |friend| user.friends.include?(friend) or user == friend }
|
75
|
+
end
|
76
|
+
|
77
|
+
def friends_of_friends
|
78
|
+
self.friends.collect do |friend|
|
79
|
+
friend.friends_not_in_common_with(self)
|
80
|
+
end.flatten.uniq
|
81
|
+
end
|
82
|
+
|
83
|
+
# Destroyes (in both ways) the friendship
|
84
|
+
def destroy_friendship_with(friend)
|
85
|
+
friendship = friendship_for(friend)
|
86
|
+
other_friendship = friend.friendship_for(self)
|
87
|
+
friendship.destroy
|
88
|
+
other_friendship.destroy
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
# Destroyes all friendships of user
|
93
|
+
def destroy_all_friendships
|
94
|
+
Friendship.destroy_all({:user_id => id})
|
95
|
+
Friendship.destroy_all({:friend_id => id})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
ActiveRecord::Base.extend HasFriends::ClassMethods
|
data/log/test.log
ADDED
File without changes
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "has_friends" do
|
4
|
+
before do
|
5
|
+
User.delete_all
|
6
|
+
|
7
|
+
@vader = User.create(:login => "darth_vader")
|
8
|
+
@luke = User.create(:login => "luke_skywalker")
|
9
|
+
@leia = User.create(:login => "princess_leia")
|
10
|
+
@han_solo = User.create(:login => "han_solo")
|
11
|
+
@yoda = User.create(:login => "yoda")
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "methods" do
|
15
|
+
it "should respond to has_friends method" do
|
16
|
+
User.should respond_to(:has_friends)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should respond to be_friends_with method" do
|
20
|
+
@vader.should respond_to(:be_friends_with)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond to friends? method" do
|
24
|
+
@vader.should respond_to(:friends?)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should respond to friends_in_common_with method" do
|
28
|
+
@vader.should respond_to(:friends_in_common_with)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should responde to friends_not_in_common_with" do
|
32
|
+
@vader.should respond_to(:friends_not_in_common_with)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should respond to friends_of_friends method" do
|
36
|
+
@vader.should respond_to(:friends_of_friends)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should respond to destroy_friendship_with" do
|
40
|
+
@vader.should respond_to(:destroy_friendship_with)
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "friends" do
|
46
|
+
before(:each) do
|
47
|
+
create_friendship @vader, @luke
|
48
|
+
create_friendship @vader, @leia
|
49
|
+
create_friendship @luke, @leia
|
50
|
+
create_friendship @luke, @yoda
|
51
|
+
create_friendship @leia, @han_solo
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should order vader's friends" do
|
55
|
+
# => princess_leia, luke_skywalker
|
56
|
+
@vader.friends.all(:order => 'login desc').should == [@leia, @luke]
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return luke's friends" do
|
60
|
+
@luke.friends.should == [@vader, @leia, @yoda]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return leia's frieds" do
|
64
|
+
@leia.friends.should == [@vader, @luke, @han_solo]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return yoda's friends" do
|
68
|
+
@yoda.friends.should == [@luke]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return solo's friends" do
|
72
|
+
@han_solo.friends.should == [@leia]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should increment counter" do
|
76
|
+
@vader.reload
|
77
|
+
@vader.friends_count.should == 2
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should decrement counter" do
|
81
|
+
friendship = @vader.friendship_for(@luke)
|
82
|
+
friendship.destroy
|
83
|
+
|
84
|
+
@vader.reload
|
85
|
+
@vader.friends_count.should == 1
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should be @vader" do
|
89
|
+
@vader.is?(@vader).should be_true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should not be @vader" do
|
93
|
+
@vader.is?(@leia).should_not be_true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return vader and luke friends in common" do
|
97
|
+
@vader.friends_in_common_with(@luke).should == [@leia]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return vader and luke friends not in common" do
|
101
|
+
create_friendship @vader, @han_solo
|
102
|
+
@vader.friends_not_in_common_with(@luke).should == [@han_solo]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return friends of vader's friends" do
|
106
|
+
@vader.friends_of_friends.should == [@yoda, @han_solo]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should destroy friendship" do
|
110
|
+
expect {
|
111
|
+
@vader.destroy_friendship_with(@luke)
|
112
|
+
}.should change(Friendship, :count).by(-2)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "friendship request" do
|
117
|
+
it "should return nil and 'friend is required' status" do
|
118
|
+
friendship, status = @vader.be_friends_with(nil)
|
119
|
+
|
120
|
+
friendship.should be_nil
|
121
|
+
status.should == Friendship::STATUS_FRIEND_IS_REQUIRED
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should return nil and 'is you' status" do
|
125
|
+
friendship, status = @vader.be_friends_with(@vader)
|
126
|
+
|
127
|
+
friendship.should be_nil
|
128
|
+
status.should == Friendship::STATUS_IS_YOU
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return nil and 'already friends status" do
|
132
|
+
@vader.be_friends_with(@luke)
|
133
|
+
@luke.be_friends_with(@vader)
|
134
|
+
friendship, status = @vader.be_friends_with(@luke)
|
135
|
+
|
136
|
+
friendship.should be_nil
|
137
|
+
status.should == Friendship::STATUS_ALREADY_FRIENDS
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should return nil and 'already requested' status" do
|
141
|
+
@vader.be_friends_with(@luke)
|
142
|
+
friendship, status = @vader.be_friends_with(@luke)
|
143
|
+
|
144
|
+
friendship.should be_nil
|
145
|
+
status.should == Friendship::STATUS_ALREADY_REQUESTED
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should return friendship and 'accepted friendship' status" do
|
149
|
+
@vader.be_friends_with(@luke)
|
150
|
+
friendship, status = @luke.be_friends_with(@vader)
|
151
|
+
|
152
|
+
friendship.should be_kind_of(Friendship)
|
153
|
+
status.should == Friendship::STATUS_FRIENDSHIP_ACCEPTED
|
154
|
+
@vader.should be_friends(@luke)
|
155
|
+
@luke.should be_friends(@vader)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should create friendships" do
|
159
|
+
lambda {
|
160
|
+
@vader.be_friends_with(@luke)
|
161
|
+
|
162
|
+
@vader.friendships.count.should == 1
|
163
|
+
@luke.friendships.count.should == 1
|
164
|
+
}.should change(Friendship, :count).by(2)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe Friendship do
|
169
|
+
it "should be pending status" do
|
170
|
+
@friendship = Friendship.new(:status => 'pending')
|
171
|
+
@friendship.should be_pending
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should be accepted status" do
|
175
|
+
@friendship = Friendship.new(:status => 'accepted')
|
176
|
+
@friendship.should be_accepted
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should be requested status" do
|
180
|
+
@friendship = Friendship.new(:status => 'requested')
|
181
|
+
@friendship.should be_requested
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when attaching has_many" do
|
185
|
+
before do
|
186
|
+
class Thing < ActiveRecord::Base
|
187
|
+
belongs_to :friendship
|
188
|
+
end
|
189
|
+
|
190
|
+
class Friendship < ActiveRecord::Base
|
191
|
+
has_many :things, :dependent => :destroy
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should destroy related" do
|
196
|
+
@friendships = create_friendship @vader, @han_solo
|
197
|
+
@thing = Thing.create(:friendship => @friendships.first)
|
198
|
+
expect {
|
199
|
+
@vader.destroy
|
200
|
+
}.should change(Thing, :count).by(-1)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "pagination" do
|
206
|
+
before(:each) do
|
207
|
+
pending unless Object.const_defined?('Paginate')
|
208
|
+
|
209
|
+
create_friendship @vader, @luke
|
210
|
+
create_friendship @vader, @leia
|
211
|
+
create_friendship @vader, @han_solo
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should paginate friends" do
|
215
|
+
@vader.friends.paginate(:limit => 1).to_a.should == [@luke, @leia]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
def create_friendship(user1, user2)
|
221
|
+
user1.be_friends_with(user2)
|
222
|
+
user2.be_friends_with(user1)
|
223
|
+
end
|
224
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'has_friends'
|
2
|
+
|
3
|
+
# configura o banco de dados para o ambiente de testes
|
4
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3",
|
5
|
+
:database => File.dirname(__FILE__) + "/has_friends.sqlite3")
|
6
|
+
load File.dirname(__FILE__) + '/support/schema.rb'
|
7
|
+
load File.dirname(__FILE__) + '/support/models.rb'
|
8
|
+
load File.dirname(__FILE__) + '/support/data.rb'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
self.verbose = false
|
3
|
+
|
4
|
+
begin
|
5
|
+
drop_table :users
|
6
|
+
drop_table :friendships
|
7
|
+
drop_table :things
|
8
|
+
rescue
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :users do |t|
|
12
|
+
t.string :login
|
13
|
+
t.integer :friends_count, :default => 0, :null => false
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :friendships do |t|
|
17
|
+
t.references :user, :friend
|
18
|
+
t.string :status
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :things do |t|
|
23
|
+
t.references :friendship
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_friends
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- embs
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-06-17 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: thor
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activerecord
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rails3-generators
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
type: :development
|
75
|
+
version_requirements: *id004
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: sqlite3
|
78
|
+
prerelease: false
|
79
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
type: :development
|
89
|
+
version_requirements: *id005
|
90
|
+
description: This gem is based on homonym plugin from fnando https://github.com/fnando/has_friends
|
91
|
+
email:
|
92
|
+
- embs@cin.ufpe.br
|
93
|
+
executables:
|
94
|
+
- has_friends
|
95
|
+
extensions: []
|
96
|
+
|
97
|
+
extra_rdoc_files: []
|
98
|
+
|
99
|
+
files:
|
100
|
+
- .gitignore
|
101
|
+
- .rspec
|
102
|
+
- Gemfile
|
103
|
+
- MIT-LICENSE
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- bin/has_friends
|
107
|
+
- has_friends.gemspec
|
108
|
+
- lib/friendship.rb
|
109
|
+
- lib/has_friends.rb
|
110
|
+
- lib/has_friends/cli.rb
|
111
|
+
- lib/has_friends/generators/friends_counter.rb
|
112
|
+
- lib/has_friends/generators/install.rb
|
113
|
+
- lib/has_friends/generators/templates/add_friends_counter.rb
|
114
|
+
- lib/has_friends/generators/templates/create_friendships.rb
|
115
|
+
- lib/has_friends/version.rb
|
116
|
+
- log/test.log
|
117
|
+
- spec/lib/has_friends_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
- spec/support/data.rb
|
120
|
+
- spec/support/models.rb
|
121
|
+
- spec/support/schema.rb
|
122
|
+
homepage: http://cin.ufpe.br/~embs
|
123
|
+
licenses: []
|
124
|
+
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 3
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
version: "0"
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
hash: 3
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
version: "0"
|
148
|
+
requirements: []
|
149
|
+
|
150
|
+
rubyforge_project: has_friends
|
151
|
+
rubygems_version: 1.8.10
|
152
|
+
signing_key:
|
153
|
+
specification_version: 3
|
154
|
+
summary: Add has_friends functionality to your ActiveRecord models
|
155
|
+
test_files: []
|
156
|
+
|