amico 1.1.0 → 1.2.0
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 +1 -0
- data/CHANGELOG.md +4 -0
- data/README.md +93 -1
- data/lib/amico/configuration.rb +48 -26
- data/lib/amico/relationships.rb +196 -102
- data/lib/amico/version.rb +1 -1
- data/spec/amico/configuration_spec.rb +2 -0
- data/spec/amico/relationships_spec.rb +121 -0
- data/spec/spec_helper.rb +11 -3
- metadata +10 -10
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -27,6 +27,8 @@ Amico.configure do |configuration|
|
|
27
27
|
configuration.followers_key = 'followers'
|
28
28
|
configuration.blocked_key = 'blocked'
|
29
29
|
configuration.reciprocated_key = 'reciprocated'
|
30
|
+
configuration.pending_key = 'pending'
|
31
|
+
configuration.pending_follow = false
|
30
32
|
configuration.page_size = 25
|
31
33
|
end
|
32
34
|
```
|
@@ -44,6 +46,8 @@ Amico.configure do |configuration|
|
|
44
46
|
configuration.followers_key = 'followers'
|
45
47
|
configuration.blocked_key = 'blocked'
|
46
48
|
configuration.reciprocated_key = 'reciprocated'
|
49
|
+
configuration.pending_key = 'pending'
|
50
|
+
configuration.pending_follow = false
|
47
51
|
configuration.page_size = 25
|
48
52
|
end
|
49
53
|
|
@@ -111,10 +115,98 @@ Amico.reciprocated(1)
|
|
111
115
|
=> ["11"]
|
112
116
|
```
|
113
117
|
|
118
|
+
Use amico (with pending relationships for follow):
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
require 'amico'
|
122
|
+
=> true
|
123
|
+
|
124
|
+
Amico.configure do |configuration|
|
125
|
+
configuration.redis = Redis.new
|
126
|
+
configuration.namespace = 'amico'
|
127
|
+
configuration.following_key = 'following'
|
128
|
+
configuration.followers_key = 'followers'
|
129
|
+
configuration.blocked_key = 'blocked'
|
130
|
+
configuration.reciprocated_key = 'reciprocated'
|
131
|
+
configuration.pending_key = 'pending'
|
132
|
+
configuration.pending_follow = true
|
133
|
+
configuration.page_size = 25
|
134
|
+
end
|
135
|
+
|
136
|
+
Amico.follow(1, 11)
|
137
|
+
=> true
|
138
|
+
|
139
|
+
Amico.follow(11, 1)
|
140
|
+
=> true
|
141
|
+
|
142
|
+
Amico.pending?(1, 11)
|
143
|
+
=> true
|
144
|
+
|
145
|
+
Amico.pending?(11, 1)
|
146
|
+
=> true
|
147
|
+
|
148
|
+
Amico.accept(1, 11)
|
149
|
+
=> nil
|
150
|
+
|
151
|
+
Amico.pending?(1, 11)
|
152
|
+
=> false
|
153
|
+
|
154
|
+
Amico.pending?(11, 1)
|
155
|
+
=> true
|
156
|
+
|
157
|
+
Amico.following?(1, 11)
|
158
|
+
=> true
|
159
|
+
|
160
|
+
Amico.following?(11, 1)
|
161
|
+
=> false
|
162
|
+
|
163
|
+
Amico.follower?(11, 1)
|
164
|
+
=> true
|
165
|
+
|
166
|
+
Amico.follower?(1, 11)
|
167
|
+
=> false
|
168
|
+
|
169
|
+
Amico.accept(11, 1)
|
170
|
+
=> [1, 1]
|
171
|
+
|
172
|
+
Amico.pending?(1, 11)
|
173
|
+
=> false
|
174
|
+
|
175
|
+
Amico.pending?(11, 1)
|
176
|
+
=> false
|
177
|
+
|
178
|
+
Amico.following?(1, 11)
|
179
|
+
=> true
|
180
|
+
|
181
|
+
Amico.following?(11, 1)
|
182
|
+
=> true
|
183
|
+
|
184
|
+
Amico.follower?(11, 1)
|
185
|
+
=> true
|
186
|
+
|
187
|
+
Amico.follower?(1, 11)
|
188
|
+
=> true
|
189
|
+
|
190
|
+
Amico.reciprocated?(1, 11)
|
191
|
+
=> true
|
192
|
+
```
|
193
|
+
|
114
194
|
## Documentation
|
115
195
|
|
116
196
|
The source for the [relationships module](https://github.com/agoragames/amico/blob/master/lib/amico/relationships.rb) is well-documented. There are some
|
117
|
-
simple examples in the method documentation. You can also refer to the [online documentation](http://rubydoc.info/
|
197
|
+
simple examples in the method documentation. You can also refer to the [online documentation](http://rubydoc.info/github/agoragames/amico/master/frames).
|
198
|
+
|
199
|
+
## FAQ?
|
200
|
+
|
201
|
+
### Why use Redis sorted sets and not Redis sets?
|
202
|
+
|
203
|
+
Based on the work I did in developing [leaderboard](https://github.com/agoragames/leaderboard),
|
204
|
+
leaderboards backed by Redis, I know I wanted to be able to page through the various relationships.
|
205
|
+
This does not seem to be possible given the current set of commands for Redis sets.
|
206
|
+
|
207
|
+
Also, by using the "score" in Redis sorted sets that is based on the time of when a relationship
|
208
|
+
is established, we can get our "recent friends". It is possible that the scoring function may be
|
209
|
+
user-defined in the future to allow for some specific ordering.
|
118
210
|
|
119
211
|
## Contributing to amico
|
120
212
|
|
data/lib/amico/configuration.rb
CHANGED
@@ -1,28 +1,34 @@
|
|
1
1
|
module Amico
|
2
2
|
# Configuration settings for Amico.
|
3
3
|
module Configuration
|
4
|
-
#
|
4
|
+
# Redis instance.
|
5
5
|
attr_accessor :redis
|
6
6
|
|
7
|
-
#
|
8
|
-
|
7
|
+
# Amico namespace for Redis.
|
8
|
+
attr_writer :namespace
|
9
9
|
|
10
|
-
#
|
11
|
-
|
10
|
+
# Key used in Redis for tracking who an individual is following.
|
11
|
+
attr_writer :following_key
|
12
12
|
|
13
|
-
#
|
14
|
-
|
13
|
+
# Key used in Redis for tracking the followers of an individual.
|
14
|
+
attr_writer :followers_key
|
15
15
|
|
16
|
-
#
|
17
|
-
|
16
|
+
# Key used in Redis for tracking who an individual blocks.
|
17
|
+
attr_writer :blocked_key
|
18
18
|
|
19
|
-
#
|
20
|
-
|
19
|
+
# Key used in Redis for tracking who has reciprocated a follow for an individual.
|
20
|
+
attr_writer :reciprocated_key
|
21
21
|
|
22
|
-
#
|
23
|
-
|
22
|
+
# Key used in Redis for tracking pending follow relationships for an individual.
|
23
|
+
attr_writer :pending_key
|
24
24
|
|
25
|
-
#
|
25
|
+
# Key used to indicate whether or not a follow should be pending or not.
|
26
|
+
attr_writer :pending_follow
|
27
|
+
|
28
|
+
# Page size to be used when paging through the various types of relationships.
|
29
|
+
attr_writer :page_size
|
30
|
+
|
31
|
+
# Yield self to be able to configure Amico with block-style configuration.
|
26
32
|
#
|
27
33
|
# Example:
|
28
34
|
#
|
@@ -33,50 +39,66 @@ module Amico
|
|
33
39
|
# configuration.followers_key = 'followers'
|
34
40
|
# configuration.blocked_key = 'blocked'
|
35
41
|
# configuration.reciprocated_key = 'reciprocated'
|
42
|
+
# configuration.pending_key = 'pending'
|
43
|
+
# configuration.pending_follow = false
|
36
44
|
# configuration.page_size = 25
|
37
45
|
# end
|
38
46
|
def configure
|
39
47
|
yield self
|
40
48
|
end
|
41
49
|
|
42
|
-
#
|
50
|
+
# Amico namespace for Redis.
|
43
51
|
#
|
44
|
-
#
|
52
|
+
# @return the Amico namespace or the default of 'amico' if not set.
|
45
53
|
def namespace
|
46
54
|
@namespace ||= 'amico'
|
47
55
|
end
|
48
56
|
|
49
|
-
#
|
57
|
+
# Key used in Redis for tracking who an individual is following.
|
50
58
|
#
|
51
|
-
#
|
59
|
+
# @return the key used in Redis for tracking who an individual is following or the default of 'following' if not set.
|
52
60
|
def following_key
|
53
61
|
@following_key ||= 'following'
|
54
62
|
end
|
55
63
|
|
56
|
-
#
|
64
|
+
# Key used in Redis for tracking the followers of an individual.
|
57
65
|
#
|
58
|
-
#
|
66
|
+
# @return the key used in Redis for tracking the followers of an individual or the default of 'followers' if not set.
|
59
67
|
def followers_key
|
60
68
|
@followers_key ||= 'followers'
|
61
69
|
end
|
62
70
|
|
63
|
-
#
|
71
|
+
# Key used in Redis for tracking who an individual blocks.
|
64
72
|
#
|
65
|
-
#
|
73
|
+
# @return the key used in Redis for tracking who an individual blocks or the default of 'blocked' if not set.
|
66
74
|
def blocked_key
|
67
75
|
@blocked_key ||= 'blocked'
|
68
76
|
end
|
69
77
|
|
70
|
-
#
|
78
|
+
# Key used in Redis for tracking who has reciprocated a follow for an individual.
|
71
79
|
#
|
72
|
-
#
|
80
|
+
# @return the key used in Redis for tracking who has reciprocated a follow for an individual or the default of 'reciprocated' if not set.
|
73
81
|
def reciprocated_key
|
74
82
|
@reciprocated_key ||= 'reciprocated'
|
75
83
|
end
|
76
84
|
|
77
|
-
#
|
85
|
+
# Key used in Redis for tracking pending follow relationships for an individual.
|
86
|
+
#
|
87
|
+
# @return the key used in Redis for tracking pending follow relationships for an individual.
|
88
|
+
def pending_key
|
89
|
+
@pending_key ||= 'pending'
|
90
|
+
end
|
91
|
+
|
92
|
+
# Key used to indicate whether or not a follow should be pending or not.
|
93
|
+
#
|
94
|
+
# @return the key used to indicate whether or not a follow should be pending or not.
|
95
|
+
def pending_follow
|
96
|
+
@pending_follow ||= false
|
97
|
+
end
|
98
|
+
|
99
|
+
# Page size to be used when paging through the various types of relationships.
|
78
100
|
#
|
79
|
-
#
|
101
|
+
# @return the page size to be used when paging through the various types of relationships or the default of 25 if not set.
|
80
102
|
def page_size
|
81
103
|
@page_size ||= 25
|
82
104
|
end
|
data/lib/amico/relationships.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Amico
|
2
2
|
module Relationships
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# Establish a follow relationship between two IDs. After adding the follow
|
4
|
+
# relationship, it checks to see if the relationship is reciprocated and establishes that
|
5
|
+
# relationship if so.
|
6
6
|
#
|
7
|
-
# from_id
|
8
|
-
# to_id
|
7
|
+
# @param from_id [String] The ID of the individual establishing the follow relationship.
|
8
|
+
# @param to_id [String] The ID of the individual to be followed.
|
9
9
|
#
|
10
10
|
# Examples
|
11
11
|
#
|
@@ -13,26 +13,21 @@ module Amico
|
|
13
13
|
def follow(from_id, to_id)
|
14
14
|
return if from_id == to_id
|
15
15
|
return if blocked?(to_id, from_id)
|
16
|
+
return if Amico.pending_follow && pending?(from_id, to_id)
|
16
17
|
|
17
|
-
Amico.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
if reciprocated?(from_id, to_id)
|
23
|
-
Amico.redis.multi do
|
24
|
-
Amico.redis.zadd("#{Amico.namespace}:#{Amico.reciprocated_key}:#{from_id}", Time.now.to_i, to_id)
|
25
|
-
Amico.redis.zadd("#{Amico.namespace}:#{Amico.reciprocated_key}:#{to_id}", Time.now.to_i, from_id)
|
26
|
-
end
|
18
|
+
unless Amico.pending_follow
|
19
|
+
add_following_followers_reciprocated(from_id, to_id)
|
20
|
+
else
|
21
|
+
Amico.redis.zadd("#{Amico.namespace}:#{Amico.pending_key}:#{to_id}", Time.now.to_i, from_id)
|
27
22
|
end
|
28
23
|
end
|
29
24
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
25
|
+
# Remove a follow relationship between two IDs. After removing the follow
|
26
|
+
# relationship, if a reciprocated relationship was established, it is
|
27
|
+
# also removed.
|
33
28
|
#
|
34
|
-
# from_id
|
35
|
-
# to_id
|
29
|
+
# @param from_id [String] The ID of the individual removing the follow relationship.
|
30
|
+
# @param to_id [String] The ID of the individual to be unfollowed.
|
36
31
|
#
|
37
32
|
# Examples
|
38
33
|
#
|
@@ -46,14 +41,15 @@ module Amico
|
|
46
41
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.followers_key}:#{to_id}", from_id)
|
47
42
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.reciprocated_key}:#{from_id}", to_id)
|
48
43
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.reciprocated_key}:#{to_id}", from_id)
|
44
|
+
Amico.redis.zrem("#{Amico.namespace}:#{Amico.pending_key}:#{to_id}", from_id)
|
49
45
|
end
|
50
|
-
end
|
46
|
+
end
|
51
47
|
|
52
|
-
#
|
53
|
-
#
|
48
|
+
# Block a relationship between two IDs. This method also has the side effect
|
49
|
+
# of removing any follower or following relationship between the two IDs.
|
54
50
|
#
|
55
|
-
# from_id
|
56
|
-
# to_id
|
51
|
+
# @param from_id [String] The ID of the individual blocking the relationship.
|
52
|
+
# @param to_id [String] The ID of the individual being blocked.
|
57
53
|
#
|
58
54
|
# Examples
|
59
55
|
#
|
@@ -68,14 +64,15 @@ module Amico
|
|
68
64
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.followers_key}:#{from_id}", to_id)
|
69
65
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.reciprocated_key}:#{from_id}", to_id)
|
70
66
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.reciprocated_key}:#{to_id}", from_id)
|
67
|
+
Amico.redis.zrem("#{Amico.namespace}:#{Amico.pending_key}:#{from_id}", to_id)
|
71
68
|
Amico.redis.zadd("#{Amico.namespace}:#{Amico.blocked_key}:#{from_id}", Time.now.to_i, to_id)
|
72
69
|
end
|
73
70
|
end
|
74
71
|
|
75
|
-
#
|
72
|
+
# Unblock a relationship between two IDs.
|
76
73
|
#
|
77
|
-
# from_id
|
78
|
-
# to_id
|
74
|
+
# @param from_id [String] The ID of the individual unblocking the relationship.
|
75
|
+
# @param to_id [String] The ID of the blocked individual.
|
79
76
|
#
|
80
77
|
# Examples
|
81
78
|
#
|
@@ -87,51 +84,69 @@ module Amico
|
|
87
84
|
Amico.redis.zrem("#{Amico.namespace}:#{Amico.blocked_key}:#{from_id}", to_id)
|
88
85
|
end
|
89
86
|
|
90
|
-
#
|
87
|
+
# Accept a relationship that is pending between two IDs.
|
88
|
+
#
|
89
|
+
# @param from_id [String] The ID of the individual accepting the relationship.
|
90
|
+
# @param to_id [String] The ID of the individual to be accepted.
|
91
|
+
#
|
92
|
+
# Example
|
93
|
+
#
|
94
|
+
# Amico.follow(1, 11)
|
95
|
+
# Amico.pending?(1, 11) # true
|
96
|
+
# Amico.accept(1, 11)
|
97
|
+
# Amico.pending?(1, 11) # false
|
98
|
+
# Amico.following?(1, 11) #true
|
99
|
+
def accept(from_id, to_id)
|
100
|
+
return if from_id == to_id
|
101
|
+
|
102
|
+
add_following_followers_reciprocated(from_id, to_id)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Count the number of individuals that someone is following.
|
91
106
|
#
|
92
|
-
# id
|
107
|
+
# @param id [String] ID of the individual to retrieve following count for.
|
93
108
|
#
|
94
109
|
# Examples
|
95
110
|
#
|
96
111
|
# Amico.follow(1, 11)
|
97
112
|
# Amico.following_count(1)
|
98
113
|
#
|
99
|
-
#
|
114
|
+
# @return the count of the number of individuals that someone is following.
|
100
115
|
def following_count(id)
|
101
116
|
Amico.redis.zcard("#{Amico.namespace}:#{Amico.following_key}:#{id}")
|
102
117
|
end
|
103
118
|
|
104
|
-
#
|
119
|
+
# Count the number of individuals that are following someone.
|
105
120
|
#
|
106
|
-
# id
|
121
|
+
# @param id [String] ID of the individual to retrieve followers count for.
|
107
122
|
#
|
108
123
|
# Examples
|
109
124
|
#
|
110
125
|
# Amico.follow(11, 1)
|
111
126
|
# Amico.followers_count(1)
|
112
127
|
#
|
113
|
-
#
|
128
|
+
# @return the count of the number of individuals that are following someone.
|
114
129
|
def followers_count(id)
|
115
130
|
Amico.redis.zcard("#{Amico.namespace}:#{Amico.followers_key}:#{id}")
|
116
131
|
end
|
117
132
|
|
118
|
-
#
|
133
|
+
# Count the number of individuals that someone has blocked.
|
119
134
|
#
|
120
|
-
# id
|
135
|
+
# @param id [String] ID of the individual to retrieve blocked count for.
|
121
136
|
#
|
122
137
|
# Examples
|
123
138
|
#
|
124
139
|
# Amico.block(1, 11)
|
125
140
|
# Amico.blocked_count(1)
|
126
141
|
#
|
127
|
-
#
|
142
|
+
# @return the count of the number of individuals that someone has blocked.
|
128
143
|
def blocked_count(id)
|
129
144
|
Amico.redis.zcard("#{Amico.namespace}:#{Amico.blocked_key}:#{id}")
|
130
145
|
end
|
131
146
|
|
132
|
-
#
|
147
|
+
# Count the number of individuals that have reciprocated a following relationship.
|
133
148
|
#
|
134
|
-
# id
|
149
|
+
# @param id [String] ID of the individual to retrieve reciprocated following count for.
|
135
150
|
#
|
136
151
|
# Examples
|
137
152
|
#
|
@@ -139,59 +154,75 @@ module Amico
|
|
139
154
|
# Amico.follow(11, 1)
|
140
155
|
# Amico.reciprocated_count(1)
|
141
156
|
#
|
142
|
-
#
|
157
|
+
# @return the count of the number of individuals that have reciprocated a following relationship.
|
143
158
|
def reciprocated_count(id)
|
144
159
|
Amico.redis.zcard("#{Amico.namespace}:#{Amico.reciprocated_key}:#{id}")
|
145
160
|
end
|
146
161
|
|
147
|
-
#
|
162
|
+
# Count the number of relationships pending for an individual.
|
148
163
|
#
|
149
|
-
# id
|
150
|
-
#
|
164
|
+
# @param id [String] ID of the individual to retrieve pending count for.
|
165
|
+
#
|
166
|
+
# Examples
|
167
|
+
#
|
168
|
+
# Amico.follow(11, 1)
|
169
|
+
# Amico.follow(12, 1)
|
170
|
+
# Amico.pending_count(1) # 2
|
171
|
+
#
|
172
|
+
# @return the count of the number of relationships pending for an individual.
|
173
|
+
def pending_count(id)
|
174
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.pending_key}:#{id}")
|
175
|
+
end
|
176
|
+
|
177
|
+
# Check to see if one individual is following another individual.
|
178
|
+
#
|
179
|
+
# @param id [String] ID of the individual checking the following status.
|
180
|
+
# @param following_id [String] ID of the individual to see if they are being followed by id.
|
151
181
|
#
|
152
182
|
# Examples
|
153
183
|
#
|
154
184
|
# Amico.follow(1, 11)
|
155
185
|
# Amico.following?(1, 11)
|
156
186
|
#
|
157
|
-
#
|
187
|
+
# @return true if id is following following_id, false otherwise
|
158
188
|
def following?(id, following_id)
|
159
189
|
!Amico.redis.zscore("#{Amico.namespace}:#{Amico.following_key}:#{id}", following_id).nil?
|
160
190
|
end
|
161
191
|
|
162
|
-
#
|
192
|
+
# Check to see if one individual is a follower of another individual.
|
163
193
|
#
|
164
|
-
# id
|
165
|
-
# following_id
|
194
|
+
# @param id [String] ID of the individual checking the follower status.
|
195
|
+
# @param following_id [String] ID of the individual to see if they are following id.
|
166
196
|
#
|
167
197
|
# Examples
|
168
198
|
#
|
169
199
|
# Amico.follow(11, 1)
|
170
200
|
# Amico.follower?(1, 11)
|
171
|
-
#
|
201
|
+
#
|
202
|
+
# @return true if follower_id is following id, false otherwise
|
172
203
|
def follower?(id, follower_id)
|
173
204
|
!Amico.redis.zscore("#{Amico.namespace}:#{Amico.followers_key}:#{id}", follower_id).nil?
|
174
205
|
end
|
175
206
|
|
176
|
-
#
|
207
|
+
# Check to see if one individual has blocked another individual.
|
177
208
|
#
|
178
|
-
# id
|
179
|
-
# blocked_id
|
209
|
+
# @param id [String] ID of the individual checking the blocked status.
|
210
|
+
# @param blocked_id [String] ID of the individual to see if they are blocked by id.
|
180
211
|
#
|
181
212
|
# Examples
|
182
213
|
#
|
183
214
|
# Amico.block(1, 11)
|
184
215
|
# Amico.blocked?(1, 11)
|
185
216
|
#
|
186
|
-
#
|
217
|
+
# @return true if id has blocked blocked_id, false otherwise
|
187
218
|
def blocked?(id, blocked_id)
|
188
219
|
!Amico.redis.zscore("#{Amico.namespace}:#{Amico.blocked_key}:#{id}", blocked_id).nil?
|
189
220
|
end
|
190
221
|
|
191
|
-
#
|
222
|
+
# Check to see if one individual has reciprocated in following another individual.
|
192
223
|
#
|
193
|
-
# from_id
|
194
|
-
# to_id
|
224
|
+
# @param from_id [String] ID of the individual checking the reciprocated relationship.
|
225
|
+
# @param to_id [String] ID of the individual to see if they are following from_id.
|
195
226
|
#
|
196
227
|
# Examples
|
197
228
|
#
|
@@ -199,16 +230,30 @@ module Amico
|
|
199
230
|
# Amico.follow(11, 1)
|
200
231
|
# Amico.reciprocated?(1, 11)
|
201
232
|
#
|
202
|
-
#
|
233
|
+
# @return true if both individuals are following each other, false otherwise
|
203
234
|
def reciprocated?(from_id, to_id)
|
204
235
|
following?(from_id, to_id) && following?(to_id, from_id)
|
205
236
|
end
|
206
237
|
|
207
|
-
#
|
238
|
+
# Check to see if one individual has a pending relationship in following another individual.
|
208
239
|
#
|
209
|
-
#
|
210
|
-
#
|
211
|
-
#
|
240
|
+
# @param from_id [String] ID of the individual checking the pending relationships.
|
241
|
+
# @param to_id [String] ID of the individual to see if they are pending a follow from from_id.
|
242
|
+
#
|
243
|
+
# Examples
|
244
|
+
#
|
245
|
+
# Amico.follow(1, 11)
|
246
|
+
# Amico.pending?(1, 11) # true
|
247
|
+
#
|
248
|
+
# @return true if the relationship is pending, false otherwise
|
249
|
+
def pending?(from_id, to_id)
|
250
|
+
!Amico.redis.zscore("#{Amico.namespace}:#{Amico.pending_key}:#{to_id}", from_id).nil?
|
251
|
+
end
|
252
|
+
|
253
|
+
# Retrieve a page of followed individuals for a given ID.
|
254
|
+
#
|
255
|
+
# @param id [String] ID of the individual.
|
256
|
+
# @param options [Hash] Options to be passed for retrieving a page of followed individuals.
|
212
257
|
#
|
213
258
|
# Examples
|
214
259
|
#
|
@@ -216,16 +261,15 @@ module Amico
|
|
216
261
|
# Amico.follow(1, 12)
|
217
262
|
# Amico.following(1, :page => 1)
|
218
263
|
#
|
219
|
-
#
|
264
|
+
# @return a page of followed individuals for a given ID.
|
220
265
|
def following(id, options = default_options)
|
221
266
|
members("#{Amico.namespace}:#{Amico.following_key}:#{id}", options)
|
222
267
|
end
|
223
268
|
|
224
|
-
#
|
269
|
+
# Retrieve a page of followers for a given ID.
|
225
270
|
#
|
226
|
-
# id
|
227
|
-
# options
|
228
|
-
# default({:page_size => Amico.page_size, :page => 1})
|
271
|
+
# @param id [String] ID of the individual.
|
272
|
+
# @param options [Hash] Options to be passed for retrieving a page of followers.
|
229
273
|
#
|
230
274
|
# Examples
|
231
275
|
#
|
@@ -233,16 +277,15 @@ module Amico
|
|
233
277
|
# Amico.follow(12, 1)
|
234
278
|
# Amico.followers(1, :page => 1)
|
235
279
|
#
|
236
|
-
#
|
280
|
+
# @return a page of followers for a given ID.
|
237
281
|
def followers(id, options = default_options)
|
238
282
|
members("#{Amico.namespace}:#{Amico.followers_key}:#{id}", options)
|
239
283
|
end
|
240
284
|
|
241
|
-
#
|
285
|
+
# Retrieve a page of blocked individuals for a given ID.
|
242
286
|
#
|
243
|
-
# id
|
244
|
-
# options
|
245
|
-
# default({:page_size => Amico.page_size, :page => 1})
|
287
|
+
# @param id [String] ID of the individual.
|
288
|
+
# @param options [Hash] Options to be passed for retrieving a page of blocked individuals.
|
246
289
|
#
|
247
290
|
# Examples
|
248
291
|
#
|
@@ -250,16 +293,15 @@ module Amico
|
|
250
293
|
# Amico.block(1, 12)
|
251
294
|
# Amico.blocked(1, :page => 1)
|
252
295
|
#
|
253
|
-
#
|
296
|
+
# @return a page of blocked individuals for a given ID.
|
254
297
|
def blocked(id, options = default_options)
|
255
298
|
members("#{Amico.namespace}:#{Amico.blocked_key}:#{id}", options)
|
256
299
|
end
|
257
300
|
|
258
|
-
#
|
301
|
+
# Retrieve a page of individuals that have reciprocated a follow for a given ID.
|
259
302
|
#
|
260
|
-
# id
|
261
|
-
# options
|
262
|
-
# default({:page_size => Amico.page_size, :page => 1})
|
303
|
+
# @param id [String] ID of the individual.
|
304
|
+
# @param options [Hash] Options to be passed for retrieving a page of individuals that have reciprocated a follow.
|
263
305
|
#
|
264
306
|
# Examples
|
265
307
|
#
|
@@ -269,15 +311,31 @@ module Amico
|
|
269
311
|
# Amico.follow(12, 1)
|
270
312
|
# Amico.reciprocated(1, :page => 1)
|
271
313
|
#
|
272
|
-
#
|
314
|
+
# @return a page of individuals that have reciprocated a follow for a given ID.
|
273
315
|
def reciprocated(id, options = default_options)
|
274
316
|
members("#{Amico.namespace}:#{Amico.reciprocated_key}:#{id}", options)
|
275
317
|
end
|
276
318
|
|
277
|
-
#
|
319
|
+
# Retrieve a page of pending relationships for a given ID.
|
278
320
|
#
|
279
|
-
# id
|
280
|
-
#
|
321
|
+
# @param id [String] ID of the individual.
|
322
|
+
# @param options [Hash] Options to be passed for retrieving a page of pending relationships.
|
323
|
+
#
|
324
|
+
# Examples
|
325
|
+
#
|
326
|
+
# Amico.follow(1, 11)
|
327
|
+
# Amico.follow(2, 11)
|
328
|
+
# Amico.pending(1, :page => 1)
|
329
|
+
#
|
330
|
+
# @return a page of pending relationships for a given ID.
|
331
|
+
def pending(id, options = default_options)
|
332
|
+
members("#{Amico.namespace}:#{Amico.pending_key}:#{id}", options)
|
333
|
+
end
|
334
|
+
|
335
|
+
# Count the number of pages of following relationships for an individual.
|
336
|
+
#
|
337
|
+
# @param id [String] ID of the individual.
|
338
|
+
# @param page_size [int] Page size.
|
281
339
|
#
|
282
340
|
# Examples
|
283
341
|
#
|
@@ -285,15 +343,15 @@ module Amico
|
|
285
343
|
# Amico.follow(1, 12)
|
286
344
|
# Amico.following_page_count(1)
|
287
345
|
#
|
288
|
-
#
|
346
|
+
# @return the number of pages of following relationships for an individual.
|
289
347
|
def following_page_count(id, page_size = Amico.page_size)
|
290
348
|
total_pages("#{Amico.namespace}:#{Amico.following_key}:#{id}", page_size)
|
291
349
|
end
|
292
350
|
|
293
|
-
#
|
351
|
+
# Count the number of pages of follower relationships for an individual.
|
294
352
|
#
|
295
|
-
# id
|
296
|
-
# page_size
|
353
|
+
# @param id [String] ID of the individual.
|
354
|
+
# @param page_size [int] Page size (default: Amico.page_size).
|
297
355
|
#
|
298
356
|
# Examples
|
299
357
|
#
|
@@ -301,15 +359,15 @@ module Amico
|
|
301
359
|
# Amico.follow(12, 1)
|
302
360
|
# Amico.followers_page_count(1)
|
303
361
|
#
|
304
|
-
#
|
362
|
+
# @return the number of pages of follower relationships for an individual.
|
305
363
|
def followers_page_count(id, page_size = Amico.page_size)
|
306
364
|
total_pages("#{Amico.namespace}:#{Amico.followers_key}:#{id}", page_size)
|
307
365
|
end
|
308
366
|
|
309
|
-
#
|
367
|
+
# Count the number of pages of blocked relationships for an individual.
|
310
368
|
#
|
311
|
-
# id
|
312
|
-
# page_size
|
369
|
+
# @param id [String] ID of the individual.
|
370
|
+
# @param page_size [int] Page size (default: Amico.page_size).
|
313
371
|
#
|
314
372
|
# Examples
|
315
373
|
#
|
@@ -317,15 +375,15 @@ module Amico
|
|
317
375
|
# Amico.block(1, 12)
|
318
376
|
# Amico.blocked_page_count(1)
|
319
377
|
#
|
320
|
-
#
|
378
|
+
# @return the number of pages of blocked relationships for an individual.
|
321
379
|
def blocked_page_count(id, page_size = Amico.page_size)
|
322
380
|
total_pages("#{Amico.namespace}:#{Amico.blocked_key}:#{id}", page_size)
|
323
381
|
end
|
324
382
|
|
325
|
-
#
|
383
|
+
# Count the number of pages of reciprocated relationships for an individual.
|
326
384
|
#
|
327
|
-
# id
|
328
|
-
# page_size
|
385
|
+
# @param id [String] ID of the individual.
|
386
|
+
# @param page_size [int] Page size (default: Amico.page_size).
|
329
387
|
#
|
330
388
|
# Examples
|
331
389
|
#
|
@@ -335,36 +393,72 @@ module Amico
|
|
335
393
|
# Amico.follow(12, 1)
|
336
394
|
# Amico.reciprocated_page_count(1)
|
337
395
|
#
|
338
|
-
#
|
396
|
+
# @return the number of pages of reciprocated relationships for an individual.
|
339
397
|
def reciprocated_page_count(id, page_size = Amico.page_size)
|
340
398
|
total_pages("#{Amico.namespace}:#{Amico.reciprocated_key}:#{id}", page_size)
|
341
399
|
end
|
342
400
|
|
401
|
+
# Count the number of pages of pending relationships for an individual.
|
402
|
+
#
|
403
|
+
# @param id [String] ID of the individual.
|
404
|
+
# @param page_size [int] Page size (default: Amico.page_size).
|
405
|
+
#
|
406
|
+
# Examples
|
407
|
+
#
|
408
|
+
# Amico.follow(11, 1)
|
409
|
+
# Amico.follow(12, 1)
|
410
|
+
# Amico.pending_page_count(1) # 1
|
411
|
+
#
|
412
|
+
# @return the number of pages of pending relationships for an individual.
|
413
|
+
def pending_page_count(id, page_size = Amico.page_size)
|
414
|
+
total_pages("#{Amico.namespace}:#{Amico.pending_key}:#{id}", page_size)
|
415
|
+
end
|
416
|
+
|
343
417
|
private
|
344
418
|
|
345
|
-
#
|
419
|
+
# Add the following, followers and check for a reciprocated relationship. To be used from the
|
420
|
+
# +follow++ and ++accept++ methods.
|
421
|
+
#
|
422
|
+
# @param from_id [String] The ID of the individual establishing the follow relationship.
|
423
|
+
# @param to_id [String] The ID of the individual to be followed.
|
424
|
+
def add_following_followers_reciprocated(from_id, to_id)
|
425
|
+
Amico.redis.multi do
|
426
|
+
Amico.redis.zadd("#{Amico.namespace}:#{Amico.following_key}:#{from_id}", Time.now.to_i, to_id)
|
427
|
+
Amico.redis.zadd("#{Amico.namespace}:#{Amico.followers_key}:#{to_id}", Time.now.to_i, from_id)
|
428
|
+
Amico.redis.zrem("#{Amico.namespace}:#{Amico.pending_key}:#{to_id}", from_id)
|
429
|
+
end
|
430
|
+
|
431
|
+
if reciprocated?(from_id, to_id)
|
432
|
+
Amico.redis.multi do
|
433
|
+
Amico.redis.zadd("#{Amico.namespace}:#{Amico.reciprocated_key}:#{from_id}", Time.now.to_i, to_id)
|
434
|
+
Amico.redis.zadd("#{Amico.namespace}:#{Amico.reciprocated_key}:#{to_id}", Time.now.to_i, from_id)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
# Default options for doing, for example, paging.
|
346
440
|
#
|
347
|
-
#
|
441
|
+
# @return a hash of the default options.
|
348
442
|
def default_options
|
349
443
|
{:page_size => Amico.page_size, :page => 1}
|
350
444
|
end
|
351
445
|
|
352
|
-
#
|
446
|
+
# Count the total number of pages for a given key in a Redis sorted set.
|
353
447
|
#
|
354
|
-
# key
|
355
|
-
# page_size
|
448
|
+
# @param key [String] Redis key.
|
449
|
+
# @param page_size [int] Page size from which to calculate total pages.
|
356
450
|
#
|
357
|
-
#
|
451
|
+
# @return total number of pages for a given key in a Redis sorted set.
|
358
452
|
def total_pages(key, page_size)
|
359
453
|
(Amico.redis.zcard(key) / page_size.to_f).ceil
|
360
454
|
end
|
361
455
|
|
362
|
-
#
|
456
|
+
# Retrieve a page of items from a Redis sorted set without scores.
|
363
457
|
#
|
364
|
-
# key
|
365
|
-
# options
|
458
|
+
# @param key [String] Redis key.
|
459
|
+
# @param options [Hash] Default options for paging.
|
366
460
|
#
|
367
|
-
#
|
461
|
+
# @return a page of items from a Redis sorted set without scores.
|
368
462
|
def members(key, options = default_options)
|
369
463
|
options = default_options.dup.merge!(options)
|
370
464
|
if options[:page] < 1
|
data/lib/amico/version.rb
CHANGED
@@ -9,6 +9,8 @@ describe Amico::Configuration do
|
|
9
9
|
configuration.followers_key.should eql('followers')
|
10
10
|
configuration.blocked_key.should eql('blocked')
|
11
11
|
configuration.reciprocated_key.should eql('reciprocated')
|
12
|
+
configuration.pending_key.should eql('pending')
|
13
|
+
configuration.pending_follow.should be_false
|
12
14
|
configuration.page_size.should be(25)
|
13
15
|
end
|
14
16
|
end
|
@@ -269,6 +269,127 @@ describe Amico::Relationships do
|
|
269
269
|
end
|
270
270
|
end
|
271
271
|
|
272
|
+
describe 'pending_follow enabled' do
|
273
|
+
before(:each) do
|
274
|
+
Amico.pending_follow = true
|
275
|
+
end
|
276
|
+
|
277
|
+
after(:each) do
|
278
|
+
Amico.pending_follow = false
|
279
|
+
end
|
280
|
+
|
281
|
+
describe '#follow' do
|
282
|
+
it 'should allow you to follow but the relationship is initially pending' do
|
283
|
+
Amico.follow(1, 11)
|
284
|
+
|
285
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.following_key}:1").should be(0)
|
286
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.followers_key}:11").should be(0)
|
287
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.pending_key}:11").should be(1)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should remove the pending relationship if you have a pending follow, but you unfollow' do
|
291
|
+
Amico.follow(1, 11)
|
292
|
+
|
293
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.following_key}:1").should be(0)
|
294
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.followers_key}:11").should be(0)
|
295
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.pending_key}:11").should be(1)
|
296
|
+
|
297
|
+
Amico.unfollow(1, 11)
|
298
|
+
|
299
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.following_key}:1").should be(0)
|
300
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.followers_key}:11").should be(0)
|
301
|
+
Amico.redis.zcard("#{Amico.namespace}:#{Amico.pending_key}:11").should be(0)
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'should remove the pending relationship and add to following and followers if #accept is called' do
|
305
|
+
Amico.follow(1, 11)
|
306
|
+
Amico.pending?(1, 11).should be_true
|
307
|
+
|
308
|
+
Amico.accept(1, 11)
|
309
|
+
|
310
|
+
Amico.pending?(1, 11).should be_false
|
311
|
+
Amico.following?(1, 11).should be_true
|
312
|
+
Amico.following?(11, 1).should be_false
|
313
|
+
Amico.follower?(11, 1).should be_true
|
314
|
+
Amico.follower?(1, 11).should be_false
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'should remove the pending relationship and add to following and followers if #accept is called and add to reciprocated relationship' do
|
318
|
+
Amico.follow(1, 11)
|
319
|
+
Amico.follow(11, 1)
|
320
|
+
Amico.pending?(1, 11).should be_true
|
321
|
+
Amico.pending?(11, 1).should be_true
|
322
|
+
|
323
|
+
Amico.accept(1, 11)
|
324
|
+
|
325
|
+
Amico.pending?(1, 11).should be_false
|
326
|
+
Amico.pending?(11, 1).should be_true
|
327
|
+
Amico.following?(1, 11).should be_true
|
328
|
+
Amico.following?(11, 1).should be_false
|
329
|
+
Amico.follower?(11, 1).should be_true
|
330
|
+
Amico.follower?(1, 11).should be_false
|
331
|
+
|
332
|
+
Amico.accept(11, 1)
|
333
|
+
|
334
|
+
Amico.pending?(1, 11).should be_false
|
335
|
+
Amico.pending?(11, 1).should be_false
|
336
|
+
Amico.following?(1, 11).should be_true
|
337
|
+
Amico.following?(11, 1).should be_true
|
338
|
+
Amico.follower?(11, 1).should be_true
|
339
|
+
Amico.follower?(1, 11).should be_true
|
340
|
+
Amico.reciprocated?(1, 11).should be_true
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe '#block' do
|
345
|
+
it 'should remove the pending relationship if you block someone' do
|
346
|
+
Amico.follow(11, 1)
|
347
|
+
Amico.pending?(11, 1).should be_true
|
348
|
+
Amico.block(1, 11)
|
349
|
+
Amico.pending?(11, 1).should be_false
|
350
|
+
Amico.blocked?(1, 11).should be_true
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe '#pending' do
|
355
|
+
it 'should return the correct list' do
|
356
|
+
Amico.follow(1, 11)
|
357
|
+
Amico.follow(11, 1)
|
358
|
+
Amico.pending(1).should eql(["11"])
|
359
|
+
Amico.pending(11).should eql(["1"])
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'should page correctly' do
|
363
|
+
add_reciprocal_followers
|
364
|
+
|
365
|
+
Amico.pending(1, :page => 1, :page_size => 5).size.should be(5)
|
366
|
+
Amico.pending(1, :page => 1, :page_size => 10).size.should be(10)
|
367
|
+
Amico.pending(1, :page => 1, :page_size => 26).size.should be(25)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe '#pending_count' do
|
372
|
+
it 'should return the correct count' do
|
373
|
+
Amico.follow(1, 11)
|
374
|
+
Amico.follow(11, 1)
|
375
|
+
Amico.follow(1, 12)
|
376
|
+
Amico.follow(12, 1)
|
377
|
+
Amico.follow(1, 13)
|
378
|
+
Amico.pending_count(1).should be(2)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
describe '#pending_page_count' do
|
383
|
+
it 'should return the correct count' do
|
384
|
+
add_reciprocal_followers
|
385
|
+
|
386
|
+
Amico.pending_page_count(1).should be(1)
|
387
|
+
Amico.pending_page_count(1, 10).should be(3)
|
388
|
+
Amico.pending_page_count(1, 5).should be(5)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
272
393
|
private
|
273
394
|
|
274
395
|
def add_reciprocal_followers(count = 26, block_relationship = false)
|
data/spec/spec_helper.rb
CHANGED
@@ -4,11 +4,19 @@ require 'amico'
|
|
4
4
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
5
5
|
|
6
6
|
RSpec.configure do |config|
|
7
|
-
config.before(:
|
7
|
+
config.before(:all) do
|
8
8
|
Amico.configure do |configuration|
|
9
|
-
redis = Redis.new
|
10
|
-
redis.flushall
|
9
|
+
redis = Redis.new(:db => 15)
|
11
10
|
configuration.redis = redis
|
12
11
|
end
|
13
12
|
end
|
13
|
+
|
14
|
+
config.before(:each) do
|
15
|
+
Amico.redis.flushdb
|
16
|
+
end
|
17
|
+
|
18
|
+
config.after(:all) do
|
19
|
+
Amico.redis.flushdb
|
20
|
+
Amico.redis.quit
|
21
|
+
end
|
14
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amico
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &2157986940 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2157986940
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &2157986520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2157986520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &2157986100 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2157986100
|
47
47
|
description: Relationships (e.g. friendships) backed by Redis
|
48
48
|
email:
|
49
49
|
- dczarnecki@agoragames.com
|
@@ -81,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
81
|
version: '0'
|
82
82
|
segments:
|
83
83
|
- 0
|
84
|
-
hash:
|
84
|
+
hash: 4319511261827775332
|
85
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
90
|
version: '0'
|
91
91
|
segments:
|
92
92
|
- 0
|
93
|
-
hash:
|
93
|
+
hash: 4319511261827775332
|
94
94
|
requirements: []
|
95
95
|
rubyforge_project: amico
|
96
96
|
rubygems_version: 1.8.10
|