13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
# File 'lib/recommendable/rater.rb', line 13
def recommends(*things)
Recommendable.configure do |config|
config.ratable_classes = []
config.user_class = self
end
things.each { |thing| thing.to_s.classify.constantize.make_recommendable! }
class_eval do
include Liker
include Disliker
include Hider
include Bookmarker
include Recommender
include Hooks
case
when defined?(Sequel::Model) && ancestors.include?(Sequel::Model)
def before_destroy
super
remove_from_recommendable!
end
when defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base),
defined?(Mongoid::Document) && ancestors.include?(Mongoid::Document),
defined?(MongoMapper::Document) && ancestors.include?(MongoMapper::Document),
defined?(MongoMapper::EmbeddedDocument) && ancestors.include?(MongoMapper::EmbeddedDocument)
before_destroy :remove_from_recommendable!
when defined?(DataMapper::Resource) && ancestors.include?(DataMapper::Resource)
before :destroy, :remove_from_recommendable!
else
warn "Model #{self} is not using a supported ORM. You must handle removal from Redis manually when destroying instances."
end
define_hooks :before_like, :after_like, :before_unlike, :after_unlike,
:before_dislike, :after_dislike, :before_undislike, :after_undislike,
:before_hide, :after_hide, :before_unhide, :after_unhide,
:before_bookmark, :after_bookmark, :before_unbookmark, :after_unbookmark
before_like lambda { |obj| undislike(obj) || unhide(obj) }
before_dislike lambda { |obj| unlike(obj) || unhide(obj) }
%w[like unlike dislike undislike].each do |action|
send("after_#{action}", lambda { |obj|
Recommendable::Helpers::Calculations.update_score_for(obj.class, obj.id)
Recommendable.enqueue(self.id) if Recommendable.config.auto_enqueue
})
end
%w[like dislike hide bookmark].each do |action|
send("after_#{action}", lambda { |obj| unrecommend(obj) })
end
def method_missing(method, *args, &block)
if method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_in_common_with\z/
begin
send("#{$1}_in_common_with", $2.classify.constantize, *args)
rescue NameError
super
end
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_count\z/
begin
send("#{$1}_count_for", $2.classify.constantize, *args)
rescue NameError
super
end
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_ids\z/
begin
send("#{$1}_ids_for", $2.classify.constantize, *args)
rescue NameError
super
end
elsif method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked|recommended)_(.+)\z/
begin
send("#{$1}_for", $2.classify.constantize, *args)
rescue NameError
super
end
else
super
end
end
def respond_to?(method, include_private = false)
if method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_in_common_with\z/ ||
method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked)_(.+)_ids\z/ ||
method.to_s =~ /\A((?:dis)?liked|hidden|bookmarked|recommended)_(.+)\z/
begin
true if $2.classify.constantize.recommendable?
rescue NameError
false
end
else
super
end
end
def rated?(obj)
likes?(obj) || dislikes?(obj)
end
def rated_anything?
likes_count > 0 || dislikes_count > 0
end
def unrate(obj)
unlike(obj) || undislike(obj) || unhide(obj)
unbookmark(obj)
end
end
end
|