recommendable 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.gitignore +57 -0
  2. data/.travis.yml +3 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +118 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.markdown +340 -0
  7. data/Rakefile +26 -0
  8. data/TODO +6 -0
  9. data/app/jobs/recommendable/recommendation_refresher.rb +12 -0
  10. data/app/models/recommendable/dislike.rb +9 -0
  11. data/app/models/recommendable/ignore.rb +9 -0
  12. data/app/models/recommendable/like.rb +9 -0
  13. data/app/models/recommendable/stashed_item.rb +9 -0
  14. data/config/routes.rb +3 -0
  15. data/db/migrate/20120124193723_create_likes.rb +17 -0
  16. data/db/migrate/20120124193728_create_dislikes.rb +17 -0
  17. data/db/migrate/20120127092558_create_ignores.rb +17 -0
  18. data/db/migrate/20120131173909_create_stashed_items.rb +17 -0
  19. data/lib/generators/recommendable/USAGE +8 -0
  20. data/lib/generators/recommendable/install_generator.rb +47 -0
  21. data/lib/generators/recommendable/templates/initializer.rb +18 -0
  22. data/lib/recommendable.rb +19 -0
  23. data/lib/recommendable/acts_as_recommendable.rb +85 -0
  24. data/lib/recommendable/acts_as_recommended_to.rb +659 -0
  25. data/lib/recommendable/engine.rb +13 -0
  26. data/lib/recommendable/exceptions.rb +4 -0
  27. data/lib/recommendable/railtie.rb +6 -0
  28. data/lib/recommendable/version.rb +3 -0
  29. data/lib/tasks/recommendable_tasks.rake +1 -0
  30. data/recommendable.gemspec +32 -0
  31. data/script/rails +8 -0
  32. data/spec/configuration_spec.rb +9 -0
  33. data/spec/dummy/README.rdoc +261 -0
  34. data/spec/dummy/Rakefile +7 -0
  35. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  36. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  38. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  39. data/spec/dummy/app/mailers/.gitkeep +0 -0
  40. data/spec/dummy/app/models/.gitkeep +0 -0
  41. data/spec/dummy/app/models/bully.rb +2 -0
  42. data/spec/dummy/app/models/movie.rb +3 -0
  43. data/spec/dummy/app/models/php_framework.rb +2 -0
  44. data/spec/dummy/app/models/user.rb +3 -0
  45. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  46. data/spec/dummy/config.ru +4 -0
  47. data/spec/dummy/config/application.rb +56 -0
  48. data/spec/dummy/config/boot.rb +10 -0
  49. data/spec/dummy/config/database.yml +25 -0
  50. data/spec/dummy/config/environment.rb +5 -0
  51. data/spec/dummy/config/environments/development.rb +37 -0
  52. data/spec/dummy/config/environments/production.rb +67 -0
  53. data/spec/dummy/config/environments/test.rb +37 -0
  54. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  55. data/spec/dummy/config/initializers/inflections.rb +15 -0
  56. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  57. data/spec/dummy/config/initializers/recommendable.rb +16 -0
  58. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  59. data/spec/dummy/config/initializers/session_store.rb +8 -0
  60. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/spec/dummy/config/locales/en.yml +5 -0
  62. data/spec/dummy/config/routes.rb +4 -0
  63. data/spec/dummy/db/migrate/20120128005553_create_likes.recommendable.rb +18 -0
  64. data/spec/dummy/db/migrate/20120128005554_create_dislikes.recommendable.rb +18 -0
  65. data/spec/dummy/db/migrate/20120128005555_create_ignores.recommendable.rb +18 -0
  66. data/spec/dummy/db/migrate/20120128020228_create_users.rb +9 -0
  67. data/spec/dummy/db/migrate/20120128020413_create_movies.rb +10 -0
  68. data/spec/dummy/db/migrate/20120128024632_create_php_frameworks.rb +9 -0
  69. data/spec/dummy/db/migrate/20120128024804_create_bullies.rb +9 -0
  70. data/spec/dummy/db/migrate/20120131195416_create_stashed_items.recommendable.rb +18 -0
  71. data/spec/dummy/db/schema.rb +89 -0
  72. data/spec/dummy/lib/assets/.gitkeep +0 -0
  73. data/spec/dummy/log/.gitkeep +0 -0
  74. data/spec/dummy/public/404.html +26 -0
  75. data/spec/dummy/public/422.html +26 -0
  76. data/spec/dummy/public/500.html +25 -0
  77. data/spec/dummy/public/favicon.ico +0 -0
  78. data/spec/dummy/recommendable_dummy_development +0 -0
  79. data/spec/dummy/recommendable_dummy_test +0 -0
  80. data/spec/dummy/script/rails +6 -0
  81. data/spec/factories.rb +16 -0
  82. data/spec/models/dislike_spec.rb +27 -0
  83. data/spec/models/ignore_spec.rb +27 -0
  84. data/spec/models/like_spec.rb +28 -0
  85. data/spec/models/stashed_item_spec.rb +27 -0
  86. data/spec/models/user_benchmark_spec.rb +49 -0
  87. data/spec/models/user_spec.rb +320 -0
  88. data/spec/spec_helper.rb +28 -0
  89. metadata +254 -0
