recommendable 1.1.3 → 1.1.4

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/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- recommendable (1.1.1)
4
+ recommendable (1.1.3)
5
5
  hooks
6
6
  rails (>= 3.0.0)
7
- redis (~> 2.2.0)
7
+ redis (>= 2.2.0)
8
8
 
9
9
  GEM
10
10
  remote: http://rubygems.org/
@@ -79,7 +79,7 @@ GEM
79
79
  rake (0.9.2.2)
80
80
  rdoc (3.12)
81
81
  json (~> 1.4)
82
- redis (2.2.2)
82
+ redis (3.0.1)
83
83
  shoulda (3.0.1)
84
84
  shoulda-context (~> 1.0.0)
85
85
  shoulda-matchers (~> 1.0.0)
@@ -2,7 +2,7 @@ module Recommendable
2
2
  if defined?(Sidekiq)
3
3
  class SidekiqWorker
4
4
  include ::Sidekiq::Worker
5
- sidekiq_options :queue => :recommendable
5
+ sidekiq_options :queue => :recommendable, :unique => true
6
6
 
7
7
  def perform(user_id)
8
8
  user = Recommendable.user_class.find(user_id)
@@ -11,3 +11,18 @@ require "redis"
11
11
  # Tell Redis which database to use (usually between 0 and 15). The default of 0
12
12
  # is most likely okay unless you have another application using that database.
13
13
  # Recommendable.redis.select "0"
14
+
15
+ # If using Sidekiq, uncomment the following or place it in config/initializers/sidekiq.rb:
16
+ # Sidekiq.configure_server do |config|
17
+ # require 'sidekiq/middleware/server/unique_jobs'
18
+ # config.server_middleware do |chain|
19
+ # chain.add Sidekiq::Middleware::Server::UniqueJobs
20
+ # end
21
+ # end
22
+ #
23
+ # Sidekiq.configure_client do |config|
24
+ # require 'sidekiq/middleware/client/unique_jobs'
25
+ # config.client_middleware do |chain|
26
+ # chain.add Sidekiq::Middleware::Client::UniqueJobs
27
+ # end
28
+ # end
data/lib/recommendable.rb CHANGED
@@ -6,6 +6,8 @@ require 'recommendable/exceptions'
6
6
  require 'recommendable/railtie' if defined?(Rails)
7
7
  require 'recommendable/version'
8
8
  require 'hooks'
9
+ require 'sidekiq/middleware/client/unique_jobs' if defined?(Sidekiq)
10
+ require 'sidekiq/middleware/server/unique_jobs' if defined?(Sidekiq)
9
11
 
10
12
  module Recommendable
11
13
  mattr_accessor :redis, :user_class
@@ -121,8 +121,20 @@ module Recommendable
121
121
  protected :redis_key
122
122
 
123
123
  module LikeableMethods
124
+ # Retrieve the number of likes this object has received. Cached in Redis.
125
+ # @return [Fixnum] the number of times this object has been liked
126
+ def like_count
127
+ Recommendable.redis.get("#{redis_key}:like_count").to_i
128
+ end
129
+
124
130
  private
125
131
 
132
+ # Updates the cache for how many times this object has been liked.
133
+ # @private
134
+ def update_like_count
135
+ Recommendable.redis.set "#{redis_key}:like_count", liked_by.count
136
+ end
137
+
126
138
  # Used for setup purposes. Creates a set in redis containing users that
127
139
  # have liked this object.
128
140
  # @private
@@ -135,8 +147,20 @@ module Recommendable
135
147
  end
136
148
 
137
149
  module DislikeableMethods
150
+ # Retrieve the number of dislikes this object has received. Cached in Redis.
151
+ # @return [Fixnum] the number of times this object has been disliked
152
+ def dislike_count
153
+ Recommendable.redis.get("#{redis_key}:dislike_count").to_i
154
+ end
155
+
138
156
  private
139
157
 
158
+ # Updates the cache for how many times this object has been disliked.
159
+ # @private
160
+ def update_dislike_count
161
+ Recommendable.redis.set "#{redis_key}:dislike_count", disliked_by.count
162
+ end
163
+
140
164
  # Used for setup purposes. Creates a set in redis containing users that
141
165
  # have disliked this object.
142
166
  # @private
@@ -52,7 +52,11 @@ module Recommendable
52
52
  end
53
53
 
54
54
  %w(like unlike dislike undislike).each do |action|
