has_friends-rails3 0.0.3

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/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.markdown ADDED
@@ -0,0 +1,123 @@
1
+ has_friends
2
+ ===========
3
+
4
+ **ATTENTION:** This is a Rails 3 implementation.
5
+
6
+ NOTE: You should have a User model. When you execute the plugin generator, I'll add a column
7
+ friends_count on users' table.
8
+
9
+
10
+ Instalation
11
+ -----------
12
+
13
+ 1) Add a gem line to your Gemfile. `gem 'has_friends-rails3, :require => 'has_friends'`
14
+
15
+ 2) Execute the plugin generator `rails g has_friends:migration`
16
+
17
+ 3) Run the migrations with `rake db:migrate`
18
+
19
+ Usage
20
+ -----
21
+
22
+ 1) Add the method call `has_friends` to your model.
23
+
24
+ class User < ActiveRecord::Base
25
+ has_friends
26
+ end
27
+
28
+ john = User.find_by_login 'john'
29
+ mary = User.find_by_login 'mary'
30
+ paul = User.find_by_login 'paul'
31
+
32
+ # John wants to be friend with Mary
33
+ # always return a friendship object
34
+ john.be_friends_with(mary, "Hi Mary! I have worked with you on Meroy Merlin!")
35
+
36
+ # Creating a new Relation kind
37
+ RelationType.create(:name => "coworker")
38
+
39
+ # You can pass kind of relationship, when...
40
+ john.be_friends_with(mary, "Hi Mary! I have worked with you on Meroy Merlin!", [:coworker])
41
+
42
+ # if you specify a non existent Relation,
43
+ # it will create a new Relation
44
+ # and associate then to friendship
45
+ john.be_friends_with(mary, "Hi Mary! I have worked with you on Meroy Merlin!", [:coworker, :friend])
46
+ # In this case, friend is a new relation
47
+
48
+ # are they friends?
49
+ john.friends?(mary) ==> false
50
+
51
+ # get the friendship object
52
+ john.friendship_for(mary)
53
+
54
+ # Mary accepts John's request if it exists...
55
+ mary.accept_friendship_with(john)
56
+ mary.friends?(john) ==> true
57
+
58
+ # either if Mary request John's friendship, then they will be friends automatically.
59
+ mary.be_friends_with(john)
60
+ mary.friends?(john) ==> true
61
+
62
+ # Mary can reject John's friendship.
63
+ mary.remove_friendship_with(john)
64
+
65
+ # check if an user is the current user, so it can
66
+ # be differently presented
67
+ mary.friends.each {|friend| friend.is?(current_user) }
68
+
69
+ # if you're dealing with a friendship object,
70
+ # the following methods are available
71
+ friendship.accept!
72
+
73
+ # You can specify relations when accept a friendship, so...
74
+ friendship.accept!([:friend])
75
+
76
+ # If you want to accept friendship and clear current relations...
77
+ friendship.accept!([])
78
+
79
+ # the be_friends_with method returns 2 params: friendship object and status.
80
+ # the friendship object will be present only when the friendship is created
81
+ # (that is, when is requested for the first time)
82
+ # STATUS_ALREADY_FRIENDS # => users are already friends
83
+ # STATUS_ALREADY_REQUESTED # => user has already requested friendship
84
+ # STATUS_IS_YOU # => user is trying add himself as friend
85
+ # STATUS_FRIEND_IS_REQUIRED # => friend argument is missing
86
+ # STATUS_FRIENDSHIP_ACCEPTED # => friendship has been accepted
87
+ # STATUS_REQUESTED # => friendship has been requested
88
+
89
+ friendship, status = mary.be_friends_with(john)
90
+
91
+ if status == Friendship::STATUS_REQUESTED
92
+ # the friendship has been requested
93
+ Mailer.deliver_friendship_request(friendship)
94
+ elsif status == Friendship::STATUS_ALREADY_FRIENDS
95
+ # they're already friends
96
+ else
97
+ # ...
98
+ end
99
+
100
+
101
+ LICENSE:
102
+ --------
103
+
104
+ (The MIT License)
105
+
106
+ Permission is hereby granted, free of charge, to any person obtaining
107
+ a copy of this software and associated documentation files (the
108
+ 'Software'), to deal in the Software without restriction, including
109
+ without limitation the rights to use, copy, modify, merge, publish,
110
+ distribute, sublicense, and/or sell copies of the Software, and to
111
+ permit persons to whom the Software is furnished to do so, subject to
112
+ the following conditions:
113
+
114
+ The above copyright notice and this permission notice shall be
115
+ included in all copies or substantial portions of the Software.
116
+
117
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
118
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
119
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
120
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
121
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
122
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
123
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/RakeFile ADDED
@@ -0,0 +1,25 @@
1
+ if defined?(Rspec)
2
+ require 'spec/rake/spectask'
3
+
4
+ namespace :has_friends do
5
+ desc "Run all specs in spec directory (excluding plugin specs)"
6
+ Spec::Rake::SpecTask.new(:spec) do |t|
7
+ t.spec_files = FileList["spec/**/*_spec.rb"]
8
+ end
9
+ end
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gemspec|
15
+ gemspec.name = "has_friends-rails3"
16
+ gemspec.summary = "Rails 3 version of has_friends gem"
17
+ gemspec.description = "Rails 3 version of has_friends gem"
18
+ gemspec.email = "rrouse@rachotech.com"
19
+ gemspec.homepage = "http://github.com/rrouse/has_friends"
20
+ gemspec.authors = ["Robert Rouse"]
21
+ gemspec.files.include %w(lib/**/*.rb)
22
+ end
23
+ rescue LoadError
24
+ puts "Jeweler not available. Install it with: gem install jeweler"
25
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
@@ -0,0 +1,72 @@
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
+
10
+ FRIENDSHIP_ACCEPTED = "accepted"
11
+ FRIENDSHIP_PENDING = "pending"
12
+ FRIENDSHIP_REQUESTED = "requested"
13
+
14
+ # scopes
15
+ scope :pending, :conditions => {:status => FRIENDSHIP_PENDING}
16
+ scope :accepted, :conditions => {:status => FRIENDSHIP_ACCEPTED}
17
+ scope :requested, :conditions => {:status => FRIENDSHIP_REQUESTED}
18
+
19
+ # associations
20
+ belongs_to :user
21
+ belongs_to :friend, :class_name => 'User', :foreign_key => 'friend_id'
22
+ belongs_to :message, :class_name => "FriendshipMessage", :foreign_key => "friendship_message_id", :dependent => :destroy
23
+
24
+ has_many :friendship_relations, :class_name => "FriendshipRelationType", :readonly => true, :dependent => :destroy
25
+ has_many :relations, :through => :friendship_relations, :class_name => "RelationType", :source => :relation
26
+
27
+ # callback
28
+ after_destroy do |f|
29
+ User.decrement_counter(:friends_count, f.user_id) if f.status == FRIENDSHIP_ACCEPTED
30
+ end
31
+
32
+ def pending?
33
+ status == FRIENDSHIP_PENDING
34
+ end
35
+
36
+ def accepted?
37
+ status == FRIENDSHIP_ACCEPTED
38
+ end
39
+
40
+ def requested?
41
+ status == FRIENDSHIP_REQUESTED
42
+ end
43
+
44
+ def accept!(new_relation_names = nil)
45
+ unless accepted?
46
+ self.transaction do
47
+ User.increment_counter(:friends_count, user_id)
48
+ update_attribute(:status, FRIENDSHIP_ACCEPTED)
49
+ update_attribute(:accepted_at, Time.now)
50
+ add_relations(new_relation_names) unless new_relation_names.nil?
51
+ end
52
+ end
53
+ end
54
+
55
+ def add_relations(new_relation_names = [])
56
+ self.transaction do
57
+ actual_relation_names = self.relation_names
58
+ self.friendship_relations.each do |fr|
59
+ fr.destroy unless actual_relation_names.include?(fr.relation.name.to_sym)
60
+ end
61
+
62
+ new_relation_names.each do |nr|
63
+ relation = RelationType.find_or_create_by_name(nr.to_s)
64
+ self.relations << relation unless relations.include?(relation)
65
+ end
66
+ end
67
+ end
68
+
69
+ def relation_names
70
+ relations.all(:select => :name, :order => :name).collect{|r| r.name}
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ class FriendshipMessage < ActiveRecord::Base
2
+ validates :body, :presence => true
3
+ end
@@ -0,0 +1,4 @@
1
+ class FriendshipRelationType < ActiveRecord::Base
2
+ belongs_to :friendship
3
+ belongs_to :relation, :class_name => "RelationType"
4
+ end
@@ -0,0 +1,10 @@
1
+ class RelationType < ActiveRecord::Base
2
+ validates :name, :presence => true
3
+
4
+ after_destroy :destroy_all_friendsip_relations
5
+
6
+ private
7
+ def destroy_all_friendsip_relations
8
+ FriendshipRelationType.delete_all :relation_id => self.id
9
+ end
10
+ end
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in RakeFile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{has_friends-rails3}
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Robert Rouse"]
12
+ s.date = %q{2010-07-25}
13
+ s.description = %q{Rails 3 version of has_friends gem}
14
+ s.email = %q{rrouse@rachotech.com}
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
18
+ s.files = [
19
+ "MIT-LICENSE",
20
+ "README.markdown",
21
+ "RakeFile",
22
+ "VERSION",
23
+ "app/models/friendship.rb",
24
+ "app/models/friendship_message.rb",
25
+ "app/models/friendship_relation_type.rb",
26
+ "app/models/relation_type.rb",
27
+ "has_friends-rails3.gemspec",
28
+ "lib/generators/has_friends.rb",
29
+ "lib/generators/has_friends/migration/migration_generator.rb",
30
+ "lib/generators/has_friends/migration/templates/create_has_friends_tables.rb",
31
+ "lib/has_friends.rb",
32
+ "lib/has_friends/engine.rb",
33
+ "lib/has_friends/exceptions.rb",
34
+ "lib/has_friends/has_friends.rb",
35
+ "spec/fixtures/relation_types.yml",
36
+ "spec/fixtures/users.yml",
37
+ "spec/friendship_message_spec.rb",
38
+ "spec/friendship_relation_type_spec.rb",
39
+ "spec/friendship_spec.rb",
40
+ "spec/has_friends_spec.rb",
41
+ "spec/relation_type_spec.rb",
42
+ "spec/schema.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+ s.homepage = %q{http://github.com/rrouse/has_friends}
46
+ s.rdoc_options = ["--charset=UTF-8"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.7}
49
+ s.summary = %q{Rails 3 version of has_friends gem}
50
+ s.test_files = [
51
+ "spec/friendship_message_spec.rb",
52
+ "spec/friendship_relation_type_spec.rb",
53
+ "spec/friendship_spec.rb",
54
+ "spec/has_friends_spec.rb",
55
+ "spec/relation_type_spec.rb",
56
+ "spec/schema.rb",
57
+ "spec/spec_helper.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
+ else
66
+ end
67
+ else
68
+ end
69
+ end
70
+
@@ -0,0 +1,14 @@
1
+ require 'generators/has_friends'
2
+
3
+ module HasFriends
4
+ module Generators
5
+ class MigrationGenerator < Base
6
+ desc "Generate has_friends migration"
7
+
8
+ def create_migration_file
9
+ migration_template "create_has_friends_tables.rb", File.join('db', 'migrate', "create_has_friends_tables.rb")
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ class CreateHasFriendsTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :friendships, :force => true do |t|
4
+ t.references :user, :friend, :friendship_message
5
+ t.datetime :requested_at, :accepted_at
6
+ t.string :status
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :friendships, :user_id
11
+ add_index :friendships, :friend_id
12
+ add_index :friendships, :status
13
+
14
+ create_table :relation_types, :force => true do |t|
15
+ t.string :name
16
+ t.timestamps
17
+ end
18
+
19
+ add_index :relation_types, :name
20
+
21
+ create_table :friendship_messages, :force => true do |t|
22
+ t.string :body
23
+ t.timestamps
24
+ end
25
+
26
+ create_table :friendship_relation_types, :force => true do |t|
27
+ t.references :relation, :friendship
28
+ t.timestamps
29
+ end
30
+
31
+ add_column :users, :friends_count, :integer, :default => 0, :null => false
32
+ end
33
+
34
+ def self.down
35
+ remove_column :users, :friends_count
36
+
37
+ drop_table :friendship_relation_types
38
+ drop_table :friendship_messages
39
+ drop_table :relation_types
40
+ drop_table :friendships
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ require 'rails/generators/migration'
2
+
3
+ module HasFriends
4
+ module Generators
5
+ class Base < Rails::Generators::Base
6
+
7
+ include Rails::Generators::Migration
8
+
9
+ def self.source_root
10
+ @_has_friends_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'has_friends', generator_name, 'templates'))
11
+ end
12
+
13
+ def self.next_migration_number(path)
14
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ require 'has_friends'
2
+ require 'rails'
3
+
4
+ module Has
5
+ module Friends
6
+ class Engine < Rails::Engine
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1 @@
1
+ class YouCanNotJudgeARequestFriendshipError < StandardError; end
@@ -0,0 +1,118 @@
1
+ module Has
2
+ module Friends
3
+ def self.included(base)
4
+ base.extend Has::Friends::ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def has_friends
9
+ include Has::Friends::InstanceMethods
10
+
11
+ has_many :friendships
12
+ has_many :friends, :through => :friendships, :source => :friend, :conditions => "friendships.status = 'accepted'"
13
+
14
+ after_destroy :destroy_all_friendships
15
+ end
16
+ end
17
+
18
+ module InstanceMethods
19
+ def be_friends_with(friend, message = nil, relations = [])
20
+ # no user object
21
+ return nil, Friendship::STATUS_FRIEND_IS_REQUIRED unless friend
22
+
23
+ # should not create friendship if user is trying to add himself
24
+ return nil, Friendship::STATUS_IS_YOU if is?(friend)
25
+
26
+ # should not create friendship if users are already friends
27
+ return nil, Friendship::STATUS_ALREADY_FRIENDS if friends?(friend)
28
+
29
+ # retrieve the friendship request
30
+ friendship = self.friendship_for(friend)
31
+
32
+ # let's check if user has already a friendship request or have removed
33
+ request = friend.friendship_for(self)
34
+
35
+ # friendship has already been requested
36
+ return nil, Friendship::STATUS_ALREADY_REQUESTED if friendship && friendship.requested?
37
+
38
+ # friendship is pending so accept it
39
+ if friendship && friendship.pending?
40
+ ActiveRecord::Base.transaction do
41
+ friendship.accept!
42
+ request.accept!
43
+ end
44
+
45
+ return friendship, Friendship::STATUS_FRIENDSHIP_ACCEPTED
46
+ end
47
+
48
+ ActiveRecord::Base.transaction do
49
+ message = FriendshipMessage.create(:body => message) if message
50
+
51
+ # we didn't find a friendship, so let's create one!
52
+ friendship = self.friendships.create(:friend_id => friend.id, :status => 'requested', :message => message, :requested_at => Time.now)
53
+ friendship.add_relations(relations)
54
+
55
+ # we didn't find a friendship request, so let's create it!
56
+ request = friend.friendships.create(:friend_id => id, :status => 'pending', :message => message, :requested_at => Time.now)
57
+ request.add_relations(relations)
58
+ end
59
+
60
+ return friendship, Friendship::STATUS_REQUESTED
61
+ end
62
+
63
+ def friends?(friend)
64
+ friendship = friendship_for(friend)
65
+ !!(friendship && friendship.accepted?)
66
+ end
67
+
68
+ def friendship_for(friend)
69
+ friendships.first :conditions => {:friend_id => friend.id}
70
+ end
71
+
72
+ def is?(friend)
73
+ self.id == friend.id
74
+ end
75
+
76
+ def remove_friendship_with(friend)
77
+ ActiveRecord::Base.transaction do
78
+ [friendship_for(friend), friend.friendship_for(self)].compact.each do |friendship|
79
+ friendship.destroy if friendship
80
+ end
81
+ end
82
+ end
83
+
84
+ def deny_friendship_with(friend)
85
+ if (pendent = self.friendship_for(friend)).pending?
86
+ ActiveRecord::Base.transaction do
87
+ [friendship_for(friend), friend.friendship_for(self)].compact.each do |friendship|
88
+ friendship.destroy if friendship
89
+ end
90
+ end
91
+ else
92
+ raise YouCanNotJudgeARequestFriendshipError
93
+ end
94
+ end
95
+
96
+ def accept_friendship_with(friend, relations = nil)
97
+ if (pendent = self.friendship_for(friend)).pending?
98
+ requested = friend.friendship_for(self)
99
+
100
+ ActiveRecord::Base.transaction do
101
+ pendent.accept!(relations)
102
+ requested.accept! unless requested.accepted?
103
+ end
104
+ else
105
+ raise YouCanNotJudgeARequestFriendshipError
106
+ end
107
+ end
108
+
109
+ private
110
+ def destroy_all_friendships
111
+ ActiveRecord::Base.transaction do
112
+ Friendship.delete_all({:user_id => id})
113
+ Friendship.delete_all({:friend_id => id})
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,5 @@
1
+ require 'has_friends/engine'
2
+ require 'has_friends/has_friends'
3
+ require 'has_friends/exceptions'
4
+
5
+ ActiveRecord::Base.send(:include, Has::Friends)
@@ -0,0 +1,8 @@
1
+ friend:
2
+ name: friend
3
+
4
+ met:
5
+ name: met
6
+
7
+ coworker:
8
+ name: coworker
@@ -0,0 +1,14 @@
1
+ vader:
2
+ login: darth_vader
3
+
4
+ luke:
5
+ login: luke_skywalker
6
+
7
+ leia:
8
+ login: princess_leia
9
+
10
+ han_solo:
11
+ login: han_solo
12
+
13
+ yoda:
14
+ login: yoda
@@ -0,0 +1,10 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe FriendshipMessage do
4
+ it "should require a body" do
5
+ @message = FriendshipMessage.new
6
+
7
+ @message.should_not be_valid
8
+ @message.errors[:body].should == "can't be blank"
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe FriendshipRelationType do
4
+ describe "structure" do
5
+ it "should belong_to :friendship" do
6
+ @friendship = Friendship.new
7
+ @friendship_relation = FriendshipRelationType.new :friendship => @friendship
8
+ @friendship_relation.friendship.should == @friendship
9
+ end
10
+
11
+ it "should belong_to :relation" do
12
+ @relation = RelationType.new
13
+ @friendship_relation = FriendshipRelationType.new :relation => @relation
14
+ @friendship_relation.relation.should == @relation
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,113 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe Friendship do
4
+ fixtures :all
5
+
6
+ describe "structure" do
7
+ before(:each) do
8
+ @friendship = Friendship.new
9
+ end
10
+
11
+ it "should belong to user" do
12
+ @friendship.user = @vader
13
+ @friendship.user.should == @vader
14
+ end
15
+
16
+ it "should_belong to friend" do
17
+ @friendship.friend = @luke
18
+ @friendship.friend.should == @luke
19
+ end
20
+
21
+ it "should belong to message" do
22
+ @message = FriendshipMessage.new :body => "Luke, I'm your father!"
23
+ @friendship.message = @vader_message_for_luke
24
+ @friendship.message.should == @vader_message_for_luke
25
+ end
26
+
27
+ it "should has many relations" do
28
+ @friendship.relations << @friend
29
+ @friendship.relations << @coworker
30
+
31
+ @friendship.relations.should == [@friend, @coworker]
32
+ end
33
+
34
+ it "should list relations names" do
35
+ @friendship.relations << @friend
36
+ @friendship.relations << @coworker
37
+ @friendship.save
38
+ @friendship.reload
39
+
40
+ @friendship.relation_names.should == ["coworker", "friend"]
41
+ end
42
+ end
43
+
44
+ it "should be pending status" do
45
+ @friendship = Friendship.new(:status => 'pending')
46
+ @friendship.should be_pending
47
+ end
48
+
49
+ it "should be accepted status" do
50
+ @friendship = Friendship.new(:status => 'accepted')
51
+ @friendship.should be_accepted
52
+ end
53
+
54
+ it "should be requested status" do
55
+ @friendship = Friendship.new(:status => 'requested')
56
+ @friendship.should be_requested
57
+ end
58
+
59
+ describe "on accept pending friendship" do
60
+ before(:each) do
61
+ @friendship = Friendship.create(:user => @vader, :friend => @luke, :status => Friendship::FRIENDSHIP_PENDING)
62
+ end
63
+
64
+ it "should be ok" do
65
+ @friendship.accept!
66
+ @friendship.status.should == Friendship::FRIENDSHIP_ACCEPTED
67
+ end
68
+
69
+ it "should be ok and add new relations" do
70
+ @friendship.accept!([:met, :coworker])
71
+ @friendship.status.should == Friendship::FRIENDSHIP_ACCEPTED
72
+ @friendship.relations.size == 2
73
+ @friendship.relations.should == [@met, @coworker]
74
+ end
75
+
76
+ describe "with relations" do
77
+ before(:each) do
78
+ [@friend, @met].each do |r|
79
+ @friendship.relations << r
80
+ end
81
+ @friendship.save
82
+ end
83
+
84
+ it "should be ok and no change current relations" do
85
+ @friendship.accept!
86
+ @friendship.reload
87
+
88
+ @friendship.status.should == Friendship::FRIENDSHIP_ACCEPTED
89
+ @friendship.relations.size.should == 2
90
+ @friendship.relations.should == [@friend, @met]
91
+ end
92
+
93
+ it "should be ok and change relations" do
94
+ @friendship.accept!([:met, :coworker])
95
+ @friendship.reload
96
+
97
+ @friendship.status.should == Friendship::FRIENDSHIP_ACCEPTED
98
+ @friendship.relations.size.should == 2
99
+ @friendship.relations.should == [@met, @coworker]
100
+ end
101
+
102
+ it "should be ok and clear current relations" do
103
+ @friendship.accept!([])
104
+ @friendship.reload
105
+
106
+ @friendship.status.should == Friendship::FRIENDSHIP_ACCEPTED
107
+ @friendship.relations.size.should == 0
108
+ @friendship.relations.should == []
109
+ end
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,252 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe "has_friends" do
4
+ fixtures :all
5
+
6
+ describe "methods" do
7
+ it "should respond to has_friends method" do
8
+ User.should respond_to(:has_friends)
9
+ end
10
+
11
+ it "should respond to be_friends_with method" do
12
+ @vader.should respond_to(:be_friends_with)
13
+ end
14
+
15
+ it "should respond to friends? method" do
16
+ @vader.should respond_to(:friends?)
17
+ end
18
+
19
+ it "should respond to accept_friendship_with" do
20
+ @vader.should respond_to(:accept_friendship_with)
21
+ end
22
+
23
+ it "should respond to remove_friendship_with" do
24
+ @vader.should respond_to(:remove_friendship_with)
25
+ end
26
+ end
27
+
28
+ describe "user" do
29
+ before(:each) do
30
+ #requesting friendship between @vader and @luke
31
+ @vader.be_friends_with(@luke)
32
+ @leia.be_friends_with(@luke)
33
+ @luke.accept_friendship_with(@leia)
34
+ end
35
+
36
+ it "should accept a friendship" do
37
+ @luke.accept_friendship_with(@vader)
38
+
39
+ @luke.reload
40
+ @vader.reload
41
+
42
+ @vader.friends.should == [@luke]
43
+ @luke.friends.should == [@vader, @leia]
44
+ @vader.friends_count.should == 1
45
+ @luke.friends_count.should == 2
46
+ end
47
+
48
+ it "should accept a friendship with relation types" do
49
+ doing {
50
+ @luke.accept_friendship_with(@vader, [:parent, :met])
51
+ }.should change(FriendshipRelationType, :count).by(2)
52
+ end
53
+
54
+ it "should reject when user try accept his friendship request" do
55
+ lambda { @vader.accept_friendship_with(@luke) }.should raise_error(YouCanNotJudgeARequestFriendshipError)
56
+
57
+ @luke.reload
58
+ @vader.reload
59
+
60
+ @vader.friends.should == []
61
+ @luke.friends.should == [@leia]
62
+ @vader.friends_count.should == 0
63
+ @luke.friends_count.should == 1
64
+ end
65
+
66
+ it "should accept a friendship with relation types" do
67
+ @luke.deny_friendship_with(@vader)
68
+
69
+ @luke.reload
70
+ @vader.reload
71
+
72
+ @vader.friends.should == []
73
+ @luke.friends.should == [@leia]
74
+ @vader.friends_count.should == 0
75
+ @luke.friends_count.should == 1
76
+ end
77
+
78
+ it "should reject when user try deny his friendship request" do
79
+ lambda { @vader.deny_friendship_with(@luke) }.should raise_error(YouCanNotJudgeARequestFriendshipError)
80
+
81
+ @luke.reload
82
+ @vader.reload
83
+
84
+ @vader.friends.should == []
85
+ @luke.friends.should == [@leia]
86
+ @vader.friends_count.should == 0
87
+ @luke.friends_count.should == 1
88
+ end
89
+
90
+ it "should remove a friendship" do
91
+ #make @vader and @luke friends
92
+ @luke.be_friends_with(@vader)
93
+
94
+ @vader.remove_friendship_with(@luke)
95
+
96
+ @luke.reload
97
+ @vader.reload
98
+
99
+ @vader.friends.should == []
100
+ @luke.friends.should == [@leia]
101
+ @vader.friends_count.should == 0
102
+ @luke.friends_count.should == 1
103
+ end
104
+ end
105
+
106
+ describe "friends" do
107
+ before(:each) do
108
+ create_friendship @vader, @luke
109
+ create_friendship @vader, @leia
110
+ create_friendship @luke, @leia
111
+ create_friendship @luke, @yoda
112
+ create_friendship @leia, @han_solo
113
+ end
114
+
115
+ it "should order vader's friends" do
116
+ # => princess_leia, luke_skywalker
117
+ @vader.friends.all(:order => 'login desc').should == [@leia, @luke]
118
+ end
119
+
120
+ it "should return luke's friends" do
121
+ @luke.friends.should == [@vader, @leia, @yoda]
122
+ end
123
+
124
+ it "should return leia's frieds" do
125
+ @leia.friends.should == [@vader, @luke, @han_solo]
126
+ end
127
+
128
+ it "should return yoda's friends" do
129
+ @yoda.friends.should == [@luke]
130
+ end
131
+
132
+ it "should return solo's friends" do
133
+ @han_solo.friends.should == [@leia]
134
+ end
135
+
136
+ it "should increment counter" do
137
+ @vader.reload
138
+ @vader.friends_count.should == 2
139
+ end
140
+
141
+ it "should decrement counter" do
142
+ friendship = @vader.friendship_for(@luke)
143
+ friendship.destroy
144
+
145
+ @vader.reload
146
+ @vader.friends_count.should == 1
147
+ end
148
+
149
+ it "should be @vader" do
150
+ @vader.is?(@vader).should be_true
151
+ end
152
+
153
+ it "should not be @vader" do
154
+ @vader.is?(@leia).should_not be_true
155
+ end
156
+ end
157
+
158
+ describe "friendship request" do
159
+ it "should return nil and 'friend is required' status" do
160
+ friendship, status = @vader.be_friends_with(nil)
161
+
162
+ friendship.should be_nil
163
+ status.should == Friendship::STATUS_FRIEND_IS_REQUIRED
164
+ end
165
+
166
+ it "should return nil and 'is you' status" do
167
+ friendship, status = @vader.be_friends_with(@vader)
168
+
169
+ friendship.should be_nil
170
+ status.should == Friendship::STATUS_IS_YOU
171
+ end
172
+
173
+ it "should return nil and 'already friends status" do
174
+ @vader.be_friends_with(@luke)
175
+ @luke.be_friends_with(@vader)
176
+ friendship, status = @vader.be_friends_with(@luke)
177
+
178
+ friendship.should be_nil
179
+ status.should == Friendship::STATUS_ALREADY_FRIENDS
180
+ end
181
+
182
+ it "should return nil and 'already requested' status" do
183
+ @vader.be_friends_with(@luke)
184
+ friendship, status = @vader.be_friends_with(@luke)
185
+
186
+ friendship.should be_nil
187
+ status.should == Friendship::STATUS_ALREADY_REQUESTED
188
+ end
189
+
190
+ it "should return friendship and 'accepted friendship' status" do
191
+ @vader.be_friends_with(@luke)
192
+ friendship, status = @luke.be_friends_with(@vader)
193
+
194
+ friendship.should be_kind_of(Friendship)
195
+ status.should == Friendship::STATUS_FRIENDSHIP_ACCEPTED
196
+ @vader.should be_friends(@luke)
197
+ @luke.should be_friends(@vader)
198
+ end
199
+
200
+ it "should create friendships" do
201
+ doing {
202
+ friendship, status = @vader.be_friends_with(@luke)
203
+
204
+ @vader.friendships.count.should == 1
205
+ @luke.friendships.count.should == 1
206
+ status.should == Friendship::STATUS_REQUESTED
207
+ }.should change(Friendship, :count).by(2)
208
+ end
209
+
210
+ it "should create friendship with message" do
211
+ doing {
212
+ friendship, status = @vader.be_friends_with(@luke, "Luke, I'm your father!")
213
+ friendship.message.body.should == "Luke, I'm your father!"
214
+ }.should change(FriendshipMessage, :count).by(1)
215
+ end
216
+
217
+ it "should create friendship with exist relations" do
218
+ doing {
219
+ doing {
220
+ friendship, status = @vader.be_friends_with(@luke, nil, [:met, :friend])
221
+ }.should change(FriendshipRelationType, :count).by(4)
222
+ }.should_not change(RelationType, :count)
223
+ end
224
+
225
+ it "should create friendship with new relations" do
226
+ doing {
227
+ friendship, status = @vader.be_friends_with(@luke, nil, [:parent, :met])
228
+ }.should change(RelationType, :count).by(1)
229
+ end
230
+ end
231
+
232
+ describe "pagination" do
233
+ before(:each) do
234
+ pending unless Object.const_defined?('Paginate')
235
+
236
+ create_friendship @vader, @luke
237
+ create_friendship @vader, @leia
238
+ create_friendship @vader, @han_solo
239
+ end
240
+
241
+ it "should paginate friends" do
242
+ @vader.friends.paginate(:limit => 1).to_a.should == [@luke, @leia]
243
+ end
244
+ end
245
+
246
+ private
247
+ def create_friendship(user1, user2)
248
+ user1.be_friends_with(user2)
249
+ user2.be_friends_with(user1)
250
+ end
251
+
252
+ end
@@ -0,0 +1,9 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe RelationType do
4
+ it "should require a name" do
5
+ @relation_type = RelationType.new
6
+ @relation_type.should_not be_valid
7
+ @relation_type.errors[:name].should == "can't be blank"
8
+ end
9
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,37 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ begin
3
+ drop_table :users
4
+ drop_table :friendships
5
+ drop_table :friendship_messages
6
+ drop_table :relations_types
7
+ drop_table :friendship_relations
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, :friendship_message
18
+ t.string :status
19
+ t.timestamps
20
+ end
21
+
22
+ create_table :friendship_messages do |t|
23
+ t.string :body
24
+ t.timestamps
25
+ end
26
+
27
+ create_table :relation_types do |t|
28
+ t.string :name
29
+ t.timestamps
30
+ end
31
+
32
+ create_table :friendship_relation_types do |t|
33
+ t.references :relation, :friendship
34
+ t.timestamps
35
+ end
36
+
37
+ end
@@ -0,0 +1,37 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "../../../../config/environment"))
4
+ require "spec"
5
+ require "spec/rails"
6
+ require "ruby-debug"
7
+
8
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ":memory:"}}
9
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["test"])
10
+
11
+ load(File.join(File.dirname(__FILE__), 'schema.rb'))
12
+
13
+ Spec::Runner.configure do |config|
14
+ config.use_transactional_fixtures = true
15
+ config.use_instantiated_fixtures = true
16
+ config.fixture_path = File.dirname(__FILE__) + '/fixtures/'
17
+ end
18
+
19
+ class Object
20
+ def self.unset_class(*args)
21
+ class_eval do
22
+ args.each do |klass|
23
+ eval(klass) rescue nil
24
+ remove_const(klass) if const_defined?(klass)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ alias :doing :lambda
31
+
32
+ # unset models used for testing purposes
33
+ Object.unset_class('User')
34
+
35
+ class User < ActiveRecord::Base
36
+ has_friends
37
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_friends-rails3
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 3
9
+ version: 0.0.3
10
+ platform: ruby
11
+ authors:
12
+ - Robert Rouse
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-25 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Rails 3 version of has_friends gem
22
+ email: rrouse@rachotech.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.markdown
29
+ files:
30
+ - MIT-LICENSE
31
+ - README.markdown
32
+ - RakeFile
33
+ - VERSION
34
+ - app/models/friendship.rb
35
+ - app/models/friendship_message.rb
36
+ - app/models/friendship_relation_type.rb
37
+ - app/models/relation_type.rb
38
+ - has_friends-rails3.gemspec
39
+ - lib/generators/has_friends.rb
40
+ - lib/generators/has_friends/migration/migration_generator.rb
41
+ - lib/generators/has_friends/migration/templates/create_has_friends_tables.rb
42
+ - lib/has_friends.rb
43
+ - lib/has_friends/engine.rb
44
+ - lib/has_friends/exceptions.rb
45
+ - lib/has_friends/has_friends.rb
46
+ - spec/fixtures/relation_types.yml
47
+ - spec/fixtures/users.yml
48
+ - spec/friendship_message_spec.rb
49
+ - spec/friendship_relation_type_spec.rb
50
+ - spec/friendship_spec.rb
51
+ - spec/has_friends_spec.rb
52
+ - spec/relation_type_spec.rb
53
+ - spec/schema.rb
54
+ - spec/spec_helper.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/rrouse/has_friends
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.7
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Rails 3 version of has_friends gem
87
+ test_files:
88
+ - spec/friendship_message_spec.rb
89
+ - spec/friendship_relation_type_spec.rb
90
+ - spec/friendship_spec.rb
91
+ - spec/has_friends_spec.rb
92
+ - spec/relation_type_spec.rb
93
+ - spec/schema.rb
94
+ - spec/spec_helper.rb