data/.gitignore ADDED
@@ -0,0 +1,57 @@
1
+ # RVM / rbenv version files
2
+ .rvmrc
3
+ .rbenv-version
4
+
5
+ # rcov generated
6
+ coverage
7
+
8
+ # rdoc generated
9
+ rdoc
10
+
11
+ # yard generated
12
+ doc
13
+ .yardoc
14
+
15
+ # bundler
16
+ .bundle
17
+ vendor/bundle
18
+
19
+ # jeweler generated
20
+ pkg
21
+
22
+ # logging
23
+ *.log
24
+
25
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
26
+ #
27
+ # * Create a file at ~/.gitignore
28
+ # * Include files you want ignored
29
+ # * Run: git config --global core.excludesfile ~/.gitignore
30
+ #
31
+ # After doing this, these files will be ignored in all your git projects,
32
+ # saving you from having to 'pollute' every project you touch with them
33
+ #
34
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
35
+ #
36
+ # For MacOS:
37
+
38
+ .DS_Store
39
+
40
+ # For TextMate
41
+ *.tmproj
42
+ tmtags
43
+
44
+ # For emacs:
45
+ #*~
46
+ #\#*
47
+ #.\#*
48
+
49
+ # For vim:
50
+ *.swp
51
+
52
+ # For redcar:
53
+ #.redcar
54
+
55
+ # For rubinius:
56
+ #*.rbc
57
+ .rake_tasks*
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ gem "rails", ">= 3.0.0"
4
+ gem "redis", "~> 2.2.0"
5
+ gem "resque", "~> 1.19.0"
6
+ gem "resque-loner", "~> 1.2.0"
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "sqlite3"
12
+ gem "minitest"
13
+ gem "shoulda"
14
+ gem "miniskirt"
15
+ gem "yard", "~> 0.6.0"
16
+ gem "bundler", "~> 1.0.0"
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,118 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (3.2.0)
5
+ actionpack (= 3.2.0)
6
+ mail (~> 2.4.0)
7
+ actionpack (3.2.0)
8
+ activemodel (= 3.2.0)
9
+ activesupport (= 3.2.0)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.0)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.1)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.0)
18
+ activesupport (= 3.2.0)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.0)
21
+ activemodel (= 3.2.0)
22
+ activesupport (= 3.2.0)
23
+ arel (~> 3.0.0)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.0)
26
+ activemodel (= 3.2.0)
27
+ activesupport (= 3.2.0)
28
+ activesupport (3.2.0)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ arel (3.0.0)
32
+ builder (3.0.0)
33
+ erubis (2.7.0)
34
+ hike (1.2.1)
35
+ i18n (0.6.0)
36
+ journey (1.0.0)
37
+ json (1.6.5)
38
+ mail (2.4.1)
39
+ i18n (>= 0.4.0)
40
+ mime-types (~> 1.16)
41
+ treetop (~> 1.4.8)
42
+ mime-types (1.17.2)
43
+ miniskirt (1.1.1)
44
+ activesupport (>= 2.2)
45
+ minitest (2.10.1)
46
+ multi_json (1.0.4)
47
+ polyglot (0.3.3)
48
+ rack (1.4.0)
49
+ rack-cache (1.1)
50
+ rack (>= 0.4)
51
+ rack-protection (1.2.0)
52
+ rack
53
+ rack-ssl (1.3.2)
54
+ rack
55
+ rack-test (0.6.1)
56
+ rack (>= 1.0)
57
+ rails (3.2.0)
58
+ actionmailer (= 3.2.0)
59
+ actionpack (= 3.2.0)
60
+ activerecord (= 3.2.0)
61
+ activeresource (= 3.2.0)
62
+ activesupport (= 3.2.0)
63
+ bundler (~> 1.0)
64
+ railties (= 3.2.0)
65
+ railties (3.2.0)
66
+ actionpack (= 3.2.0)
67
+ activesupport (= 3.2.0)
68
+ rack-ssl (~> 1.3.2)
69
+ rake (>= 0.8.7)
70
+ rdoc (~> 3.4)
71
+ thor (~> 0.14.6)
72
+ rake (0.9.2.2)
73
+ rdoc (3.12)
74
+ json (~> 1.4)
75
+ redis (2.2.2)
76
+ redis-namespace (1.0.3)
77
+ redis (< 3.0.0)
78
+ resque (1.19.0)
79
+ multi_json (~> 1.0)
80
+ redis-namespace (~> 1.0.2)
81
+ sinatra (>= 0.9.2)
82
+ vegas (~> 0.1.2)
83
+ resque-loner (1.2.0)
84
+ resque (~> 1.0)
85
+ shoulda (2.11.3)
86
+ sinatra (1.3.2)
87
+ rack (~> 1.3, >= 1.3.6)
88
+ rack-protection (~> 1.2)
89
+ tilt (~> 1.3, >= 1.3.3)
90
+ sprockets (2.1.2)
91
+ hike (~> 1.2)
92
+ rack (~> 1.0)
93
+ tilt (~> 1.1, != 1.3.0)
94
+ sqlite3 (1.3.5)
95
+ thor (0.14.6)
96
+ tilt (1.3.3)
97
+ treetop (1.4.10)
98
+ polyglot
99
+ polyglot (>= 0.3.1)
100
+ tzinfo (0.3.31)
101
+ vegas (0.1.11)
102
+ rack (>= 1.0.0)
103
+ yard (0.6.8)
104
+
105
+ PLATFORMS
106
+ ruby
107
+
108
+ DEPENDENCIES
109
+ bundler (~> 1.0.0)
110
+ miniskirt
111
+ minitest
112
+ rails (>= 3.0.0)
113
+ redis (~> 2.2.0)
114
+ resque (~> 1.19.0)
115
+ resque-loner (~> 1.2.0)
116
+ shoulda
117
+ sqlite3
118
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 David Celis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,340 @@
1
+ # recommendable [![Build Status](https://secure.travis-ci.org/davidcelis/recommendable.png)](http://travis-ci.org/davidcelis/recommendable)
2
+
3
+ Recommendable is a Rails Engine to add Like/Dislike functionality to your
4
+ application. It uses Redis to generate recommendations quickly through a
5
+ collaborative filtering algorithm that I modified myself. Your users' tastes
6
+ are compared with one another and used to give them great recommendations!
7
+ Yes, Redis is required. Scroll to the end of the README for more info on that.
8
+
9
+ Why Likes and Dislikes?
10
+ -----------------------
11
+
12
+ [I hate five-star rating scales][0].
13
+
14
+ **tl;dr:** Binary voting habits are most certainly not an odd phenomenon.
15
+ People tend to vote in only two different ways. Some folks give either 1 star
16
+ or 5 stars. Some people fluctuate between 3 and 4 stars. There are always
17
+ outliers, but what it comes down to is this: a person's binary votes indicate,
18
+ in general, a dislike or like of what they're voting on. I'm just giving the
19
+ people what they want.
20
+
21
+ Installation
22
+ ------------
23
+
24
+ Add the following to your Rails application's `Gemfile`:
25
+
26
+ ``` ruby
27
+ gem "recommendable"
28
+ ```
29
+
30
+ After your `bundle install`, you can then run:
31
+
32
+ $ rails g recommendable:install (--user-class=User)
33
+
34
+ After running the installation generator, you should double check
35
+ `config/initializers/recommendable.rb` for options on configuring your Redis
36
+ connection.
37
+
38
+ Finally, Recommendable uses Resque to place users in a queue. Users must wait
39
+ their turn to regenerate recommendations so that your application does not get
40
+ throttled. Don't worry, though! Most of the time, your users will barely have
41
+ to wait. In fact, you can run multiple resque workers if you wish.
42
+
43
+ Assuming you have `redis-server` running...
44
+
45
+ $ QUEUE=recommendable rake environment resque:work
46
+
47
+ You can run this command multiple times if you wish to start more than one
48
+ worker. This is the standard rake task for starting a Resque worker so, for
49
+ more options on this task, head over to [defunkt/resque][1]
50
+
51
+ Usage
52
+ -----
53
+
54
+ In your Rails model that represents your application's user:
55
+
56
+ ``` ruby
57
+ class User < ActiveRecord::Base
58
+ acts_as_recommended_to
59
+
60
+ # ...
61
+ end
62
+ ```
63
+
64
+ Then, from any Rails model you wish your `user` to be able to `like` or `dislike`:
65
+
66
+ ``` ruby
67
+ class Movie < ActiveRecord::Base
68
+ acts_as_recommendable
69
+
70
+ # ...
71
+ end
72
+
73
+ class Show < ActiveRecord::Base
74
+ acts_as_recommendable
75
+
76
+ # ...
77
+ end
78
+ ````
79
+
80
+ And that's it!
81
+
82
+ ### Liking/Disliking
83
+
84
+ At this point, your user will be ready to `like` movies...
85
+
86
+ ``` ruby
87
+ current_user.like Movie.create(:title => '2001: A Space Odyssey', :year => 1968)
88
+ #=> true
89
+ ```
90
+
91
+ ... or `dislike` them:
92
+
93
+ ``` ruby
94
+ current_user.dislike Movie.create(:title => 'Star Wars: Episode I - The Phantom Menace', :year => 1999)
95
+ #=> true
96
+ ```
97
+
98
+ In addition, several helpful methods are available to your user now:
99
+
100
+ ``` ruby
101
+ current_user.likes? Movie.find_by_title('2001: A Space Odyssey')
102
+ #=> true
103
+ current_user.dislikes? Movie.find_by_title('Star Wars: Episode I - The Phantom Menace')
104
+ #=> true
105
+ other_movie = Movie.create('Back to the Future', :year => 1985)
106
+ current_user.dislikes? other_movie
107
+ #=> false
108
+ current_user.like other_movie
109
+ #=> true
110
+ current_user.liked
111
+ #=> [#<Movie name: '2001: A Space Odyssey', year: 1968>, #<Movie name: 'Back to the Future', :year => 1985>]
112
+ current_user.disliked
113
+ #=> [#<Movie name: 'Star Wars: Episode I - The Phantom Menace', year: 1999>]
114
+ ```
115
+
116
+ Because you are allowed to declare multiple models as recommendable, you may
117
+ wish to return a set of liked or disliked objects for only one of those
118
+ models.
119
+
120
+ ``` ruby
121
+ current_user.liked_for(Movie)
122
+ #=> [#<Movie name: '2001: A Space Odyssey', year: 1968>, #<Movie name: 'Back to the Future', :year => 1985>]
123
+ current_user.disliked_for(Show)
124
+ #=> []
125
+ ```
126
+
127
+ ### Ignoring
128
+
129
+ If you want to give your user the ability to `ignore` recommendations or even
130
+ just hide stuff on your website that they couldn't care less about, you can!
131
+
132
+ ``` ruby
133
+ weird_movie_nobody_wants_to_watch = Movie.create(:title => 'Cool World', :year => 1998)
134
+ current_user.ignore weird_movie_nobody_wants_to_watch
135
+ #=> true
136
+ current_user.ignored
137
+ #=> [#<Movie name: 'Cool World', year: 1998>]
138
+ current_user.ignored_for(Show)
139
+ #=> []
140
+ ```
141
+
142
+ Do what you will with this list of records. The power is yours.
143
+
144
+ ### Saving for later
145
+
146
+ Your user might want to maintain a list of items to try later but still receive
147
+ new recommendations. For this, you can use Recommendable::StashedItems. Note that
148
+ adding an item to a user's stash will remove it from their list of recommendations.
149
+ Additionally, an item can not be stashed if the user already likes or dislikes it.
150
+
151
+ ``` ruby
152
+ movie_to_watch_later = Movie.create(:title => 'The Descendants', :year => 2011)
153
+ current_user.stash(movie_to_watch_later)
154
+ #=> true
155
+ current_user.stashed
156
+ #=> [#<Movie name: 'The Descendants', year: 2011>]
157
+ # Later...
158
+ current_user.like(movie_to_watch_later)
159
+ #=> true
160
+ current_user.stash(movie_to_watch_later)
161
+ #=> nil
162
+ current_user.has_stashed?(movie_to_watch_later)
163
+ #=> false
164
+ ```
165
+
166
+ ### Unliking/Undisliking/Unignoring/Unstashing
167
+
168
+ Note that liking a movie that has already been disliked (or vice versa) will
169
+ simply destroy the old rating and create a new one. If a user attempts to `like`
170
+ a movie that they already like, however, nothing happens and `nil` is returned.
171
+ If you wish to manually remove an item from a user's likes or dislikes or
172
+ ignored records, you can:
173
+
174
+ ``` ruby
175
+ current_user.like Movie.create(:title => 'Avatar', :year => 2009)
176
+ #=> true
177
+ current_user.unlike Movie.find_by_title('Avatar')
178
+ #=> true
179
+ current_user.liked
180
+ #=> []
181
+ ```
182
+
183
+ You can use `undislike`, `unignore` and `unstash` in the same fashion. So, as
184
+ far as the Likes and Dislikes go, do you think that's enough? Because I didn't.
185
+
186
+ ``` ruby
187
+ friend = User.create(:username => 'joeblow')
188
+ awesome_movie = Movie.find_by_title('2001: A Space Odyssey')
189
+ friend.like awesome_movie
190
+ #=> true
191
+ awesome_movie.liked_by
192
+ #=> [#<User username: 'davidcelis'>, #<User username: 'joeblow'>]
193
+ Movie.find_by_title('Star Wars: Episode I - The Phantom Menace').disliked_by
194
+ #=> [#<User username: 'davidcelis'>]
195
+ current_user.common_likes_with(friend)
196
+ #=> [#<Movie title: '2001: A Space Odyssey', year: 1968>]
197
+ ```
198
+
199
+ `common_dislikes_with` and `disagreements_with` are available for similar use.
200
+
201
+ Recommendations
202
+ ---------------
203
+
204
+ When a user submits a new `Like` or `Dislike`, they enter a queue to have their
205
+ recommendations refreshed. Once that user exits the queue, you can retrieve
206
+ these like so:
207
+
208
+ ``` ruby
209
+ current_user.recommendations
210
+ #=> [#<Movie highly_recommended>, #<Show somewhat_recommended>, #<Movie meh>]
211
+ current_user.recommendations_for(Show)
212
+ #=> [#<Show somewhat_recommended>]
213
+ ```
214
+
215
+ The top recommendations are returned in an array ordered by how good recommendable
216
+ believes the recommendation to be (from best to worst).
217
+
218
+ ``` ruby
219
+ current_user.like somewhat_recommended_show
220
+ #=> true
221
+ current_user.recommendations
222
+ #=> [#<Movie highly_recommended>, #<Movie meh>]
223
+ ```
224
+
225
+ Finally, you can also get a list of the users found to be most similar to your
226
+ current user:
227
+
228
+ ``` ruby
229
+ current_user.similar_raters
230
+ #=> [#<User username: 'joe-blow'>, #<User username: 'less-so-than-joe-blow']
231
+ ```
232
+
233
+ Likewise, this list is ordered from most similar to least similar.
234
+
235
+ Documentation
236
+ -------------
237
+
238
+ Some of the above methods are tweakable with options. For example, you can
239
+ adjust the number of recommendations returned to you (the default is 10) and
240
+ the number of similar uses returned (also 10). To see these options, check
241
+ the documentation.
242
+
243
+ A note on Redis
244
+ ---------------
245
+
246
+ Recommendable currently depends on [Redis](http://redis.io/). It will install
247
+ the redis-rb gem as a dependency, but you must install Redis and run it
248
+ yourself. Also note that your Redis database must be persistent. Recommendable
249
+ will use Redis to permanently store sorted sets to quickly access recommendations.
250
+ Please take care with your Redis database! Fortunately, if you do lose your
251
+ Redis database, there's hope (more on that later).
252
+
253
+ Installing Redis
254
+ ----------------
255
+
256
+ Recommendable requires Redis to deliver recommendations. Why? Because my
257
+ collaborative filtering algorithm is based almost entirely on set math, and
258
+ Ruby's Set class just won't cut it for fast recommendations.
259
+
260
+ ### Homebrew
261
+
262
+ For Mac OS X users, homebrew is by far the easiest way to install Redis.
263
+
264
+ $ brew install redis
265
+ $ redis-server /usr/local/etc/redis.conf
266
+
267
+ You should now have Redis running as a daemon on localhost:6379
268
+
269
+ ### Via Resque
270
+
271
+ Resque (which is also a dependency of recommendable) includes Rake tasks that
272
+ will install and run Redis for you:
273
+
274
+ $ git clone git://github.com/defunkt/resque.git
275
+ $ cd resque
276
+ $ rake redis:install dtach:install
277
+ $ rake redis:start
278
+
279
+ If you do not have admin rights to your machine:
280
+
281
+ $ git clone git://github.com/defunkt/resque.git
282
+ $ cd resque
283
+ $ PREFIX=<your_prefix> rake redis:install dtach:install
284
+ $ rake redis:start
285
+
286
+ Redis will now be running on localhost:6379. After a second, you can hit `ctrl-\`
287
+ to detach and keep Redis running in the background.
288
+
289
+ (Thanks to [defunkt][1] for mentioning this
290
+ method, and thanks to [ezmobius][2] for
291
+ making it possible)
292
+
293
+ Manually regenerating recommendations
294
+ -------------------------------------
295
+
296
+ If a catastrophe occurs and your Redis database is either destroyed or rendered
297
+ unusable in some other way, there is hope. You can run the following from your
298
+ application's console (assuming your user class is User):
299
+
300
+ User.all.each do |user|
301
+ user.update_similarities
302
+ user.update_recommendations
303
+ end
304
+
305
+ But please try not to have to do this manually!
306
+
307
+ Contributing to recommendable
308
+ -----------------------------
309
+
310
+ Read the [Contributing][3] wiki page first.
311
+
312
+ Once you've made your great commits:
313
+
314
+ 1. [Fork][4] recommendable
315
+ 2. Create a feature branch
316
+ 3. Write your code (and tests please)
317
+ 4. Push to your branch's origin
318
+ 5. Create a [Pull Request][5] from your branch
319
+ 6. That's it!
320
+
321
+ Links
322
+ -----
323
+ * Code: `git clone git://github.com/davidcelis/recommendable.git`
324
+ * Home: <http://github.com/davidcelis/recommendable>
325
+ * Docs: <http://rubydoc.info/gems/recommendable/0.1.0/frames>
326
+ * Bugs: <http://github.com/davidcelis/recommendable/issues>
327
+ * Gems: <http://rubygems.org/gems/recommendable>
328
+
329
+ Copyright
330
+ ---------
331
+
332
+ Copyright © 2012 David Celis. See LICENSE.txt for
333
+ further details.
334
+
335
+ [0]: http://davidcelis.com/blog/2012/02/01/why-i-hate-five-star-ratings/
336
+ [1]: https://github.com/defunkt/resque
337
+ [2]: https://github.com/ezmobius/redis-rb
338
+ [3]: http://wiki.github.com/defunkt/resque/contributing
339
+ [4]: http://help.github.com/forking/
340
+ [5]: http://help.github.com/pull-requests/