amistad 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ A history of changes to the gem...
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Rawane ZOSSOU
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,107 @@
1
+ # amistad #
2
+
3
+ Amistad adds friendships management into a rails 3.0 application.
4
+
5
+ ## Installation ##
6
+
7
+ Just run the following command :
8
+
9
+ gem install amistad
10
+
11
+ Then in your gem file add the following line :
12
+
13
+ gem 'amistad'
14
+
15
+ ## Usage ##
16
+
17
+ First generate a friendship model :
18
+
19
+ rails generate friendship
20
+
21
+ This commands create a new model called __friendship__ in *'app/models'* :
22
+
23
+ class Friendship < ActiveRecord::Base
24
+ acts_as_friendship
25
+ end
26
+
27
+ It also creates a new migration for the friendship model so don't forget to migrate your database :
28
+
29
+ db:migrate
30
+
31
+ Then activate __amistad__ in your user model :
32
+
33
+ class User < ActiveRecord::Base
34
+ acts_as_friend
35
+ end
36
+
37
+ ## Friendships management ##
38
+
39
+ ### Creating friendships ###
40
+ To create a new friendship with another user use the method called __invite()__ :
41
+
42
+ @john.invite @jane
43
+ @peter.invite @john
44
+ @peter.invite @jane
45
+ @victoria.invite @john
46
+
47
+ The __invite()__ method return *true* if the friendship successfully created, otherwise it returns *false*. The friendships remain in pending state until they are approved by the user requested. To approve the friendship created above use the method called __approve()__ :
48
+
49
+ @jane.approve @john
50
+ @john.approve @peter
51
+ @jane.approve @peter
52
+
53
+ As __invite()__, __approve()__ return *true* if the friendship was successfuly approved or *false* if not.
54
+
55
+ ### Listing friends ###
56
+
57
+ There are two types of friends in __amistad__ :
58
+
59
+ - the friends who were invited by the user
60
+ - the friends who invited the user
61
+
62
+ To get the friend who where invited by __@john__, use the __invited()__ method :
63
+
64
+ @john.invited #=> [@jane]
65
+
66
+ To get the friends who invited __@john__, use the __invited_by()__ method :
67
+
68
+ @john.invited_by #=> [@peter]
69
+
70
+ To get all the friends of __@john__ (those he invited and those who invited him) :
71
+
72
+ @john.friends #=> [@jane, @peter]
73
+
74
+ To get the pending friendships use :
75
+
76
+ @victoria.pending_invited #=> [@john]
77
+ @john.pending_invited_by #=> [@victoria]
78
+
79
+ It is also possible to check if two users are friends :
80
+
81
+ @john.is_friend_with? @jane #=> true
82
+ @victoria.is_friend_with? @john #=> false
83
+
84
+ You can also find the friends that two users have in common :
85
+
86
+ @john.common_friend_with(@peter) #=> [@jane]
87
+
88
+ ### Removing friendships ###
89
+
90
+ The __remove()__ method allow a user to remove its friendships :
91
+
92
+ @john.remove @jane
93
+ @john.remove @peter
94
+ @john.remove @victoria
95
+
96
+ ## Note on Patches/Pull Requests ##
97
+
98
+ * Fork the project.
99
+ * Make your feature addition or bug fix.
100
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
101
+ *
102
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
103
+ * Send me a pull request. Bonus points for topic branches.
104
+
105
+ ## Copyright ##
106
+
107
+ Copyright © 2010 Rawane ZOSSOU. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "amistad"
7
+ gemspec.summary = "Adds friendships management into a rails 3.0 application"
8
+ gemspec.description = "Extends your user model with friendships management methods"
9
+ gemspec.email = "dev@raw1z.fr"
10
+ gemspec.homepage = "http://github.com/raw1z/amistad"
11
+ gemspec.authors = ["Rawane ZOSSOU"]
12
+ gemspec.files = FileList["[A-Z]*", "{lib}/**/*"]
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
+ end
17
+
18
+ begin
19
+ require 'spec/rake/spectask'
20
+ desc "Run the tests"
21
+ Spec::Rake::SpecTask.new(:spec) do |t|
22
+ t.spec_opts = ["--format", "specdoc", "--color"]
23
+ t.spec_files = Dir.glob('spec/**/*_spec.rb')
24
+ end
25
+ rescue LoadError
26
+ puts "Rspec not available. Install it with: gem install rspec"
27
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/amistad.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.join(File.dirname(__FILE__), 'amistad/friend_model')
2
+ require File.join(File.dirname(__FILE__), 'amistad/friendship_model')
@@ -0,0 +1,92 @@
1
+ module Amistad
2
+ module FriendModel
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def acts_as_friend
9
+ has_many :friendships
10
+
11
+ has_many :pending_invited,
12
+ :through => :friendships,
13
+ :source => :friend,
14
+ :conditions => { :'friendships.pending' => true }
15
+
16
+ has_many :invited,
17
+ :through => :friendships,
18
+ :source => :friend,
19
+ :conditions => { :'friendships.pending' => false }
20
+
21
+ has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
22
+
23
+ has_many :pending_invited_by,
24
+ :through => :inverse_friendships,
25
+ :source => :user,
26
+ :conditions => {:'friendships.pending' => true}
27
+
28
+ has_many :invited_by,
29
+ :through => :inverse_friendships,
30
+ :source => :user,
31
+ :conditions => {:'friendships.pending' => false}
32
+
33
+ class_eval <<-EOV
34
+ include Amistad::FriendModel::InstanceMethods
35
+ EOV
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ def invite(user)
41
+ return false if user == self
42
+
43
+ friendship = find_any_friendship_with(user)
44
+ return false if not friendship.nil?
45
+
46
+ friendship = Friendship.new(:user_id => self.id, :friend_id => user.id)
47
+ friendship.save
48
+ end
49
+
50
+ def approve(user)
51
+ friendship = find_any_friendship_with(user)
52
+ return false if friendship.nil?
53
+ friendship.pending = false
54
+ friendship.save
55
+ end
56
+
57
+ def friends
58
+ self.invited(true) + self.invited_by(true)
59
+ end
60
+
61
+ def remove(user)
62
+ friendship = find_any_friendship_with(user)
63
+ return false if friendship.nil?
64
+ friendship.destroy
65
+ friendship.destroyed?
66
+ end
67
+
68
+ def is_friend_with?(user)
69
+ friends.include?(user)
70
+ end
71
+
72
+ def common_friends_with(user)
73
+ self.friends & user.friends
74
+ end
75
+
76
+ private
77
+
78
+ def find_any_friendship_with(user)
79
+ friendship = Friendship.where(:user_id => self.id, :friend_id => user.id).first
80
+ if friendship.nil?
81
+ friendship = Friendship.where(:user_id => user.id, :friend_id => self.id).first
82
+ end
83
+ friendship
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ class ActiveRecord::Base
91
+ include Amistad::FriendModel
92
+ end
@@ -0,0 +1,32 @@
1
+ module Amistad
2
+ module FriendshipModel
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def acts_as_friendship
10
+ belongs_to :user
11
+ belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
12
+
13
+ validates_presence_of :user_id, :friend_id
14
+
15
+ class_eval <<-EOV
16
+ include Amistad::FriendshipModel::InstanceMethods
17
+ EOV
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def pending?
23
+ self.pending
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ class ActiveRecord::Base
31
+ include Amistad::FriendshipModel
32
+ end
@@ -0,0 +1,21 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class FriendshipGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ def self.next_migration_number
8
+ now = DateTime.now
9
+ "#{now.year}#{'%02d' % now.month}#{'%02d' % now.day}#{'%02d' % now.hour}#{'%02d' % now.minute}#{'%02d' % now.second}"
10
+ end
11
+
12
+ def self.source_root
13
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
14
+ end
15
+
16
+ desc "This generator creates a friendship model and its migration file"
17
+ def create_friendship_model_files
18
+ template 'friendship.rb', 'app/models/friendship.rb'
19
+ template 'create_friendships.rb', "db/migrate/#{self.class.next_migration_number}_create_friendships.rb"
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ class CreateFriendships < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :friendships do |t|
4
+ t.integer :user_id
5
+ t.integer :friend_id
6
+ t.boolean :pending, :default => true
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :friendships
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ class Friendship < ActiveRecord::Base
2
+ acts_as_friendship
3
+ end
@@ -0,0 +1,149 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Amistad::FriendModel do
4
+
5
+ before(:all) do
6
+ %w(John Jane david James Peter Mary Victoria Elisabeth).each do |name|
7
+ eval "@#{name.downcase} = User.create(:name => '#{name}')"
8
+ end
9
+ end
10
+
11
+ context "when creating friendships" do
12
+ before(:each) do
13
+ Friendship.delete_all
14
+ end
15
+
16
+ it "requests frienships with other users" do
17
+ @john.invite(@jane).should == true
18
+ @victoria.invite(@john).should == true
19
+ end
20
+
21
+ it "approves frienships requested by other users" do
22
+ @john.invite(@jane).should == true
23
+ @victoria.invite(@john).should == true
24
+
25
+ @jane.approve(@john).should == true
26
+ @john.approve(@victoria).should == true
27
+ end
28
+
29
+ it "could not create a new friendship with a user which is already a friend" do
30
+ @john.invite(@jane).should == true
31
+ @john.invite(@jane).should == false
32
+ @jane.invite(@john).should == false
33
+ end
34
+
35
+ it "could not create a friendship with himself" do
36
+ @john.invite(@john).should == false
37
+ end
38
+
39
+ it "could not approuve a non-existent friendship" do
40
+ @peter.approve(@john).should == false
41
+ end
42
+ end
43
+
44
+ context "when listing friendships" do
45
+ before(:each) do
46
+ Friendship.delete_all
47
+ @john.invite(@jane).should == true
48
+ @john.invite(@james).should == true
49
+
50
+ @peter.invite(@john).should == true
51
+ @mary.invite(@john).should == true
52
+
53
+ @james.approve(@john).should == true
54
+ @john.approve(@mary).should == true
55
+ end
56
+
57
+ it "lists all the friends" do
58
+ @john.friends.count.should == 2
59
+ @john.friends.should include(@james)
60
+ @john.friends.should include(@mary)
61
+ end
62
+
63
+ it "lists the friends who invited him" do
64
+ @john.invited_by.should include(@mary)
65
+ @john.invited_by.should_not include(@peter)
66
+ end
67
+
68
+ it "lists the friends who was invited by him" do
69
+ @john.invited.should include(@james)
70
+ @john.invited.should_not include(@jane)
71
+ end
72
+
73
+ it "lists the pending friends who invited him" do
74
+ @john.pending_invited_by.should_not include(@mary)
75
+ @john.pending_invited_by.should include(@peter)
76
+ end
77
+
78
+ it "lists the pending friends who was invited by him" do
79
+ @john.pending_invited.should_not include(@james)
80
+ @john.pending_invited.should include(@jane)
81
+ end
82
+
83
+ it "checks if a user is a friend" do
84
+ @john.is_friend_with?(@james).should == true
85
+ @john.is_friend_with?(@mary).should == true
86
+
87
+ @john.is_friend_with?(@jane).should == false
88
+ @john.is_friend_with?(@peter).should == false
89
+ end
90
+
91
+ it "lists the friends he has in common with another user" do
92
+ @james.common_friends_with(@mary).count.should == 1
93
+ @james.common_friends_with(@mary).should include(@john)
94
+ end
95
+ end
96
+
97
+ context "when removing friendships" do
98
+ before(:each) do
99
+ Friendship.delete_all
100
+ @victoria.invite(@mary).should == true
101
+ @victoria.invite(@john).should == true
102
+ @victoria.invite(@elisabeth).should == true
103
+
104
+ @james.invite(@victoria).should == true
105
+ @peter.invite(@victoria).should == true
106
+ @jane.invite(@victoria).should == true
107
+
108
+ @mary.approve(@victoria).should == true
109
+ @john.approve(@victoria).should == true
110
+ @victoria.approve(@james).should == true
111
+ @victoria.approve(@jane).should == true
112
+ end
113
+
114
+ it "removes the friends invited by him" do
115
+ @victoria.remove(@mary).should == true
116
+
117
+ @victoria.invited.count.should == 1
118
+ @victoria.invited.should include(@john)
119
+ @victoria.friends.should_not include(@mary)
120
+
121
+ @mary.invited_by.should_not include(@victoria)
122
+ @mary.friends.should_not include(@victoria)
123
+ end
124
+
125
+ it "removes the friends who invited him" do
126
+ @victoria.remove(@james).should == true
127
+
128
+ @victoria.invited_by.count.should == 1
129
+ @victoria.invited_by.should include(@jane)
130
+ @victoria.friends.should_not include(@james)
131
+
132
+ @james.invited.should_not include(@victoria)
133
+ @james.friends.should_not include(@victoria)
134
+ end
135
+
136
+ it "removes the pending friends invited by him" do
137
+ @victoria.remove(@elisabeth).should == true
138
+ @victoria.pending_invited.count.should == 0
139
+ @elisabeth.pending_invited_by.should_not include(@victoria)
140
+ end
141
+
142
+ it "removes the pending friends who invited him" do
143
+ @victoria.remove(@peter).should == true
144
+ @victoria.pending_invited_by.count.should == 0
145
+ @peter.pending_invited.should_not include(@victoria)
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Amistad::FriendshipModel do
4
+
5
+ before(:each) do
6
+ Friendship.delete_all
7
+ end
8
+
9
+ it "validates presence of the user's id and the friend's id" do
10
+ friendship = Friendship.new
11
+ friendship.save.should == false
12
+
13
+ friendship = Friendship.new(:user_id => 1, :friend_id => 2)
14
+ friendship.save.should == true
15
+ end
16
+
17
+ it "is in pending state when created" do
18
+ friendship = Friendship.create(:user_id => 1, :friend_id => 2)
19
+ friendship.pending?.should == true
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'logger'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/amistad')
6
+
7
+ ActiveRecord::Base.establish_connection(
8
+ :adapter => "sqlite3",
9
+ :database => "tmp/amistad.sqlite3.db"
10
+ )
11
+
12
+ ActiveRecord::Schema.define do
13
+ create_table :users, :force => true do |t|
14
+ t.string :name, :null => false
15
+ end
16
+
17
+ create_table :friendships, :force => true do |t|
18
+ t.integer :user_id
19
+ t.integer :friend_id
20
+ t.boolean :pending, :default => true
21
+ end
22
+ end
23
+
24
+ ActiveRecord::Base.logger = Logger.new(File.open('tmp/database.log', 'a'))
25
+
26
+ class User < ActiveRecord::Base
27
+ acts_as_friend
28
+ end
29
+
30
+ class Friendship < ActiveRecord::Base
31
+ acts_as_friendship
32
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amistad
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Rawane ZOSSOU
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-13 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Extends your user model with friendships management methods
22
+ email: dev@raw1z.fr
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.markdown
29
+ files:
30
+ - CHANGELOG
31
+ - LICENCE
32
+ - README.markdown
33
+ - Rakefile
34
+ - VERSION
35
+ - lib/amistad.rb
36
+ - lib/amistad/friend_model.rb
37
+ - lib/amistad/friendship_model.rb
38
+ - lib/generators/friendship/friendship_generator.rb
39
+ - lib/generators/friendship/templates/create_friendships.rb
40
+ - lib/generators/friendship/templates/friendship.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/raw1z/amistad
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.6
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Adds friendships management into a rails 3.0 application
71
+ test_files:
72
+ - spec/friend_model_spec.rb
73
+ - spec/friendship_model_spec.rb
74
+ - spec/spec_helper.rb