recommendable 1.1.7 → 2.0.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/lib/recommendable.rb +38 -26
- data/lib/recommendable/configuration.rb +47 -0
- data/lib/recommendable/helpers.rb +3 -9
- data/lib/recommendable/helpers/calculations.rb +150 -0
- data/lib/recommendable/helpers/queriers.rb +23 -0
- data/lib/recommendable/helpers/redis_key_mapper.rb +29 -0
- data/lib/recommendable/orm/active_record.rb +6 -0
- data/lib/recommendable/orm/data_mapper.rb +7 -0
- data/lib/recommendable/orm/mongo_mapper.rb +8 -0
- data/lib/recommendable/orm/mongoid.rb +7 -0
- data/lib/recommendable/ratable.rb +83 -0
- data/lib/recommendable/ratable/dislikable.rb +26 -0
- data/lib/recommendable/ratable/likable.rb +26 -0
- data/lib/recommendable/rater.rb +109 -0
- data/lib/recommendable/rater/bookmarker.rb +120 -0
- data/lib/recommendable/rater/disliker.rb +122 -0
- data/lib/recommendable/rater/hider.rb +120 -0
- data/lib/recommendable/rater/liker.rb +122 -0
- data/lib/recommendable/rater/recommender.rb +68 -0
- data/lib/recommendable/version.rb +5 -4
- data/lib/recommendable/workers/delayed_job.rb +16 -0
- data/lib/recommendable/workers/rails.rb +16 -0
- data/lib/recommendable/workers/resque.rb +13 -0
- data/lib/recommendable/workers/sidekiq.rb +13 -0
- metadata +62 -131
- data/.gitignore +0 -57
- data/.travis.yml +0 -3
- data/CHANGELOG.markdown +0 -159
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -112
- data/LICENSE.txt +0 -22
- data/README.markdown +0 -135
- data/Rakefile +0 -26
- data/TODO +0 -7
- data/app/models/recommendable/dislike.rb +0 -19
- data/app/models/recommendable/ignore.rb +0 -19
- data/app/models/recommendable/like.rb +0 -19
- data/app/models/recommendable/stash.rb +0 -19
- data/app/workers/recommendable/delayed_job_worker.rb +0 -17
- data/app/workers/recommendable/rails_worker.rb +0 -17
- data/app/workers/recommendable/resque_worker.rb +0 -14
- data/app/workers/recommendable/sidekiq_worker.rb +0 -14
- data/config/routes.rb +0 -3
- data/db/migrate/20120124193723_create_likes.rb +0 -17
- data/db/migrate/20120124193728_create_dislikes.rb +0 -17
- data/db/migrate/20120127092558_create_ignores.rb +0 -17
- data/db/migrate/20120131173909_create_stashes.rb +0 -17
- data/lib/generators/recommendable/USAGE +0 -8
- data/lib/generators/recommendable/install_generator.rb +0 -40
- data/lib/generators/recommendable/templates/initializer.rb +0 -28
- data/lib/recommendable/acts_as_recommendable.rb +0 -176
- data/lib/recommendable/acts_as_recommended_to.rb +0 -774
- data/lib/recommendable/engine.rb +0 -14
- data/lib/recommendable/exceptions.rb +0 -4
- data/lib/recommendable/railtie.rb +0 -6
- data/lib/sidekiq/middleware/client/unique_jobs.rb +0 -37
- data/lib/sidekiq/middleware/server/unique_jobs.rb +0 -17
- data/lib/tasks/recommendable_tasks.rake +0 -1
- data/recommendable.gemspec +0 -30
- data/script/rails +0 -8
- data/spec/configuration_spec.rb +0 -9
- data/spec/dummy/README.rdoc +0 -261
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/assets/javascripts/application.js +0 -15
- data/spec/dummy/app/assets/stylesheets/application.css +0 -13
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/bully.rb +0 -2
- data/spec/dummy/app/models/movie.rb +0 -2
- data/spec/dummy/app/models/php_framework.rb +0 -2
- data/spec/dummy/app/models/user.rb +0 -3
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/config/application.rb +0 -56
- data/spec/dummy/config/boot.rb +0 -10
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -37
- data/spec/dummy/config/environments/production.rb +0 -67
- data/spec/dummy/config/environments/test.rb +0 -37
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/recommendable.rb +0 -14
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -4
- data/spec/dummy/db/migrate/20120128005553_create_likes.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128005554_create_dislikes.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128005555_create_ignores.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128020228_create_users.rb +0 -9
- data/spec/dummy/db/migrate/20120128020413_create_movies.rb +0 -10
- data/spec/dummy/db/migrate/20120128024632_create_php_frameworks.rb +0 -9
- data/spec/dummy/db/migrate/20120128024804_create_bullies.rb +0 -9
- data/spec/dummy/db/migrate/20120131195416_create_stashes.recommendable.rb +0 -19
- data/spec/dummy/db/schema.rb +0 -89
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -25
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/recommendable_dummy_development +0 -0
- data/spec/dummy/recommendable_dummy_test +0 -0
- data/spec/dummy/script/rails +0 -6
- data/spec/factories.rb +0 -16
- data/spec/models/dislike_spec.rb +0 -41
- data/spec/models/ignore_spec.rb +0 -27
- data/spec/models/like_spec.rb +0 -42
- data/spec/models/movie_spec.rb +0 -82
- data/spec/models/stash_spec.rb +0 -27
- data/spec/models/user_benchmark_spec.rb +0 -49
- data/spec/models/user_spec.rb +0 -443
- data/spec/spec_helper.rb +0 -28
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Recommendable
|
|
2
|
+
module Ratable
|
|
3
|
+
module Dislikable
|
|
4
|
+
# Fetch a list of users that have disliked this item.
|
|
5
|
+
#
|
|
6
|
+
# @return [Array] a list of users that have disliked this item
|
|
7
|
+
def disliked_by
|
|
8
|
+
Recommendable.query(Recommendable.config.user_class, disliked_by_ids)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Get the number of users that have disliked this item
|
|
12
|
+
#
|
|
13
|
+
# @return [Fixnum] the number of users that have disliked this item
|
|
14
|
+
def disliked_by_count
|
|
15
|
+
Recommendable.redis.scard(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(self.class, id))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get the IDs of users that have disliked this item.
|
|
19
|
+
#
|
|
20
|
+
# @return [Array] the IDs of users that have disliked this item
|
|
21
|
+
def disliked_by_ids
|
|
22
|
+
Recommendable.redis.smembers(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(self.class, id))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Recommendable
|
|
2
|
+
module Ratable
|
|
3
|
+
module Likable
|
|
4
|
+
# Fetch a list of users that have liked this item.
|
|
5
|
+
#
|
|
6
|
+
# @return [Array] a list of users that have liked this item
|
|
7
|
+
def liked_by
|
|
8
|
+
Recommendable.query(Recommendable.config.user_class, liked_by_ids)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Get the number of users that have liked this item
|
|
12
|
+
#
|
|
13
|
+
# @return [Fixnum] the number of users that have liked this item
|
|
14
|
+
def liked_by_count
|
|
15
|
+
Recommendable.redis.scard(Recommendable::Helpers::RedisKeyMapper.liked_by_set_for(self.class, id))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get the IDs of users that have liked this item.
|
|
19
|
+
#
|
|
20
|
+
# @return [Array] the IDs of users that have liked this item
|
|
21
|
+
def liked_by_ids
|
|
22
|
+
Recommendable.redis.smembers(Recommendable::Helpers::RedisKeyMapper.liked_by_set_for(self.class, id))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require 'recommendable/rater/liker'
|
|
2
|
+
require 'recommendable/rater/disliker'
|
|
3
|
+
require 'recommendable/rater/hider'
|
|
4
|
+
require 'recommendable/rater/bookmarker'
|
|
5
|
+
require 'recommendable/rater/recommender'
|
|
6
|
+
require 'hooks'
|
|
7
|
+
|
|
8
|
+
module Recommendable
|
|
9
|
+
module Rater
|
|
10
|
+
extend ActiveSupport::Concern
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def recommends(*things)
|
|
14
|
+
Recommendable.configure do |config|
|
|
15
|
+
config.ratable_classes = []
|
|
16
|
+
config.user_class = self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
things.each { |thing| thing.to_s.classify.constantize.make_recommendable! }
|
|
20
|
+
|
|
21
|
+
class_eval do
|
|
22
|
+
include Liker
|
|
23
|
+
include Disliker
|
|
24
|
+
include Hider
|
|
25
|
+
include Bookmarker
|
|
26
|
+
include Recommender
|
|
27
|
+
include Hooks
|
|
28
|
+
|
|
29
|
+
if ancestors.include?(ActiveRecord::Base) || include?(Mongoid::Document) || include?(MongoMapper::Document) || include?(MongoMapper::EmbeddedDocument)
|
|
30
|
+
before_destroy :remove_from_recommendable!
|
|
31
|
+
elsif include?(DataMapper::Resource)
|
|
32
|
+
before :destroy, :remove_from_recommendable!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
define_hooks :before_like, :after_like, :before_unlike, :after_unlike,
|
|
36
|
+
:before_dislike, :after_dislike, :before_undislike, :after_undislike,
|
|
37
|
+
:before_hide, :after_hide, :before_unhide, :after_unhide,
|
|
38
|
+
:before_bookmark, :after_bookmark, :before_unbookmark, :after_unbookmark
|
|
39
|
+
|
|
40
|
+
before_like lambda { |obj| undislike(obj) || unhide(obj) }
|
|
41
|
+
before_dislike lambda { |obj| unlike(obj) || unhide(obj) }
|
|
42
|
+
|
|
43
|
+
%w[like unlike dislike undislike].each do |action|
|
|
44
|
+
send("after_#{action}", lambda { |obj|
|
|
45
|
+
Recommendable::Helpers::Calculations.update_score_for(obj.class, obj.id)
|
|
46
|
+
Recommendable.enqueue(self.id) if Recommendable.config.auto_enqueue
|
|
47
|
+
})
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
%w[like dislike hide bookmark].each do |action|
|
|
51
|
+
send("after_#{action}", lambda { |obj| unrecommend(obj) })
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def method_missing(method, *args, &block)
|
|
55
|
+
if method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_in_common_with\z/
|
|
56
|
+
begin
|
|
57
|
+
send("#{$1}_in_common_with", $2.classify.constantize, *args)
|
|
58
|
+
rescue NameError
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_count\z/
|
|
62
|
+
begin
|
|
63
|
+
send("#{$1}_count_for", $2.classify.constantize, *args)
|
|
64
|
+
rescue NameError
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_ids\z/
|
|
68
|
+
begin
|
|
69
|
+
send("#{$1}_ids_for", $2.classify.constantize)
|
|
70
|
+
rescue NameError
|
|
71
|
+
super
|
|
72
|
+
end
|
|
73
|
+
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked|recommended)_(.+)\z/
|
|
74
|
+
begin
|
|
75
|
+
send("#{$1}_for", $2.classify.constantize)
|
|
76
|
+
rescue NameError
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
else
|
|
80
|
+
super
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def respond_to?(method, include_private = false)
|
|
85
|
+
if method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_in_common_with\z/ ||
|
|
86
|
+
method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_ids\z/ ||
|
|
87
|
+
method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked|recommended)_(.+)\z/
|
|
88
|
+
begin
|
|
89
|
+
true if $2.classify.constantize.recommendable?
|
|
90
|
+
rescue NameError
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
else
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def rated?(obj)
|
|
99
|
+
likes?(obj) || dislikes?(obj)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def rated_anything?
|
|
103
|
+
likes_count > 0 || dislikes_count > 0
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module Recommendable
|
|
2
|
+
module Rater
|
|
3
|
+
module Bookmarker
|
|
4
|
+
# Bookmark an object. This is not possible if the object is hidden.
|
|
5
|
+
#
|
|
6
|
+
# @param [Object] obj the object to be bookmarked
|
|
7
|
+
# @return true if object was bookmarked successfully
|
|
8
|
+
# @raise [ArgumentError] if the passed object was not declared ratable
|
|
9
|
+
def bookmark(obj)
|
|
10
|
+
raise(ArgumentError, 'Object has not been declared ratable.') unless obj.respond_to?(:recommendable?) && obj.recommendable?
|
|
11
|
+
return if hides?(obj) || bookmarks?(obj)
|
|
12
|
+
|
|
13
|
+
run_hook(:before_bookmark, obj)
|
|
14
|
+
Recommendable.redis.sadd(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(obj.class, id), obj.id)
|
|
15
|
+
run_hook(:after_bookmark, obj)
|
|
16
|
+
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Check whether the user has bookmarked an object.
|
|
21
|
+
#
|
|
22
|
+
# @param [Object] obj the object in question
|
|
23
|
+
# @return true if the user has bookmarked obj, false if not
|
|
24
|
+
def bookmarks?(obj)
|
|
25
|
+
Recommendable.redis.sismember(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(obj.class, id), obj.id)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Unbookmark an object. This removes the object from a user's set of bookmarks.
|
|
29
|
+
#
|
|
30
|
+
# @param [Object] obj the object to be unbookmarked
|
|
31
|
+
# @return true if the object was bookmarked successfully, nil if the object wasn't already bookmarked
|
|
32
|
+
def unbookmark(obj)
|
|
33
|
+
return unless bookmarks?(obj)
|
|
34
|
+
|
|
35
|
+
run_hook(:before_unbookmark, obj)
|
|
36
|
+
Recommendable.redis.srem(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(obj.class, id), obj.id)
|
|
37
|
+
run_hook(:after_unbookmark, obj)
|
|
38
|
+
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Retrieve an array of objects the user has bookmarked
|
|
43
|
+
#
|
|
44
|
+
# @return [Array] an array of records
|
|
45
|
+
def bookmarks
|
|
46
|
+
Recommendable.config.ratable_classes.map { |klass| bookmarked_for(klass) }.flatten
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Retrieve an array of objects both this user and another user have bookmarked
|
|
50
|
+
#
|
|
51
|
+
# @return [Array] an array of records
|
|
52
|
+
def bookmarks_in_common_with(user)
|
|
53
|
+
Recommendable.config.ratable_classes.map { |klass| bookmarked_in_common_with(klass, user) }.flatten
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Get the number of items the user has bookmarked
|
|
57
|
+
#
|
|
58
|
+
# @return [Fixnum] the number of bookmarked items
|
|
59
|
+
def bookmarks_count
|
|
60
|
+
Recommendable.config.ratable_classes.inject(0) do |sum, klass|
|
|
61
|
+
sum + bookmarked_count_for(klass)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
# Fetch IDs for objects belonging to a passed class that the user has bookmarked
|
|
68
|
+
#
|
|
69
|
+
# @param [String, Symbol, Class] the class for which you want IDs
|
|
70
|
+
# @return [Array] an array of IDs
|
|
71
|
+
# @private
|
|
72
|
+
def bookmarked_ids_for(klass)
|
|
73
|
+
ids = Recommendable.redis.smembers(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, id))
|
|
74
|
+
ids.map!(&:to_i) if [:active_record, :data_mapper].include?(Recommendable.config.orm)
|
|
75
|
+
ids
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Fetch records belonging to a passed class that the user has bookmarked
|
|
79
|
+
#
|
|
80
|
+
# @param [String, Symbol, Class] the class for which you want bookmarked records
|
|
81
|
+
# @return [Array] an array of bookmarked records
|
|
82
|
+
# @private
|
|
83
|
+
def bookmarked_for(klass)
|
|
84
|
+
Recommendable.query(klass, bookmarked_ids_for(klass))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get the number of items belonging to a passed class that the user has bookmarked
|
|
88
|
+
#
|
|
89
|
+
# @param [String, Symbol, Class] the class for which you want a count of bookmarks
|
|
90
|
+
# @return [Fixnum] the number of bookmarks
|
|
91
|
+
# @private
|
|
92
|
+
def bookmarked_count_for(klass)
|
|
93
|
+
Recommendable.redis.scard(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, id))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Get a list of records that both this user and a passed user have
|
|
97
|
+
# bookmarked
|
|
98
|
+
#
|
|
99
|
+
# @param [User] the other user
|
|
100
|
+
# @param [String, Symbol, Class] the class of common bookmarked items
|
|
101
|
+
# @return [Array] an array of records both users have bookmarked
|
|
102
|
+
# @private
|
|
103
|
+
def bookmarked_in_common_with(klass, user)
|
|
104
|
+
Recommendable.query(klass, bookmarked_ids_in_common_with(klass, user))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get a list of IDs for records that both this user and a passed user have
|
|
108
|
+
# bookmarked
|
|
109
|
+
#
|
|
110
|
+
# @param [User] the other user
|
|
111
|
+
# @param [String, Symbol, Class] the class of common bookmarked items
|
|
112
|
+
# @return [Array] an array of IDs for records that both users have bookmarked
|
|
113
|
+
# @private
|
|
114
|
+
def bookmarked_ids_in_common_with(klass, user_id)
|
|
115
|
+
user_id = user_id.id if user_id.is_a?(Recommendable.config.user_class)
|
|
116
|
+
Recommendable.redis.sinter(Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, id), Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, user_id))
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Recommendable
|
|
2
|
+
module Rater
|
|
3
|
+
module Disliker
|
|
4
|
+
# Dislike an object. This will remove the item from a user's set of likes
|
|
5
|
+
# or hidden items
|
|
6
|
+
#
|
|
7
|
+
# @param [Object] obj the object to be disliked
|
|
8
|
+
# @return true if object was disliked successfully
|
|
9
|
+
# @raise [ArgumentError] if the passed object was not declared ratable
|
|
10
|
+
def dislike(obj)
|
|
11
|
+
raise(ArgumentError, 'Object has not been declared ratable.') unless obj.respond_to?(:recommendable?) && obj.recommendable?
|
|
12
|
+
return if dislikes?(obj)
|
|
13
|
+
|
|
14
|
+
run_hook(:before_dislike, obj)
|
|
15
|
+
Recommendable.redis.sadd(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(obj.class, id), obj.id)
|
|
16
|
+
Recommendable.redis.sadd(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(obj.class, obj.id), id)
|
|
17
|
+
run_hook(:after_dislike, obj)
|
|
18
|
+
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Check whether the user has disliked an object.
|
|
23
|
+
#
|
|
24
|
+
# @param [Object] obj the object in question
|
|
25
|
+
# @return true if the user has disliked obj, false if not
|
|
26
|
+
def dislikes?(obj)
|
|
27
|
+
Recommendable.redis.sismember(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(obj.class, id), obj.id)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Undislike an object. This removes the object from a user's set of dislikes.
|
|
31
|
+
#
|
|
32
|
+
# @param [Object] obj the object to be undisliked
|
|
33
|
+
# @return true if the object was disliked successfully, nil if the object wasn't already disliked
|
|
34
|
+
def undislike(obj)
|
|
35
|
+
return unless dislikes?(obj)
|
|
36
|
+
|
|
37
|
+
run_hook(:before_undislike, obj)
|
|
38
|
+
Recommendable.redis.srem(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(obj.class, id), obj.id)
|
|
39
|
+
Recommendable.redis.srem(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(obj.class, obj.id), id)
|
|
40
|
+
run_hook(:after_undislike, obj)
|
|
41
|
+
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Retrieve an array of objects the user has disliked
|
|
46
|
+
#
|
|
47
|
+
# @return [Array] an array of records
|
|
48
|
+
def dislikes
|
|
49
|
+
Recommendable.config.ratable_classes.map { |klass| disliked_for(klass) }.flatten
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Retrieve an array of objects both this user and another user have disliked
|
|
53
|
+
#
|
|
54
|
+
# @return [Array] an array of records
|
|
55
|
+
def dislikes_in_common_with(user)
|
|
56
|
+
Recommendable.config.ratable_classes.map { |klass| disliked_in_common_with(klass, user) }.flatten
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get the number of items the user has disliked
|
|
60
|
+
#
|
|
61
|
+
# @return [Fixnum] the number of disliked items
|
|
62
|
+
def dislikes_count
|
|
63
|
+
Recommendable.config.ratable_classes.inject(0) do |sum, klass|
|
|
64
|
+
sum + disliked_count_for(klass)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Fetch IDs for objects belonging to a passed class that the user has disliked
|
|
71
|
+
#
|
|
72
|
+
# @param [String, Symbol, Class] the class for which you want IDs
|
|
73
|
+
# @return [Array] an array of IDs
|
|
74
|
+
# @private
|
|
75
|
+
def disliked_ids_for(klass)
|
|
76
|
+
ids = Recommendable.redis.smembers(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id))
|
|
77
|
+
ids.map!(&:to_i) if [:active_record, :data_mapper].include?(Recommendable.config.orm)
|
|
78
|
+
ids
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Fetch records belonging to a passed class that the user has disliked
|
|
82
|
+
#
|
|
83
|
+
# @param [String, Symbol, Class] the class for which you want disliked records
|
|
84
|
+
# @return [Array] an array of disliked records
|
|
85
|
+
# @private
|
|
86
|
+
def disliked_for(klass)
|
|
87
|
+
Recommendable.query(klass, disliked_ids_for(klass))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Get the number of items belonging to a passed class that the user has disliked
|
|
91
|
+
#
|
|
92
|
+
# @param [String, Symbol, Class] the class for which you want a count of dislikes
|
|
93
|
+
# @return [Fixnum] the number of dislikes
|
|
94
|
+
# @private
|
|
95
|
+
def disliked_count_for(klass)
|
|
96
|
+
Recommendable.redis.scard(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Get a list of records that both this user and a passed user have disliked
|
|
100
|
+
#
|
|
101
|
+
# @param [User] the other user
|
|
102
|
+
# @param [String, Symbol, Class] the class of common disliked items
|
|
103
|
+
# @return [Array] an array of records both users have disliked
|
|
104
|
+
# @private
|
|
105
|
+
def disliked_in_common_with(klass, user)
|
|
106
|
+
Recommendable.query(klass, disliked_ids_in_common_with(klass, user))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Get a list of IDs for records that both this user and a passed user have
|
|
110
|
+
# disliked
|
|
111
|
+
#
|
|
112
|
+
# @param [User, Fixnum] the other user (or its ID)
|
|
113
|
+
# @param [String, Symbol, Class] the class of common disliked items
|
|
114
|
+
# @return [Array] an array of IDs for records that both users have disliked
|
|
115
|
+
# @private
|
|
116
|
+
def disliked_ids_in_common_with(klass, user_id)
|
|
117
|
+
user_id = user_id.id if user_id.is_a?(Recommendable.config.user_class)
|
|
118
|
+
Recommendable.redis.sinter(Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id), Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, user_id))
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module Recommendable
|
|
2
|
+
module Rater
|
|
3
|
+
module Hider
|
|
4
|
+
# Hide an object. This action is only possible if the user has not yet
|
|
5
|
+
# rated or bookmarked the object.
|
|
6
|
+
#
|
|
7
|
+
# @param [Object] obj the object to be hidden
|
|
8
|
+
# @return true if object was hidden successfully
|
|
9
|
+
# @raise [ArgumentError] if the passed object was not declared ratable
|
|
10
|
+
def hide(obj)
|
|
11
|
+
raise(ArgumentError, 'Object has not been declared ratable.') unless obj.respond_to?(:recommendable?) && obj.recommendable?
|
|
12
|
+
return if likes?(obj) || dislikes?(obj) || bookmarks?(obj) || hides?(obj)
|
|
13
|
+
|
|
14
|
+
run_hook(:before_hide, obj)
|
|
15
|
+
Recommendable.redis.sadd(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(obj.class, id), obj.id)
|
|
16
|
+
run_hook(:after_hide, obj)
|
|
17
|
+
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Check whether the user has hidden an object.
|
|
22
|
+
#
|
|
23
|
+
# @param [Object] obj the object in question
|
|
24
|
+
# @return true if the user has hidden obj, false if not
|
|
25
|
+
def hides?(obj)
|
|
26
|
+
Recommendable.redis.sismember(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(obj.class, id), obj.id)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Unhide an object. This removes the object from a user's set of hidden items.
|
|
30
|
+
#
|
|
31
|
+
# @param [Object] obj the object to be made visible
|
|
32
|
+
# @return true if the object was successfully made visible, nil if the object wasn't already hidden
|
|
33
|
+
def unhide(obj)
|
|
34
|
+
return unless hides?(obj)
|
|
35
|
+
|
|
36
|
+
run_hook(:before_unhide, obj)
|
|
37
|
+
Recommendable.redis.srem(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(obj.class, id), obj.id)
|
|
38
|
+
run_hook(:after_unhide, obj)
|
|
39
|
+
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Retrieve an array of objects the user has hidden
|
|
44
|
+
#
|
|
45
|
+
# @return [Array] an array of records
|
|
46
|
+
def hiding
|
|
47
|
+
Recommendable.config.ratable_classes.map { |klass| hidden_for(klass) }.flatten
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Retrieve an array of objects both this user and another user have hidden
|
|
51
|
+
#
|
|
52
|
+
# @return [Array] an array of records
|
|
53
|
+
def hiding_in_common_with(user)
|
|
54
|
+
Recommendable.config.ratable_classes.map { |klass| hidden_in_common_with(klass, user) }.flatten
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Get the number of items the user has hidden
|
|
58
|
+
#
|
|
59
|
+
# @return [Fixnum] the number of hidden items
|
|
60
|
+
def hidden_count
|
|
61
|
+
Recommendable.config.ratable_classes.inject(0) do |sum, klass|
|
|
62
|
+
sum + hidden_count_for(klass)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# Fetch IDs for objects belonging to a passed class that the user has hidden
|
|
69
|
+
#
|
|
70
|
+
# @param [String, Symbol, Class] the class for which you want IDs
|
|
71
|
+
# @return [Array] an array of IDs
|
|
72
|
+
# @private
|
|
73
|
+
def hidden_ids_for(klass)
|
|
74
|
+
ids = Recommendable.redis.smembers(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, id))
|
|
75
|
+
ids.map!(&:to_i) if [:active_record, :data_mapper].include?(Recommendable.config.orm)
|
|
76
|
+
ids
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Fetch records belonging to a passed class that the user has hidden
|
|
80
|
+
#
|
|
81
|
+
# @param [String, Symbol, Class] the class for which you want hidden records
|
|
82
|
+
# @return [Array] an array of hidden records
|
|
83
|
+
# @private
|
|
84
|
+
def hidden_for(klass)
|
|
85
|
+
Recommendable.query(klass, hidden_ids_for(klass))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Get the number of items belonging to a passed class that the user has hidden
|
|
89
|
+
#
|
|
90
|
+
# @param [String, Symbol, Class] the class for which you want a count of hidden items
|
|
91
|
+
# @return [Fixnum] the number of hidden items
|
|
92
|
+
# @private
|
|
93
|
+
def hidden_count_for(klass)
|
|
94
|
+
Recommendable.redis.scard(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, id))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Get a list of records that both this user and a passed user have hidden
|
|
98
|
+
#
|
|
99
|
+
# @param [User] the other user
|
|
100
|
+
# @param [String, Symbol, Class] the class of common hidden items
|
|
101
|
+
# @return [Array] an array of records both users have hidden
|
|
102
|
+
# @private
|
|
103
|
+
def hidden_in_common_with(klass, user)
|
|
104
|
+
Recommendable.query(klass, hidden_ids_in_common_with(klass, user))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get a list of IDs for records that both this user and a passed user have
|
|
108
|
+
# hidden
|
|
109
|
+
#
|
|
110
|
+
# @param [User] the other user
|
|
111
|
+
# @param [String, Symbol, Class] the class of common hidden items
|
|
112
|
+
# @return [Array] an array of IDs for records that both users have hidden
|
|
113
|
+
# @private
|
|
114
|
+
def hidden_ids_in_common_with(klass, user_id)
|
|
115
|
+
user_id = user_id.id if user_id.is_a?(Recommendable.config.user_class)
|
|
116
|
+
Recommendable.redis.sinter(Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, id), Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, user_id))
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|