flocks 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9670cef0827448591a9929ae6b1e29e9a10907d8
4
+ data.tar.gz: f44b3a80e9ba291f79472cb32f207de3e3fd2fda
5
+ SHA512:
6
+ metadata.gz: b1bee72695582429793848aa7ae8694c6f05e5f8710ae2cf14e9f79baf0ecf62afc395e4fc1c316676f57a393f70a0dbc74413ddc7167480e630b3c9b56c460d
7
+ data.tar.gz: ac2b6281eb80f9853680c5312358035be1af26e6794aafa4f25695470a7ccd1d69e9fe4722ca45f5ab7e6c8b1963fe1e374771f40e5aa1cff145744132cc768b
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in flocks.gemspec
4
+ gemspec
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2014, Byliner, Inc
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice, this
10
+ list of conditions and the following disclaimer in the documentation and/or
11
+ other materials provided with the distribution.
12
+ * Neither the name of the DUO Interactive, LLC nor the names of its contributors
13
+ may be used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,142 @@
1
+ # Flocks
2
+
3
+ Flocks is a lightweight searchable social graph that tracks a user's followers, who they are following, and who they have blocked.
4
+
5
+ Flocks uses [Redis](http://redis.io/documentation) to store the relationships.
6
+
7
+ User lists are sorted alphabetically and can be searched!
8
+
9
+ Flocks uses usernames (or any unique string identifier) when following in order to sort the following/followers lists.
10
+ By requiring usernames when establishing relationships, Flocks becomes searchable.
11
+ Flocks will return all user ids with user_ids matching the query string.
12
+ Flocks search capabilities can be used to autocomplete text fields with usernames in a user's social graph.
13
+
14
+ For example, if a user is following: 'Adam', 'Aaron', 'Addison', and 'John'
15
+
16
+ Searching for 'a' will return the ids associated with Adam, Aaron, and Addison
17
+ Searching for 'ad' will return the id associated with Adam
18
+
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'flocks'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install flocks
33
+
34
+ ## Usage
35
+
36
+ Configure flocks:
37
+
38
+ ```ruby
39
+ Flocks.configure do |configuration|
40
+ configuration.redis = Redis.new
41
+ configuration.namespace = 'flocks'
42
+ configuration.following_key = 'following'
43
+ configuration.followers_key = 'followers'
44
+ configuration.blocked_key = 'blocked'
45
+ configuration.page_size = 25
46
+ end
47
+ ```
48
+
49
+ Use flocks:
50
+
51
+ ```ruby
52
+ require 'flocks'
53
+ => true
54
+
55
+ Flocks.configure do |configuration|
56
+ configuration.redis = Redis.new
57
+ configuration.namespace = 'flocks'
58
+ configuration.following_key = 'following'
59
+ configuration.followers_key = 'followers'
60
+ configuration.blocked_key = 'blocked'
61
+ configuration.page_size = 25
62
+ end
63
+
64
+ Flocks.new(1, 'username').follow(11, 'other_username')
65
+ => true
66
+
67
+ Flocks.new(1, 'username').following?(11)
68
+ => true
69
+
70
+ Flocks.new(11, 'other_username').following?(1)
71
+ => false
72
+
73
+ Flocks.new(11, 'other_username').follow(1, 'username')
74
+ => true
75
+
76
+ Flocks.new(11, 'other_username').following?(1)
77
+ => true
78
+
79
+ Flocks.new(1, 'username').following_count
80
+ => 1
81
+
82
+ Flocks.new(1, 'username').followers_count
83
+ => 1
84
+
85
+ Flocks.new(11, 'other_username').unfollow(1)
86
+ => true
87
+
88
+ Flocks.new(11, 'other_username').following_count
89
+ => 0
90
+
91
+ Flocks.new(1, 'username').following_count
92
+ => 1
93
+
94
+ Flocks.new(1, 'username').following
95
+ => ["11"]
96
+
97
+ Flocks.new(1, 'username').block(11)
98
+ => true
99
+
100
+ Flocks.new(11, 'username').following?(1)
101
+ => false
102
+
103
+ Flocks.new(1, 'username').blocked?(11)
104
+ => true
105
+
106
+ Flocks.new(11, 'other_username').follow(1)
107
+ => nil
108
+
109
+ Flocks.new(1, 'username').unblock(11)
110
+ => true
111
+
112
+ Flocks.new(1, 'username').blocked?(11)
113
+ => false
114
+
115
+ Flocks.new(11, 'other_username').follow(1)
116
+ => true
117
+
118
+ Flocks.new(1, 'username').follow(11)
119
+ => true
120
+
121
+ Flocks.new(1, 'username').search_following('other')
122
+ => ["11"]
123
+
124
+ Flocks.new(1, 'username').search_followers('other')
125
+ => ["11"]
126
+
127
+ Flocks.new(1, 'username').search_graph('other')
128
+ => ["11"]
129
+
130
+ ```
131
+
132
+ ## Thanks
133
+
134
+ Many thanks to [amico](https://github.com/agoragames/amico) creator [agoragames](https://github.com/agoragames). A lot of the code used was inspired by the [amico gem](https://github.com/agoragames/amico).
135
+
136
+ ## Contributing
137
+
138
+ 1. Fork it ( http://github.com/<my-github-username>/flocks/fork )
139
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
140
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
141
+ 4. Push to the branch (`git push origin my-new-feature`)
142
+ 5. Create new Pull Request
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'flocks/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "flocks"
8
+ spec.version = Flocks::VERSION
9
+ spec.authors = ["Adam Ryan"]
10
+ spec.email = ["adam.g.ryan@gmail.com"]
11
+ spec.summary = %q{Single node social relationships using redis.}
12
+ spec.description = %q{Single node social relationships using redis.}
13
+ spec.homepage = "https://github.com/byliner/flocks"
14
+ spec.license = "BSD"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "redis"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "minitest"
26
+ end
@@ -0,0 +1,23 @@
1
+ require 'redis'
2
+ require 'flocks/configuration'
3
+ require 'flocks/ordering'
4
+ require 'flocks/relationships'
5
+ require 'flocks/search'
6
+ require 'flocks/version'
7
+
8
+ module Flocks
9
+ class << self
10
+ include Configuration
11
+ include Ordering
12
+ include Search
13
+ include Relationships
14
+
15
+ attr_accessor :user_id, :username_score
16
+
17
+ def new(user_id, username = nil)
18
+ self.user_id = user_id
19
+ self.username_score = rank_username(username)
20
+ self
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,113 @@
1
+ module Flocks
2
+ # Configuration settings for Flocks.
3
+ module Configuration
4
+ # Redis instance.
5
+ attr_accessor :redis
6
+
7
+ # Flocks namespace for Redis.
8
+ attr_writer :namespace
9
+
10
+ # Key used in Redis for tracking who an individual is following.
11
+ attr_writer :following_key
12
+
13
+ # Key used in Redis for tracking the followers of an individual.
14
+ attr_writer :followers_key
15
+
16
+ # Key used in Redis for tracking who an individual blocks.
17
+ attr_writer :blocked_key
18
+
19
+ # Key used in Redis for tracking who has blocked an individual.
20
+ attr_writer :blocked_by_key
21
+
22
+ # Key used in Redis for tracking who has reciprocated a follow for an individual.
23
+ attr_writer :reciprocated_key
24
+
25
+ # Key used in Redis for tracking pending follow relationships for an individual.
26
+ attr_writer :pending_key
27
+
28
+ # Key used in Redis for tracking who an individual is awaiting approval from.
29
+ attr_writer :pending_with_key
30
+
31
+ # Key used to indicate whether or not a follow should be pending or not.
32
+ attr_writer :pending_follow
33
+
34
+ # Page size to be used when paging through the various types of relationships.
35
+ attr_writer :page_size
36
+
37
+ # Set the percision for relationship sorting granularity
38
+ attr_writer :string_score_percision
39
+
40
+ # Yield self to be able to configure Flocks with block-style configuration.
41
+ #
42
+ # Example:
43
+ #
44
+ # Flocks.configure do |configuration|
45
+ # configuration.redis = Redis.new
46
+ # configuration.namespace = 'flocks'
47
+ # configuration.following_key = 'following'
48
+ # configuration.followers_key = 'followers'
49
+ # configuration.blocked_key = 'blocked'
50
+ # configuration.blocked_by_key = 'blocked_by'
51
+ # configuration.page_size = 25
52
+ # end
53
+ def configure
54
+ yield self
55
+ end
56
+
57
+ # Flocks namespace for Redis.
58
+ #
59
+ # @return the Flocks namespace or the default of 'flocks' if not set.
60
+ def namespace
61
+ @namespace ||= 'flocks'
62
+ end
63
+
64
+ # Key used in Redis for tracking who an individual is following.
65
+ #
66
+ # @return the key used in Redis for tracking who an individual is following or the default of 'following' if not set.
67
+ def following_key
68
+ @following_key ||= 'following'
69
+ end
70
+
71
+ # Key used in Redis for tracking the followers of an individual.
72
+ #
73
+ # @return the key used in Redis for tracking the followers of an individual or the default of 'followers' if not set.
74
+ def followers_key
75
+ @followers_key ||= 'followers'
76
+ end
77
+
78
+ # Key used in Redis for tracking who an individual blocks.
79
+ #
80
+ # @return the key used in Redis for tracking who an individual blocks or the default of 'blocked' if not set.
81
+ def blocked_key
82
+ @blocked_key ||= 'blocked'
83
+ end
84
+
85
+ # Key used in Redis for tracking who has blocked an individual.
86
+ #
87
+ # @return the key used in Redis for tracking who has blocked an individual or the default of 'blocked_by' if not set.
88
+ def blocked_by_key
89
+ @blocked_by_key ||= 'blocked_by'
90
+ end
91
+
92
+ # Key used in Redis for tracking who has reciprocated a follow for an individual.
93
+ #
94
+ # @return the key used in Redis for tracking who has reciprocated a follow for an individual or the default of 'reciprocated' if not set.
95
+ def reciprocated_key
96
+ @reciprocated_key ||= 'reciprocated'
97
+ end
98
+
99
+ # Page size to be used when paging through the various types of relationships.
100
+ #
101
+ # @return the page size to be used when paging through the various types of relationships or the default of 25 if not set.
102
+ def page_size
103
+ @page_size ||= 25
104
+ end
105
+
106
+ # Number of characters to be used when scoring a username for indexing in redis
107
+ #
108
+ # @return the scoring percision
109
+ def string_score_percision
110
+ @string_score_percision ||= 5
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,33 @@
1
+ module Flocks
2
+ module Ordering
3
+ def rank_username(username)
4
+ # Selects the number of characters to be evaluated for sorting
5
+ percision_index = string_score_percision - 1
6
+
7
+ # Base score
8
+ score = 0
9
+
10
+ # Get the first 5 characters in an array
11
+ characters = username.to_s.downcase[0..percision_index].split('')
12
+
13
+ # If the username is short, tack on the lowest ascii value
14
+ characters << '0' until characters.size == string_score_percision
15
+
16
+ # Reverse them for easy multiplication scoring
17
+ characters.reverse.each_with_index do |char, i|
18
+
19
+ # Use the mutiplier, increase magnitude for weighting first letters more
20
+ # multiplier = (character_multiplier[0..(i + 1)].to_i)
21
+
22
+ multiplier = 10 ** i
23
+ # Square the multiplier to avoid large ascii values from thwrowing off calculations
24
+ char_score = "#{char}"[0].ord * multiplier * multiplier
25
+
26
+ # Aggregate the swcore
27
+ score += char_score
28
+ end
29
+
30
+ score
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,87 @@
1
+ module Flocks
2
+ module Relationships
3
+
4
+ def relationship_following_key
5
+ "#{following_key}/#{user_id}"
6
+ end
7
+
8
+ def relationship_followers_key(id = user_id)
9
+ "#{followers_key}/#{id}"
10
+ end
11
+
12
+ def relationship_blocked_key
13
+ "#{blocked_key}/#{user_id}"
14
+ end
15
+
16
+ def follow(other_user_id, other_username)
17
+ return if (user_id == other_user_id) || (blocked? other_user_id)
18
+
19
+ other_username_score = rank_username(other_username)
20
+ redis.zadd relationship_following_key, other_username_score, other_user_id
21
+ redis.zadd relationship_followers_key(other_user_id), username_score, user_id
22
+ end
23
+
24
+ def unfollow(other_user_id)
25
+ redis.zrem relationship_following_key, other_user_id
26
+ redis.zrem relationship_followers_key(other_user_id), user_id
27
+ end
28
+
29
+ def following(page = 0, limit = 0)
30
+ # Without arguments returns the full set
31
+ start, stop = bounds(page, limit)
32
+ redis.zrange relationship_following_key, start, stop
33
+ end
34
+
35
+ def followers(page = 0, limit= 0)
36
+ start, stop = bounds(page, limit)
37
+ redis.zrange relationship_followers_key(user_id), start, stop
38
+ end
39
+
40
+ def following?(other_user_id)
41
+ following.include? other_user_id.to_s
42
+ end
43
+
44
+ def following_count
45
+ redis.zcard relationship_following_key
46
+ end
47
+
48
+ def followers_count
49
+ redis.zcard relationship_followers_key
50
+ end
51
+
52
+ def following_page_count(limit = page_size)
53
+ (following_count.to_f / limit.to_f).ceil
54
+ end
55
+
56
+ def followers_page_count(limit = page_size)
57
+ (followers_count.to_f / limit.to_f).ceil
58
+ end
59
+
60
+ def block(other_user_id)
61
+ # Unfollow
62
+ unfollow other_user_id
63
+ self.new(other_user_id).unfollow user_id
64
+
65
+ # Block
66
+ redis.sadd relationship_blocked_key, other_user_id
67
+ end
68
+
69
+ def unblock(other_user_id)
70
+ redis.srem relationship_blocked_key, other_user_id
71
+ end
72
+
73
+ def blocked
74
+ redis.smembers relationship_blocked_key
75
+ end
76
+
77
+ def blocked?(other_user_id)
78
+ blocked.include? other_user_id.to_s
79
+ end
80
+
81
+ protected
82
+
83
+ def bounds(page, limit)
84
+ [(page - 1) * limit, (page * limit) - 1]
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,37 @@
1
+ module Flocks
2
+ module Search
3
+
4
+ # Search a user's list of following
5
+ def search_following(query)
6
+ redis.zrangebyscore relationship_following_key, start_score(query), stop_score(query)
7
+ end
8
+
9
+ # Search a user's list of followers
10
+ def search_followers(query)
11
+ redis.zrangebyscore relationship_followers_key, start_score(query), stop_score(query)
12
+ end
13
+
14
+ # Search a user's entire social graph
15
+ def search_graph(query)
16
+ (search_following(query) + search_followers(query)).uniq
17
+ end
18
+
19
+ protected
20
+
21
+ # Set constraints to return relevent results
22
+ # Starting score for redis zrangebyscore
23
+ def start_score(query)
24
+ rank_username(query)
25
+ end
26
+
27
+ # 'aaa' -> 'aab'
28
+ # Ending score for redis zrangebyscore
29
+ def stop_score(query)
30
+ query_array = query.chars
31
+ last_char = (query_array.pop.ord + 1).chr
32
+ stop_name = query_array.push(last_char).join('')
33
+ rank_username(stop_name)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Flocks
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ class ConfigurationTest < MiniTest::Test
4
+
5
+ def test_configuration
6
+ Flocks.configure do |config|
7
+ config.redis = Redis.new
8
+ config.namespace = 'flocks_test'
9
+ config.following_key = 'following_test'
10
+ config.followers_key = 'followers_test'
11
+ config.blocked_key = 'blocked_test'
12
+ config.blocked_by_key = 'blocked_by_test'
13
+ config.page_size = 50
14
+ end
15
+
16
+ assert_equal 'flocks_test', Flocks.namespace
17
+ assert_equal 'following_test', Flocks.following_key
18
+ assert_equal 'followers_test', Flocks.followers_key
19
+ assert_equal 'blocked_test', Flocks.blocked_key
20
+ assert_equal 'blocked_by_test', Flocks.blocked_by_key
21
+ assert_equal 50, Flocks.page_size
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+
3
+ class FlocksTest < MiniTest::Test
4
+
5
+ def test_initialization
6
+ flock = Flocks.new(1, 1)
7
+ assert_equal 1, flock.user_id
8
+ assert_equal 4948484848, flock.username_score
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class OrderingTest < MiniTest::Test
4
+ include Flocks::Ordering
5
+ include Flocks::Configuration
6
+
7
+ def test_score_string_extension
8
+ # ASCII 'd' == 100, summed up in the scorer == 10101010100
9
+ assert_equal 10101010100, rank_username('ddddd')
10
+ end
11
+
12
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ class RelationshipsTest < MiniTest::Test
4
+
5
+ def test_follow_and_unfollow
6
+ flock = Flocks.new(1, 'username')
7
+ flock.follow(2, 'other_username')
8
+ assert flock.following?(2)
9
+
10
+ flock.unfollow(2)
11
+ refute flock.following?(2)
12
+ end
13
+
14
+ def test_following_and_following_count
15
+ flock = Flocks.new(1, 'username')
16
+ flock.follow(2, 'other_username')
17
+ assert_equal ['2'], flock.following
18
+ assert_equal 1, flock.following_count
19
+ end
20
+
21
+ def test_followers_and_followers_count
22
+ flock = Flocks.new(1, 'username')
23
+ flock.follow(2, 'other_username')
24
+
25
+ other_flock = Flocks.new(2, 'other_username')
26
+ assert_equal ['1'], other_flock.followers
27
+ assert_equal 1, other_flock.followers_count
28
+ end
29
+
30
+ def test_following_page_count
31
+ flock = Flocks.new(1, 'username')
32
+ (2..40).to_a.each { |i| flock.follow(i, "#{i}") }
33
+ assert_equal 2, flock.following_page_count
34
+ end
35
+
36
+ def test_followers_page_count
37
+ (2..40).to_a.each { |i| Flocks.new(i, "#{i}").follow(1, "username") }
38
+ flock = Flocks.new(1, 'username')
39
+ assert_equal 2, flock.followers_page_count
40
+ end
41
+
42
+ def test_block_blocked_and_unblock
43
+ flock = Flocks.new(1, 'username')
44
+ flock.follow(2, 'other_username')
45
+
46
+ flock.block(2)
47
+ assert_equal ['2'], flock.blocked
48
+ assert flock.blocked? 2
49
+ refute Flocks.new(2).following? 1
50
+
51
+ flock.unblock(2)
52
+ assert_equal ([]), flock.blocked
53
+ end
54
+
55
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class SearchTest < MiniTest::Test
4
+
5
+ def test_search_following
6
+ flock = Flocks.new(1, 'username')
7
+ flock.follow(2, 'other_username')
8
+ flock.follow(3, 'other_username2')
9
+ flock.follow(4, 'dissimilar_username')
10
+ results = flock.search_following('other')
11
+
12
+ assert_equal ['2', '3'], results
13
+ end
14
+
15
+ def test_search_followers
16
+ Flocks.new(2, 'other_username').follow(1, 'username')
17
+ Flocks.new(3, 'other_username2').follow(1, 'username')
18
+ Flocks.new(4, 'disssimilar_username').follow(1, 'username')
19
+
20
+ flock = Flocks.new(1, 'username')
21
+ results = flock.search_followers('other')
22
+ assert_equal ['2', '3'], results
23
+ end
24
+
25
+ def test_search_graph
26
+ Flocks.new(1, 'username').follow(2, 'other_username')
27
+ Flocks.new(2, 'other_username').follow(1, 'username')
28
+ Flocks.new(1, 'username').follow(3, 'other_username3')
29
+ Flocks.new(4, 'other_username4').follow(1, 'username')
30
+ Flocks.new(5, 'disssimilar_username').follow(1, 'username')
31
+
32
+ flock = Flocks.new(1, 'username')
33
+ results = flock.search_graph('other')
34
+ assert_equal ['2', '3', '4'], results
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.require :test
4
+
5
+ require 'minitest/autorun'
6
+ require 'redis'
7
+ require 'flocks'
8
+
9
+ # Support files
10
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/support/*.rb"].each do |file|
11
+ require file
12
+ end
13
+
14
+ class MiniTest::Test
15
+ def setup
16
+ Flocks.configure do |config|
17
+ config.redis = Redis.new
18
+ config.namespace = 'flocks'
19
+ config.following_key = 'following'
20
+ config.followers_key = 'followers'
21
+ config.blocked_key = 'blocked'
22
+ config.blocked_by_key = 'blocked_by'
23
+ config.page_size = 25
24
+ end
25
+
26
+ Flocks.redis.flushdb
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flocks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Ryan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Single node social relationships using redis.
70
+ email:
71
+ - adam.g.ryan@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - flocks.gemspec
82
+ - lib/flocks.rb
83
+ - lib/flocks/configuration.rb
84
+ - lib/flocks/ordering.rb
85
+ - lib/flocks/relationships.rb
86
+ - lib/flocks/search.rb
87
+ - lib/flocks/version.rb
88
+ - test/flocks/configuration_test.rb
89
+ - test/flocks/flocks_test.rb
90
+ - test/flocks/ordering_test.rb
91
+ - test/flocks/relationships_test.rb
92
+ - test/flocks/search_test.rb
93
+ - test/test_helper.rb
94
+ homepage: https://github.com/byliner/flocks
95
+ licenses:
96
+ - BSD
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.0
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Single node social relationships using redis.
118
+ test_files:
119
+ - test/flocks/configuration_test.rb
120
+ - test/flocks/flocks_test.rb
121
+ - test/flocks/ordering_test.rb
122
+ - test/flocks/relationships_test.rb
123
+ - test/flocks/search_test.rb
124
+ - test/test_helper.rb