55
- send "after_#{action}", lambda { |obj| obj.send(:update_score) and Recommendable.enqueue(self.id) }
55
+ send "after_#{action}", lambda { |obj|
56
+ obj.send(:update_score)
57
+ obj.send "update_#{action.gsub('un', '')}_count"
58
+ Recommendable.enqueue(self.id)
59
+ }
56
60
  end
57
61
 
58
62
  before_stash { |obj| unignore(obj) and unpredict(obj) }
@@ -1,7 +1,7 @@
1
1
  module Recommendable
2
2
  MAJOR = 1
3
3
  MINOR = 1
4
- PATCH = 3
4
+ PATCH = 4
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join '.'
7
7
  end
@@ -0,0 +1,37 @@
1
+ require 'digest'
2
+
3
+ if defined?(Sidekiq)
4
+ module Sidekiq
5
+ module Middleware
6
+ module Client
7
+ class UniqueJobs
8
+ HASH_KEY_EXPIRATION = 30 * 60
9
+
10
+ def call(worker_class, item, queue)
11
+ enabled = worker_class.get_sidekiq_options['unique']
12
+ if enabled
13
+ payload_hash = Digest::MD5.hexdigest(Sidekiq.dump_json(item))
14
+ unique = false
15
+
16
+ Sidekiq.redis do |conn|
17
+ conn.watch(payload_hash)
18
+
19
+ if conn.get(payload_hash)
20
+ conn.unwatch
21
+ else
22
+ unique = conn.multi do
23
+ conn.setex(payload_hash, HASH_KEY_EXPIRATION, 1)
24
+ end
25
+ end
26
+ end
27
+ yield if unique
28
+ else
29
+ yield
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ if defined?(Sidekiq)
2
+ module Sidekiq
3
+ module Middleware
4
+ module Server
5
+ class UniqueJobs
6
+ def call(*args)
7
+ yield
8
+ ensure
9
+ json = Sidekiq.dump_json(args[1])
10
+ hash = Digest::MD5.hexdigest(json)
11
+ Sidekiq.redis {|conn| conn.del(hash) }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1 +1 @@
1
- require 'resque/tasks'
1
+ require 'resque/tasks' if defined?(Resque)
@@ -23,5 +23,19 @@ class DislikeSpec < MiniTest::Spec
23
23
  @user.dislike(movie).must_be_nil
24
24
  Recommendable::Dislike.count.must_equal 1
25
25
  end
26
+
27
+ it "should cache the number of dislikes" do
28
+ movie = Movie.create(:title => "Star Wars: Episode I - The Phantom Menace", :year => 1999)
29
+ @user2 = User.create(:username => "frank")
30
+
31
+ @user.dislike(movie)
32
+ movie.dislike_count.must_equal 1
33
+
34
+ @user2.dislike(movie)
35
+ movie.dislike_count.must_equal 2
36
+
37
+ @user.undislike(movie)
38
+ movie.dislike_count.must_equal 1
39
+ end
26
40
  end
27
41
  end
@@ -24,5 +24,19 @@ class LikeSpec < MiniTest::Spec
24
24
  @user.like(movie).must_be_nil
25
25
  Recommendable::Like.count.must_equal 1
26
26
  end
27
+
28
+ it "should cache the number of likes" do
29
+ movie = Movie.create(:title => "2001: A Space Odyssey", :year => 1968)
30
+ @user2 = User.create(:username => "frank")
31
+
32
+ @user.like(movie)
33
+ movie.like_count.must_equal 1
34
+
35
+ @user2.like(movie)
36
+ movie.like_count.must_equal 2
37
+
38
+ @user.unlike(movie)
39
+ movie.like_count.must_equal 1
40
+ end
27
41
  end
28
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recommendable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-20 00:00:00.000000000 Z
12
+ date: 2012-07-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sqlite3
@@ -195,6 +195,8 @@ files:
195
195
  - lib/recommendable/helpers.rb
196
196
  - lib/recommendable/railtie.rb
197
197
  - lib/recommendable/version.rb
198
+ - lib/sidekiq/middleware/client/unique_jobs.rb
199
+ - lib/sidekiq/middleware/server/unique_jobs.rb
198
200
  - lib/tasks/recommendable_tasks.rake
199
201
  - recommendable.gemspec
200
202
  - script/rails
@@ -276,7 +278,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
276
278
  version: '0'
277
279
  requirements: []
278
280
  rubyforge_project:
279
- rubygems_version: 1.8.22
281
+ rubygems_version: 1.8.23
280
282
  signing_key:
281
283
  specification_version: 3
282
284
  summary: Add like-based and/or dislike-based recommendations to your app.