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 +20 -0
- data/README.markdown +123 -0
- data/RakeFile +25 -0
- data/VERSION +1 -0
- data/app/models/friendship.rb +72 -0
- data/app/models/friendship_message.rb +3 -0
- data/app/models/friendship_relation_type.rb +4 -0
- data/app/models/relation_type.rb +10 -0
- data/has_friends-rails3.gemspec +70 -0
- data/lib/generators/has_friends/migration/migration_generator.rb +14 -0
- data/lib/generators/has_friends/migration/templates/create_has_friends_tables.rb +42 -0
- data/lib/generators/has_friends.rb +19 -0
- data/lib/has_friends/engine.rb +10 -0
- data/lib/has_friends/exceptions.rb +1 -0
- data/lib/has_friends/has_friends.rb +118 -0
- data/lib/has_friends.rb +5 -0
- data/spec/fixtures/relation_types.yml +8 -0
- data/spec/fixtures/users.yml +14 -0
- data/spec/friendship_message_spec.rb +10 -0
- data/spec/friendship_relation_type_spec.rb +17 -0
- data/spec/friendship_spec.rb +113 -0
- data/spec/has_friends_spec.rb +252 -0
- data/spec/relation_type_spec.rb +9 -0
- data/spec/schema.rb +37 -0
- data/spec/spec_helper.rb +37 -0
- metadata +94 -0
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,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 @@
|
|
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
|
data/lib/has_friends.rb
ADDED
@@ -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
|
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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|