circle 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 +17 -0
- data/.rspec +2 -0
- data/.simplecov +6 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +114 -0
- data/Rakefile +2 -0
- data/circle.gemspec +26 -0
- data/lib/circle.rb +9 -0
- data/lib/circle/circle.rb +149 -0
- data/lib/circle/models/blocked_user.rb +8 -0
- data/lib/circle/models/friendship.rb +83 -0
- data/lib/circle/railtie.rb +7 -0
- data/lib/circle/version.rb +3 -0
- data/lib/generators/circle/migration_generator.rb +18 -0
- data/lib/generators/circle/templates/migration.rb +36 -0
- data/spec/circle_spec.rb +261 -0
- data/spec/fabricators/user_fabricator.rb +3 -0
- data/spec/friendship_spec.rb +96 -0
- data/spec/schema.rb +24 -0
- data/spec/spec_helper.rb +37 -0
- metadata +183 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.simplecov
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Robert Rouse
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# Circle
|
2
|
+
|
3
|
+
Friendship management gem for ActiveRecord 3
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'circle'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install circle
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
$ rails g circle:migration
|
22
|
+
|
23
|
+
Add "has_circle" to your User model
|
24
|
+
|
25
|
+
class User < ActiveRecord::Base
|
26
|
+
has_circle
|
27
|
+
end
|
28
|
+
|
29
|
+
Call methods as needed
|
30
|
+
|
31
|
+
john = User.find_by_login 'john'
|
32
|
+
mary = User.find_by_login 'mary'
|
33
|
+
paul = User.find_by_login 'paul'
|
34
|
+
|
35
|
+
# John wants to be friend with Mary
|
36
|
+
# always return a friendship object
|
37
|
+
john.befriend(mary)
|
38
|
+
|
39
|
+
# Are they friends?
|
40
|
+
john.friends?(mary) ==> false
|
41
|
+
|
42
|
+
# Get the friendship object
|
43
|
+
john.friendship_with(mary)
|
44
|
+
|
45
|
+
# Mary accepts John's request if it exists
|
46
|
+
mary.accept_friend_request(john)
|
47
|
+
mary.friends?(john) ==> true
|
48
|
+
|
49
|
+
# If both users request a friendship through befriend, they become friends.
|
50
|
+
john.befriend(mary)
|
51
|
+
mary.befriend(john)
|
52
|
+
mary.friends?(john) ==> true
|
53
|
+
|
54
|
+
# Mary can reject John's friendship.
|
55
|
+
mary.deny_friend_request(john)
|
56
|
+
|
57
|
+
# If you're dealing with a friendship object,
|
58
|
+
# the following methods are available
|
59
|
+
friendship.accept! # accept the request
|
60
|
+
friendship.deny! # deny the request
|
61
|
+
friendship.block!(true/false) # block request and add to the users block list if passed true. This is so you can have a one sided block (e.g. The user that initiated the block has the user put in their block list and the blocked user doesn't have the initiating user put in theirs)
|
62
|
+
|
63
|
+
# The befriend method returns the friendship object and status.
|
64
|
+
# The friendship object will be present only when the friendship is created
|
65
|
+
# (that is, when is requested for the first time)
|
66
|
+
# STATUS_ALREADY_FRIENDS # => Users are already friends
|
67
|
+
# STATUS_ALREADY_REQUESTED # => User has already requested friendship
|
68
|
+
# STATUS_IS_YOU # => User is trying add himself as friend
|
69
|
+
# STATUS_FRIEND_IS_REQUIRED # => Friend argument is missing
|
70
|
+
# STATUS_FRIENDSHIP_ACCEPTED # => Friendship has been accepted
|
71
|
+
# STATUS_REQUESTED # => Friendship has been requested
|
72
|
+
# STATUS_CANNOT_SEND # => User cannot send friend requests
|
73
|
+
# STATUS_BLOCKED # => User has been blocked
|
74
|
+
|
75
|
+
friendship, status = mary.befriend(john)
|
76
|
+
|
77
|
+
if status == Circle::Friendship::STATUS_REQUESTED
|
78
|
+
# the friendship has been requested
|
79
|
+
Mailer.deliver_friendship_request(friendship)
|
80
|
+
elsif status == Circle::Friendship::STATUS_ALREADY_FRIENDS
|
81
|
+
# they're already friends
|
82
|
+
else
|
83
|
+
# ...
|
84
|
+
end
|
85
|
+
|
86
|
+
# You can specify whether or not a user can send or accept friend requests by defining two methods that return true or false.
|
87
|
+
# If these are not defined, it is assumed true.
|
88
|
+
|
89
|
+
class User < ActiveRecord::Base
|
90
|
+
has_circle
|
91
|
+
|
92
|
+
def can_send_friend_request?
|
93
|
+
# check subscription plan or whatever
|
94
|
+
end
|
95
|
+
|
96
|
+
def can_accept_friend_request?
|
97
|
+
# check subscription plan or whatever
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
## Future
|
102
|
+
|
103
|
+
1. Add Google+ style circles
|
104
|
+
2. Customizable User class
|
105
|
+
3. Customizable friendship table
|
106
|
+
4. Make ORM agnostic
|
107
|
+
|
108
|
+
## Contributing
|
109
|
+
|
110
|
+
1. Fork it
|
111
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
112
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
113
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
114
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/circle.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/circle/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Robert Rouse"]
|
6
|
+
gem.email = ["robert@theymaybecoders.com"]
|
7
|
+
gem.description = %q{Gem for maintaining friendships in ActiveRecord}
|
8
|
+
gem.summary = %q{Gem for maintaining friendships in ActiveRecord}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "circle"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Circle::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency "rspec"
|
19
|
+
gem.add_development_dependency "sqlite3"
|
20
|
+
gem.add_development_dependency "fabrication"
|
21
|
+
gem.add_development_dependency "shoulda-matchers"
|
22
|
+
gem.add_development_dependency "database_cleaner"
|
23
|
+
gem.add_development_dependency "simplecov"
|
24
|
+
|
25
|
+
gem.add_dependency "activerecord", '~> 3.0'
|
26
|
+
end
|
data/lib/circle.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'models', 'friendship')
|
2
|
+
require File.join(File.dirname(__FILE__), 'models', 'blocked_user')
|
3
|
+
|
4
|
+
|
5
|
+
module Circle
|
6
|
+
def self.included(receiver)
|
7
|
+
receiver.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def has_circle
|
12
|
+
include Circle::InstanceMethods
|
13
|
+
|
14
|
+
has_many :friendships, class_name: "Circle::Friendship"
|
15
|
+
has_many :friends, through: :friendships, source: :friend, conditions: "friendships.status = 'accepted'"
|
16
|
+
has_many :friendship_requests, class_name: "Circle::Friendship", foreign_key: :friend_id, conditions: "friendships.status = 'requested'"
|
17
|
+
has_many :users_blocked, class_name: "Circle::BlockedUser"
|
18
|
+
has_many :blocked_users, through: :users_blocked, source: :blocked_user
|
19
|
+
after_destroy :destroy_all_friendships
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
|
25
|
+
def befriend(friend)
|
26
|
+
return nil, Circle::Friendship::STATUS_FRIEND_IS_REQUIRED unless friend
|
27
|
+
return nil, Circle::Friendship::STATUS_FRIEND_IS_YOURSELF if self.id == friend.id
|
28
|
+
return nil, Circle::Friendship::STATUS_ALREADY_FRIENDS if friends?(friend)
|
29
|
+
return nil, Circle::Friendship::STATUS_BLOCKED if friend.blocked?(self) || blocked?(friend)
|
30
|
+
return nil, Circle::Friendship::STATUS_CANNOT_SEND unless can_send_friend_request? rescue nil
|
31
|
+
|
32
|
+
friendship = self.friendship_with(friend)
|
33
|
+
request = friend.friendship_with(self)
|
34
|
+
|
35
|
+
return nil, Circle::Friendship::STATUS_ALREADY_REQUESTED if friendship && friendship.requested?
|
36
|
+
|
37
|
+
if friendship && friendship.pending?
|
38
|
+
return nil, Circle::Friendship::STATUS_CANNOT_ACCEPT unless can_accept_friend_request? && friend.can_accept_friend_request? rescue nil
|
39
|
+
|
40
|
+
ActiveRecord::Base.transaction do
|
41
|
+
friendship.accept!
|
42
|
+
request.accept!
|
43
|
+
end
|
44
|
+
|
45
|
+
return friendship, Circle::Friendship::STATUS_FRIENDSHIP_ACCEPTED
|
46
|
+
end
|
47
|
+
|
48
|
+
if friendship && (friendship.denied? || friendship.blocked?)
|
49
|
+
friendship.update_attributes({status: 'requested', requested_at: Time.now})
|
50
|
+
request.update_attributes({status: 'pending', requested_at: Time.now})
|
51
|
+
else
|
52
|
+
ActiveRecord::Base.transaction do
|
53
|
+
friendship = self.friendships.create(friend_id: friend.id, status: 'requested', requested_at: Time.now)
|
54
|
+
request = friend.friendships.create(friend_id: id, status: 'pending', requested_at: Time.now)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
return friendship, Circle::Friendship::STATUS_REQUESTED
|
59
|
+
end
|
60
|
+
|
61
|
+
def friendship_with(friend)
|
62
|
+
friendships.where(friend_id: friend.id).first
|
63
|
+
end
|
64
|
+
|
65
|
+
def friends?(friend)
|
66
|
+
friendship = friendship_with(friend)
|
67
|
+
!!(friendship && friendship.accepted?)
|
68
|
+
end
|
69
|
+
|
70
|
+
def blocked?(friend)
|
71
|
+
!!users_blocked.where(blocked_user_id: friend).first
|
72
|
+
end
|
73
|
+
|
74
|
+
def unfriend(friend)
|
75
|
+
ActiveRecord::Base.transaction do
|
76
|
+
[friendship_with(friend), friend.friendship_with(self)].compact.each do |friendship|
|
77
|
+
friendship.destroy if friendship
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def accept_friend_request(friend)
|
83
|
+
return nil, Circle::Friendship::STATUS_CANNOT_ACCEPT unless can_accept_friend_request? rescue nil
|
84
|
+
friendship = self.friendship_with(friend)
|
85
|
+
if friendship.try(:pending?)
|
86
|
+
requested = friend.friendship_with(self)
|
87
|
+
|
88
|
+
ActiveRecord::Base.transaction do
|
89
|
+
friendship.accept!
|
90
|
+
requested.accept! unless requested.accepted?
|
91
|
+
end
|
92
|
+
|
93
|
+
return friendship, Circle::Friendship::STATUS_FRIENDSHIP_ACCEPTED
|
94
|
+
else
|
95
|
+
return nil, Circle::Friendship::STATUS_NOT_FOUND
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def deny_friend_request(friend)
|
100
|
+
request = friendship_with(friend)
|
101
|
+
if request.try(:pending?)
|
102
|
+
ActiveRecord::Base.transaction do
|
103
|
+
[friendship_with(friend), friend.friendship_with(self)].compact.each do |friendship|
|
104
|
+
friendship.deny! if friendship
|
105
|
+
end
|
106
|
+
end
|
107
|
+
request.reload
|
108
|
+
return request, Circle::Friendship::STATUS_FRIENDSHIP_DENIED
|
109
|
+
else
|
110
|
+
return nil, Circle::Friendship::STATUS_NOT_FOUND
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def block(friend)
|
115
|
+
request = friendship_with(friend)
|
116
|
+
if request
|
117
|
+
ActiveRecord::Base.transaction do
|
118
|
+
request.block!(true)
|
119
|
+
friend.friendship_with(self).try(:block!)
|
120
|
+
end
|
121
|
+
request.reload
|
122
|
+
return request, Circle::Friendship::STATUS_BLOCKED
|
123
|
+
else
|
124
|
+
return nil, Circle::Friendship::STATUS_NOT_FOUND
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def unblock(friend)
|
129
|
+
blocked_user = self.users_blocked.where(blocked_user_id: friend.id).first
|
130
|
+
|
131
|
+
if blocked_user
|
132
|
+
ActiveRecord::Base.transaction do
|
133
|
+
blocked_user.destroy
|
134
|
+
end
|
135
|
+
return nil, Circle::Friendship::STATUS_UNBLOCKED
|
136
|
+
else
|
137
|
+
return nil, Circle::Friendship::STATUS_NOT_FOUND
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def destroy_all_friendships
|
143
|
+
ActiveRecord::Base.transaction do
|
144
|
+
Circle::Friendship.destroy_all({user_id: id})
|
145
|
+
Circle::Friendship.destroy_all({friend_id: id})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Circle::Friendship < ActiveRecord::Base
|
2
|
+
self.table_name = "friendships"
|
3
|
+
|
4
|
+
STATUS_ALREADY_FRIENDS = 1
|
5
|
+
STATUS_ALREADY_REQUESTED = 2
|
6
|
+
STATUS_FRIEND_IS_YOURSELF = 3
|
7
|
+
STATUS_FRIENDSHIP_ACCEPTED = 4
|
8
|
+
STATUS_FRIENDSHIP_DENIED = 5
|
9
|
+
STATUS_REQUESTED = 6
|
10
|
+
STATUS_CANNOT_SEND = 7
|
11
|
+
STATUS_CANNOT_ACCEPT = 8
|
12
|
+
STATUS_NOT_FOUND = 9
|
13
|
+
STATUS_BLOCKED = 10
|
14
|
+
STATUS_UNBLOCKED = 11
|
15
|
+
|
16
|
+
FRIENDSHIP_ACCEPTED = "accepted"
|
17
|
+
FRIENDSHIP_PENDING = "pending"
|
18
|
+
FRIENDSHIP_REQUESTED = "requested"
|
19
|
+
FRIENDSHIP_DENIED = "denied"
|
20
|
+
FRIENDSHIP_BLOCKED = "blocked"
|
21
|
+
|
22
|
+
attr_accessible :friend_id, :status, :requested_at, :accepted_at, :denied_at, :blocked_at
|
23
|
+
|
24
|
+
scope :pending, where(status: FRIENDSHIP_PENDING)
|
25
|
+
scope :accepted, where(status: FRIENDSHIP_ACCEPTED)
|
26
|
+
scope :requested, where(status: FRIENDSHIP_REQUESTED)
|
27
|
+
scope :denied, where(status: FRIENDSHIP_DENIED)
|
28
|
+
scope :blocked, where(status: FRIENDSHIP_BLOCKED)
|
29
|
+
|
30
|
+
belongs_to :user
|
31
|
+
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
|
32
|
+
|
33
|
+
after_destroy do |f|
|
34
|
+
User.decrement_counter(:friends_count, f.user_id) if f.status == FRIENDSHIP_ACCEPTED
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def pending?
|
39
|
+
status == FRIENDSHIP_PENDING
|
40
|
+
end
|
41
|
+
|
42
|
+
def accepted?
|
43
|
+
status == FRIENDSHIP_ACCEPTED
|
44
|
+
end
|
45
|
+
|
46
|
+
def requested?
|
47
|
+
status == FRIENDSHIP_REQUESTED
|
48
|
+
end
|
49
|
+
|
50
|
+
def denied?
|
51
|
+
status == FRIENDSHIP_DENIED
|
52
|
+
end
|
53
|
+
|
54
|
+
def blocked?
|
55
|
+
status == FRIENDSHIP_BLOCKED
|
56
|
+
end
|
57
|
+
|
58
|
+
def accept!
|
59
|
+
unless accepted?
|
60
|
+
self.transaction do
|
61
|
+
User.increment_counter(:friends_count, user_id)
|
62
|
+
update_attribute(:status, FRIENDSHIP_ACCEPTED)
|
63
|
+
update_attribute(:accepted_at, Time.now)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def deny!
|
69
|
+
self.transaction do
|
70
|
+
update_attribute(:status, Circle::Friendship::FRIENDSHIP_DENIED)
|
71
|
+
update_attribute(:denied_at, Time.now)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def block!(add_to_block_list = false)
|
76
|
+
self.transaction do
|
77
|
+
update_attribute(:status, Circle::Friendship::FRIENDSHIP_BLOCKED)
|
78
|
+
update_attribute(:blocked_at, Time.now)
|
79
|
+
self.user.users_blocked.create(blocked_user_id: self.friend.id) if add_to_block_list
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
module Circle
|
3
|
+
module Generators
|
4
|
+
class MigrationGenerator < ::Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def install
|
10
|
+
migration_template 'migration.rb', 'db/migrate/create_circle_tables.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.next_migration_number(dirname)
|
14
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class CreateCircleTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :friendships, :force => true do |t|
|
4
|
+
t.references :user, :friend
|
5
|
+
t.datetime :requested_at, :accepted_at, :denied_at, :blocked_at
|
6
|
+
t.string :status
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :blocked_users, :force => true do |t|
|
11
|
+
t.references :user, :blocked_user
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
change_table :friendships do |t|
|
16
|
+
t.index :user_id
|
17
|
+
t.index :friend_id
|
18
|
+
t.index :status
|
19
|
+
end
|
20
|
+
|
21
|
+
change_table :blocked_users do |t|
|
22
|
+
t.index :user_id
|
23
|
+
t.index :blocked_user_id
|
24
|
+
end
|
25
|
+
|
26
|
+
change_table :users do |t|
|
27
|
+
t.integer :friends_cout, :default => 0, :null => false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.down
|
32
|
+
remove_column :users, :friends_count
|
33
|
+
drop_table :friendships
|
34
|
+
drop_table :blocked_users
|
35
|
+
end
|
36
|
+
end
|
data/spec/circle_spec.rb
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'Circle' do
|
4
|
+
|
5
|
+
describe 'methods' do
|
6
|
+
it {User.should respond_to(:has_circle)}
|
7
|
+
it {Fabricate(:user).should respond_to(:befriend)}
|
8
|
+
it {Fabricate(:user).should respond_to(:friends?)}
|
9
|
+
it {Fabricate(:user).should respond_to(:accept_friend_request)}
|
10
|
+
it {Fabricate(:user).should respond_to(:deny_friend_request)}
|
11
|
+
it {Fabricate(:user).should respond_to(:unfriend)}
|
12
|
+
it {Fabricate(:user).should respond_to(:block)}
|
13
|
+
it {Fabricate(:user).should respond_to(:unblock)}
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "user" do
|
17
|
+
before(:each) do
|
18
|
+
@bill = Fabricate(:user, login: 'Bill')
|
19
|
+
@charles = Fabricate(:user, login: 'charles')
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "using befriend" do
|
23
|
+
|
24
|
+
it 'should not allow sending of requests if the user cannot send' do
|
25
|
+
@bill.stub(:can_send_friend_request?) {false}
|
26
|
+
friendship, status = @bill.befriend(@charles)
|
27
|
+
friendship.should be_nil
|
28
|
+
status.should == Circle::Friendship::STATUS_CANNOT_SEND
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should not fail if can_send_friend_request? is undefined' do
|
32
|
+
friendship, status = @bill.befriend(@charles)
|
33
|
+
friendship.should_not be_nil
|
34
|
+
status.should == Circle::Friendship::STATUS_REQUESTED
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should create a friendship when each user befriends one another' do
|
38
|
+
@bill.befriend(@charles)
|
39
|
+
@charles.befriend(@bill)
|
40
|
+
@bill.reload
|
41
|
+
@charles.reload
|
42
|
+
|
43
|
+
@bill.friends_count.should == 1
|
44
|
+
@charles.friends_count.should == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should not create a friendship if either user cannot accept requests' do
|
48
|
+
@bill.befriend(@charles)
|
49
|
+
@charles.stub(:can_accept_friend_request?) {false}
|
50
|
+
friendship, status = @charles.befriend(@bill)
|
51
|
+
friendship.should be_nil
|
52
|
+
status.should == Circle::Friendship::STATUS_CANNOT_ACCEPT
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return an error status if you try to friend yourself' do
|
56
|
+
friendship, status = @bill.befriend(@bill)
|
57
|
+
friendship.should be_nil
|
58
|
+
status.should == Circle::Friendship::STATUS_FRIEND_IS_YOURSELF
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should return an error status when the passed in user is already a friend' do
|
62
|
+
@bill.befriend(@charles)
|
63
|
+
@charles.befriend(@bill)
|
64
|
+
|
65
|
+
friendship, status = @bill.befriend(@charles)
|
66
|
+
friendship.should be_nil
|
67
|
+
status.should == Circle::Friendship::STATUS_ALREADY_FRIENDS
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should return an error status when the request has already been made' do |variable|
|
71
|
+
@bill.befriend(@charles)
|
72
|
+
|
73
|
+
friendship, status = @bill.befriend(@charles)
|
74
|
+
friendship.should be_nil
|
75
|
+
status.should == Circle::Friendship::STATUS_ALREADY_REQUESTED
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should re-request a friendship if the user is not blocked' do
|
79
|
+
friendship, status = @bill.befriend(@charles)
|
80
|
+
friendship.should_not be_nil
|
81
|
+
status.should == Circle::Friendship::STATUS_REQUESTED
|
82
|
+
|
83
|
+
friendship, status = @charles.deny_friend_request(@bill)
|
84
|
+
friendship.should_not be_nil
|
85
|
+
status.should == Circle::Friendship::STATUS_FRIENDSHIP_DENIED
|
86
|
+
|
87
|
+
friendship, status = @bill.befriend(@charles)
|
88
|
+
friendship.should_not be_nil
|
89
|
+
status.should == Circle::Friendship::STATUS_REQUESTED
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "accepting a request" do
|
95
|
+
|
96
|
+
it 'should create a friendship when the user accepts a request' do
|
97
|
+
@bill.befriend(@charles)
|
98
|
+
@charles.accept_friend_request(@bill)
|
99
|
+
@bill.reload
|
100
|
+
@charles.reload
|
101
|
+
|
102
|
+
@bill.friends_count.should == 1
|
103
|
+
@charles.friends_count.should == 1
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should not create a friendship when the user attempts to accept if the user cannot accept' do
|
107
|
+
@bill.befriend(@charles)
|
108
|
+
@charles.stub(:can_accept_friend_request?) {false}
|
109
|
+
friendship, status = @charles.accept_friend_request(@bill)
|
110
|
+
friendship.should be_nil
|
111
|
+
status.should == Circle::Friendship::STATUS_CANNOT_ACCEPT
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should return a not found status if the request does not exist' do
|
115
|
+
friendship, status = @bill.accept_friend_request(@charles)
|
116
|
+
friendship.should be_nil
|
117
|
+
status.should == Circle::Friendship::STATUS_NOT_FOUND
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "denying a request" do
|
122
|
+
it 'should return the friendship object and a denied status' do
|
123
|
+
@bill.befriend(@charles)
|
124
|
+
friendship, status = @charles.deny_friend_request(@bill)
|
125
|
+
friendship.should_not be_nil
|
126
|
+
status.should == Circle::Friendship::STATUS_FRIENDSHIP_DENIED
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should update the friendship object with a denied status' do
|
130
|
+
@bill.befriend(@charles)
|
131
|
+
friendship, status = @charles.deny_friend_request(@bill)
|
132
|
+
friendship.should_not be_nil
|
133
|
+
friendship.status.should == Circle::Friendship::FRIENDSHIP_DENIED
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should return a not found status if the request does not exist' do
|
137
|
+
friendship, status = @bill.deny_friend_request(@charles)
|
138
|
+
friendship.should be_nil
|
139
|
+
status.should == Circle::Friendship::STATUS_NOT_FOUND
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'unfriending' do
|
144
|
+
it 'should remove the friendship if the user unfriends another user' do
|
145
|
+
@bill.befriend(@charles)
|
146
|
+
@charles.befriend(@bill)
|
147
|
+
|
148
|
+
@bill.friends.include?(@charles).should be_true
|
149
|
+
@charles.friends.include?(@bill).should be_true
|
150
|
+
|
151
|
+
@bill.unfriend(@charles)
|
152
|
+
|
153
|
+
@bill.friends.include?(@charles).should be_false
|
154
|
+
@charles.friends.include?(@bill).should be_false
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should decrement the friends counter' do
|
158
|
+
@bill.befriend(@charles)
|
159
|
+
@charles.befriend(@bill)
|
160
|
+
|
161
|
+
@bill.reload
|
162
|
+
@charles.reload
|
163
|
+
|
164
|
+
@bill.friends_count.should == 1
|
165
|
+
@charles.friends_count.should == 1
|
166
|
+
|
167
|
+
@bill.unfriend(@charles)
|
168
|
+
|
169
|
+
@bill.reload
|
170
|
+
@charles.reload
|
171
|
+
|
172
|
+
@bill.friends_count.should == 0
|
173
|
+
@charles.friends_count.should == 0
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe 'destroying all friendships' do
|
179
|
+
it "should remove all friendships for a user" do
|
180
|
+
@bill.befriend(@charles)
|
181
|
+
@charles.befriend(@bill)
|
182
|
+
|
183
|
+
@bill.reload
|
184
|
+
@charles.reload
|
185
|
+
|
186
|
+
@bill.friends_count.should == 1
|
187
|
+
@charles.friends_count.should == 1
|
188
|
+
|
189
|
+
@bill.send(:destroy_all_friendships)
|
190
|
+
|
191
|
+
@bill.reload
|
192
|
+
@charles.reload
|
193
|
+
|
194
|
+
@bill.friends_count.should == 0
|
195
|
+
@charles.friends_count.should == 0
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "friends" do
|
200
|
+
it 'should return the friends of a user' do
|
201
|
+
@bill.befriend(@charles)
|
202
|
+
@charles.befriend(@bill)
|
203
|
+
|
204
|
+
@user = Fabricate(:user)
|
205
|
+
|
206
|
+
@bill.befriend(@user)
|
207
|
+
@user.befriend(@bill)
|
208
|
+
|
209
|
+
@bill.friends.should == [@charles, @user]
|
210
|
+
@charles.friends.should == [@bill]
|
211
|
+
@user.friends.should == [@bill]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe 'blocking' do
|
216
|
+
before(:each) do
|
217
|
+
@bill.befriend(@charles)
|
218
|
+
@charles.block(@bill)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should block a user' do
|
222
|
+
@bill.blocked_users.should be_empty
|
223
|
+
@charles.blocked_users.include?(@bill).should be_true
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should not allow friend requests to be sent anymore' do
|
227
|
+
friendship, status = @bill.befriend(@charles)
|
228
|
+
friendship.should be_nil
|
229
|
+
status.should == Circle::Friendship::STATUS_BLOCKED
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'should not allow you to send requests to users that have blocked you' do
|
233
|
+
Circle::BlockedUser.destroy_all
|
234
|
+
@bill.block(@charles)
|
235
|
+
friendship, status = @charles.befriend(@bill)
|
236
|
+
friendship.should be_nil
|
237
|
+
status.should == Circle::Friendship::STATUS_BLOCKED
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should allow a user to request a friendship with a user they have previously blocked' do
|
241
|
+
@charles.unblock(@bill)
|
242
|
+
friendship, status = @charles.befriend(@bill)
|
243
|
+
friendship.should_not be_nil
|
244
|
+
status.should == Circle::Friendship::STATUS_REQUESTED
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe 'unblocking' do
|
249
|
+
before(:each) do
|
250
|
+
@bill.befriend(@charles)
|
251
|
+
@charles.block(@bill)
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should remove the blocked user' do
|
255
|
+
@charles.unblock(@bill)
|
256
|
+
@charles.reload
|
257
|
+
@charles.blocked_users.should be_empty
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Circle::Friendship do
|
4
|
+
describe 'associations' do
|
5
|
+
it {should belong_to :user}
|
6
|
+
it {should belong_to :friend}
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'status' do
|
10
|
+
|
11
|
+
describe 'pending?' do
|
12
|
+
it 'should have a pending status' do
|
13
|
+
@friendship = Circle::Friendship.new(:status => 'pending')
|
14
|
+
@friendship.should be_pending
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'accepted?' do
|
19
|
+
it 'should have an accepted status' do
|
20
|
+
@friendship = Circle::Friendship.new(:status => 'accepted')
|
21
|
+
@friendship.should be_accepted
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'requested?' do
|
26
|
+
it 'should have a requested status' do
|
27
|
+
@friendship = Circle::Friendship.new(:status => 'requested')
|
28
|
+
@friendship.should be_requested
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'denied?' do
|
33
|
+
it 'should have a denied status' do
|
34
|
+
@friendship = Circle::Friendship.new(:status => 'denied')
|
35
|
+
@friendship.should be_denied
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'blocked?' do
|
40
|
+
it 'should have a blocked status' do
|
41
|
+
@friendship = Circle::Friendship.new(:status => 'blocked')
|
42
|
+
@friendship.should be_blocked
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'accept!' do
|
49
|
+
it 'should set the status to accepted' do
|
50
|
+
@friendship = Circle::Friendship.new(:status => 'pending')
|
51
|
+
@friendship.accept!
|
52
|
+
@friendship.status.should == Circle::Friendship::FRIENDSHIP_ACCEPTED
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should increment the user friends counter' do
|
56
|
+
@user = Fabricate(:user)
|
57
|
+
@user2 = Fabricate(:user)
|
58
|
+
@user.befriend(@user2)
|
59
|
+
@user2.befriend(@user)
|
60
|
+
|
61
|
+
@user.reload
|
62
|
+
|
63
|
+
@user.friends_count.should == 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'deny!' do
|
68
|
+
it 'should set the status to denied' do
|
69
|
+
@friendship = Circle::Friendship.new(:status => 'pending')
|
70
|
+
@friendship.deny!
|
71
|
+
@friendship.status.should == Circle::Friendship::FRIENDSHIP_DENIED
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'block!' do
|
76
|
+
it 'should set the status to blocked' do
|
77
|
+
@friendship = Circle::Friendship.new(:status => 'pending')
|
78
|
+
@friendship.block!
|
79
|
+
@friendship.status.should == Circle::Friendship::FRIENDSHIP_BLOCKED
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should create a blocked user when passed true' do
|
83
|
+
@bill = Fabricate(:user, login: 'Bill')
|
84
|
+
@charles = Fabricate(:user, login: 'charles')
|
85
|
+
|
86
|
+
@bill.befriend(@charles)
|
87
|
+
@charles.block(@bill)
|
88
|
+
|
89
|
+
@bill.reload
|
90
|
+
@charles.reload
|
91
|
+
|
92
|
+
@bill.blocked_users.should be_empty
|
93
|
+
@charles.blocked_users.include?(@bill).should be_true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/schema.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
begin
|
3
|
+
drop_table :users
|
4
|
+
drop_table :friendships
|
5
|
+
rescue
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :users do |t|
|
9
|
+
t.string :login
|
10
|
+
t.integer :friends_count, :default => 0, :null => false
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :friendships do |t|
|
14
|
+
t.references :user, :friend
|
15
|
+
t.string :status
|
16
|
+
t.datetime :requested_at, :accepted_at, :denied_at, :blocked_at
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :blocked_users, :force => true do |t|
|
21
|
+
t.references :user, :blocked_user
|
22
|
+
t.timestamps
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
3
|
+
|
4
|
+
require 'active_record'
|
5
|
+
require 'circle'
|
6
|
+
require 'rspec'
|
7
|
+
require 'shoulda/matchers'
|
8
|
+
require 'database_cleaner'
|
9
|
+
require 'fabrication'
|
10
|
+
|
11
|
+
Dir[File.join(File.dirname(__FILE__), 'spec/support/**/*.rb')].each {|f| require f}
|
12
|
+
|
13
|
+
ActiveRecord::Base.configurations = {'test' => {adapter: 'sqlite3', database: ':memory:'}}
|
14
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
15
|
+
|
16
|
+
load(File.join(File.dirname(__FILE__), 'schema.rb'))
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
|
20
|
+
config.before(:suite) do
|
21
|
+
DatabaseCleaner.strategy = :transaction
|
22
|
+
DatabaseCleaner.clean_with(:truncation)
|
23
|
+
end
|
24
|
+
|
25
|
+
config.before(:each) do
|
26
|
+
DatabaseCleaner.start
|
27
|
+
end
|
28
|
+
|
29
|
+
config.after(:each) do
|
30
|
+
DatabaseCleaner.clean
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class User < ActiveRecord::Base
|
36
|
+
has_circle
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: circle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Rouse
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sqlite3
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: fabrication
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: shoulda-matchers
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: database_cleaner
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: simplecov
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: activerecord
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '3.0'
|
126
|
+
description: Gem for maintaining friendships in ActiveRecord
|
127
|
+
email:
|
128
|
+
- robert@theymaybecoders.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- .rspec
|
135
|
+
- .simplecov
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- circle.gemspec
|
141
|
+
- lib/circle.rb
|
142
|
+
- lib/circle/circle.rb
|
143
|
+
- lib/circle/models/blocked_user.rb
|
144
|
+
- lib/circle/models/friendship.rb
|
145
|
+
- lib/circle/railtie.rb
|
146
|
+
- lib/circle/version.rb
|
147
|
+
- lib/generators/circle/migration_generator.rb
|
148
|
+
- lib/generators/circle/templates/migration.rb
|
149
|
+
- spec/circle_spec.rb
|
150
|
+
- spec/fabricators/user_fabricator.rb
|
151
|
+
- spec/friendship_spec.rb
|
152
|
+
- spec/schema.rb
|
153
|
+
- spec/spec_helper.rb
|
154
|
+
homepage: ''
|
155
|
+
licenses: []
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ! '>='
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
requirements: []
|
173
|
+
rubyforge_project:
|
174
|
+
rubygems_version: 1.8.24
|
175
|
+
signing_key:
|
176
|
+
specification_version: 3
|
177
|
+
summary: Gem for maintaining friendships in ActiveRecord
|
178
|
+
test_files:
|
179
|
+
- spec/circle_spec.rb
|
180
|
+
- spec/fabricators/user_fabricator.rb
|
181
|
+
- spec/friendship_spec.rb
|
182
|
+
- spec/schema.rb
|
183
|
+
- spec/spec_helper.rb
|