activity_feed 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.markdown CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.0.0 (2013-07-12)
4
+
5
+ * Allow for bulk-loading of feed items. The `ActivityFeed.item_loader`
6
+ has been renamed to `ActivityFeed.items_loader`. The only difference
7
+ is that the proc is now passed an array of IDs, rather than an
8
+ individual ID.
9
+ * Updated `item_loader` references to `items_loader` throughout internal
10
+ documentation and README.
11
+ * Added `expire_feed_in` method alias for `expire_feed`.
12
+
3
13
  ## 2.3.0 (2013-05-03)
4
14
 
5
15
  * Added `check_item?(user_id, item_id, aggregate = ActivityFeed.aggregate)` to see if an item is in an activity feed.
data/README.markdown CHANGED
@@ -42,7 +42,9 @@ end
42
42
 
43
43
  ### Advanced configuration options
44
44
 
45
- * `item_loader`: ActivityFeed supports loading items from your ORM (e.g. ActiveRecord) or your ODM (e.g. Mongoid) when a page for a user's activity feed is requested. This option should be set to a Proc that will be called passing the item ID as its only argument.
45
+ * `items_loader`: ActivityFeed supports loading items from your ORM (e.g. ActiveRecord) or your ODM (e.g. Mongoid) when a page for a user's activity feed is requested. This option should be set to a Proc that will be called passing the item IDs as its only argument.
46
+
47
+ NOTE: The following examples developing an activity feed with Mongoid using Mongoid 3.x.
46
48
 
47
49
  For example:
48
50
 
@@ -68,15 +70,20 @@ module ActivityFeed
68
70
  field :icon, type: String
69
71
  field :sticky, type: Boolean
70
72
 
71
- index :user_id
73
+ index({ user_id: 1 }
72
74
 
73
75
  after_save :update_item_in_activity_feed
76
+ after_destroy :remove_item_from_activity_feed
74
77
 
75
78
  private
76
79
 
77
80
  def update_item_in_activity_feed
78
81
  ActivityFeed.update_item(self.user_id, self.id, self.updated_at.to_i)
79
82
  end
83
+
84
+ def remove_item_from_activity_feed
85
+ ActivityFeed.remove_item(self.user_id, self.id)
86
+ end
80
87
  end
81
88
  end
82
89
  end
@@ -85,7 +92,7 @@ end
85
92
  You would add the following option where you are configuring ActivityFeed as follows:
86
93
 
87
94
  ```ruby
88
- ActivityFeed.item_loader = Proc.new { |id| ActivityFeed::Mongoid::Item.find(id) }
95
+ ActivityFeed.items_loader = Proc.new { |ids| ActivityFeed::Mongoid::Item.where(:id.in => ids).order_by(updated_at: :desc).to_a }
89
96
  ```
90
97
 
91
98
  If you need to handle any exceptions when loading activity feed items, please do this in the Proc.
@@ -103,9 +110,7 @@ activity feed.
103
110
  # Configure Mongoid
104
111
  require 'mongoid'
105
112
 
106
- Mongoid.configure do |config|
107
- config.master = Mongo::Connection.new.db("activity_feed_gem_test")
108
- end
113
+ Mongoid.load!("/path/to/your/mongoid.yml", :production)
109
114
 
110
115
  # Create a class for activity feed items
111
116
  module ActivityFeed
@@ -125,7 +130,7 @@ module ActivityFeed
125
130
  field :icon, type: String
126
131
  field :sticky, type: Boolean
127
132
 
128
- index :user_id
133
+ index({ user_id: 1 }
129
134
 
130
135
  after_save :update_item_in_activity_feed
131
136
  after_destroy :remove_item_from_activity_feed
@@ -152,7 +157,7 @@ ActivityFeed.configure do |configuration|
152
157
  configuration.aggregate = false
153
158
  configuration.aggregate_key = 'aggregate'
154
159
  configuration.page_size = 25
155
- configuration.item_loader = Proc.new { |id| ActivityFeed::Mongoid::Item.find(id) }
160
+ configuration.items_loader = Proc.new { |ids| ActivityFeed::Mongoid::Item.where(:id.in => ids).order_by(updated_at: :desc).to_a }
156
161
  end
157
162
 
158
163
  # Create a couple of activity feed items
@@ -193,9 +198,7 @@ feed = ActivityFeed.feed('david', 1)
193
198
  # Configure Mongoid
194
199
  require 'mongoid'
195
200
 
196
- Mongoid.configure do |config|
197
- config.master = Mongo::Connection.new.db("activity_feed_gem_test")
198
- end
201
+ Mongoid.load!("/path/to/your/mongoid.yml", :production)
199
202
 
200
203
  # Create a class for activity feed items
201
204
  module ActivityFeed
@@ -234,7 +237,7 @@ ActivityFeed.configure do |configuration|
234
237
  configuration.aggregate = true
235
238
  configuration.aggregate_key = 'aggregate'
236
239
  configuration.page_size = 25
237
- configuration.item_loader = Proc.new { |id| ActivityFeed::Mongoid::Item.find(id) }
240
+ configuration.items_loader = Proc.new { |ids| ActivityFeed::Mongoid::Item.where(:id.in => ids).order_by(updated_at: :desc).to_a }
238
241
  end
239
242
 
240
243
  # Create activity feed items for a couple of users and aggregate the activity feed items from the second user in the first user's activity feed
@@ -300,6 +303,7 @@ ActivityFeed.total_items_in_feed(user_id, aggregate = ActivityFeed.aggregate)
300
303
  ActivityFeed.total_items(user_id, aggregate = ActivityFeed.aggregate)
301
304
  ActivityFeed.trim_feed(user_id, starting_timestamp, ending_timestamp, aggregate = ActivityFeed.aggregate)
302
305
  ActivityFeed.expire_feed(user_id, seconds, aggregate = ActivityFeed.aggregate)
306
+ ActivityFeed.expire_feed_in(user_id, seconds, aggregate = ActivityFeed.aggregate)
303
307
  ActivityFeed.expire_feed_at(user_id, timestamp, aggregate = ActivityFeed.aggregate)
304
308
  ActivityFeed.remove_feeds(user_id)
305
309
  ```
@@ -4,8 +4,10 @@ module ActivityFeed
4
4
  # Redis instance.
5
5
  attr_accessor :redis
6
6
 
7
- # Proc that will be called for loading an item from an ORM (e.g. ActiveRecord) or ODM (e.g. Mongoid). Proc will be called with the ID of the item from the feed.
8
- attr_accessor :item_loader
7
+ # Proc that will be called for loading items from an
8
+ # ORM (e.g. ActiveRecord) or ODM (e.g. Mongoid). Proc
9
+ # will be called with the IDs of the items from the feed.
10
+ attr_accessor :items_loader
9
11
 
10
12
  # ActivityFeed namespace for Redis.
11
13
  attr_writer :namespace
@@ -19,7 +21,8 @@ module ActivityFeed
19
21
  # Page size to be used when paging through the activity feed.
20
22
  attr_writer :page_size
21
23
 
22
- # Yield self to be able to configure ActivityFeed with block-style configuration.
24
+ # Yield self to be able to configure ActivityFeed with
25
+ # block-style configuration.
23
26
  #
24
27
  # Example:
25
28
  #
@@ -56,7 +59,7 @@ module ActivityFeed
56
59
  end
57
60
 
58
61
  # Default page size.
59
- #
62
+ #
60
63
  # @return the page size or the default of 25 if not set.
61
64
  def page_size
62
65
  @page_size ||= 25
@@ -1,7 +1,7 @@
1
1
  module ActivityFeed
2
2
  module Feed
3
3
  # Retrieve a page from the activity feed for a given +user_id+. You can configure
4
- # +ActivityFeed.item_loader+ with a Proc to retrieve an item from, for example,
4
+ # +ActivityFeed.items_loader+ with a Proc to retrieve items from, for example,
5
5
  # your ORM (e.g. ActiveRecord) or your ODM (e.g. Mongoid), and have the page
6
6
  # returned with loaded items rather than item IDs.
7
7
  #
@@ -12,22 +12,12 @@ module ActivityFeed
12
12
  # @return page from the activity feed for a given +user_id+.
13
13
  def feed(user_id, page, aggregate = ActivityFeed.aggregate)
14
14
  feederboard = ActivityFeed.feederboard_for(user_id, aggregate)
15
- feed = feederboard.leaders(page, :page_size => ActivityFeed.page_size).inject([]) do |feed_items, feed_item|
16
- item = if ActivityFeed.item_loader
17
- ActivityFeed.item_loader.call(feed_item[:member])
18
- else
19
- feed_item[:member]
20
- end
21
-
22
- feed_items << item unless item.nil?
23
- feed_items
24
- end
25
-
26
- feed.nil? ? [] : feed
15
+ feed_items = feederboard.leaders(page, :page_size => ActivityFeed.page_size)
16
+ load_feed_items(feed_items)
27
17
  end
28
18
 
29
19
  # Retrieve the entire activity feed for a given +user_id+. You can configure
30
- # +ActivityFeed.item_loader+ with a Proc to retrieve an item from, for example,
20
+ # +ActivityFeed.items_loader+ with a Proc to retrieve items from, for example,
31
21
  # your ORM (e.g. ActiveRecord) or your ODM (e.g. Mongoid), and have the page
32
22
  # returned with loaded items rather than item IDs.
33
23
  #
@@ -37,23 +27,13 @@ module ActivityFeed
37
27
  # @return the full activity feed for a given +user_id+.
38
28
  def full_feed(user_id, aggregate = ActivityFeed.aggregate)
39
29
  feederboard = ActivityFeed.feederboard_for(user_id, aggregate)
40
- feed = feederboard.leaders(1, :page_size => feederboard.total_members).inject([]) do |feed_items, feed_item|
41
- item = if ActivityFeed.item_loader
42
- ActivityFeed.item_loader.call(feed_item[:member])
43
- else
44
- feed_item[:member]
45
- end
46
-
47
- feed_items << item unless item.nil?
48
- feed_items
49
- end
50
-
51
- feed.nil? ? [] : feed
30
+ feed_items = feederboard.leaders(1, :page_size => feederboard.total_members)
31
+ load_feed_items(feed_items)
52
32
  end
53
33
 
54
34
  # Retrieve a page from the activity feed for a given +user_id+ between a
55
35
  # +starting_timestamp+ and an +ending_timestamp+. You can configure
56
- # +ActivityFeed.item_loader+ with a Proc to retrieve an item from, for example,
36
+ # +ActivityFeed.items_loader+ with a Proc to retrieve items from, for example,
57
37
  # your ORM (e.g. ActiveRecord) or your ODM (e.g. Mongoid), and have the feed data
58
38
  # returned with loaded items rather than item IDs.
59
39
  #
@@ -65,18 +45,8 @@ module ActivityFeed
65
45
  # @return feed items from the activity feed for a given +user_id+ between the +starting_timestamp+ and +ending_timestamp+.
66
46
  def feed_between_timestamps(user_id, starting_timestamp, ending_timestamp, aggregate = ActivityFeed.aggregate)
67
47
  feederboard = ActivityFeed.feederboard_for(user_id, aggregate)
68
- feed = feederboard.members_from_score_range(starting_timestamp, ending_timestamp).inject([]) do |feed_items, feed_item|
69
- item = if ActivityFeed.item_loader
70
- ActivityFeed.item_loader.call(feed_item[:member])
71
- else
72
- feed_item[:member]
73
- end
74
-
75
- feed_items << item unless item.nil?
76
- feed_items
77
- end
78
-
79
- feed.nil? ? [] : feed
48
+ feed_items = feederboard.members_from_score_range(starting_timestamp, ending_timestamp)
49
+ load_feed_items(feed_items)
80
50
  end
81
51
 
82
52
  # Return the total number of pages in the activity feed.
@@ -133,6 +103,8 @@ module ActivityFeed
133
103
  ActivityFeed.redis.expire(ActivityFeed.feed_key(user_id, aggregate), seconds)
134
104
  end
135
105
 
106
+ alias_method :expire_feed_in, :expire_feed
107
+
136
108
  # Expire an activity feed at a given timestamp.
137
109
  #
138
110
  # @param user_id [String] User ID.
@@ -141,5 +113,22 @@ module ActivityFeed
141
113
  def expire_feed_at(user_id, timestamp, aggregate = ActivityFeed.aggregate)
142
114
  ActivityFeed.redis.expireat(ActivityFeed.feed_key(user_id, aggregate), timestamp)
143
115
  end
116
+
117
+ private
118
+
119
+ # Load feed items from the `ActivityFeed.items_loader` if available,
120
+ # otherwise return the individual members from the feed items.
121
+ #
122
+ # @param feed_items [Array] Array of hash feed items as `[{:member=>"5", :rank=>1, :score=>1373564960.0}, ...]`
123
+ #
124
+ # @return Array of feed items
125
+ def load_feed_items(feed_items)
126
+ feed_item_ids = feed_items.collect { |feed_item| feed_item[:member] }
127
+ if ActivityFeed.items_loader
128
+ ActivityFeed.items_loader.call(feed_item_ids)
129
+ else
130
+ feed_item_ids
131
+ end
132
+ end
144
133
  end
145
134
  end
@@ -1,3 +1,3 @@
1
1
  module ActivityFeed
2
- VERSION = "2.3.0"
2
+ VERSION = '3.0.0'
3
3
  end
@@ -205,8 +205,8 @@ describe ActivityFeed::Feed do
205
205
  describe 'ORM or ODM loading' do
206
206
  describe 'ActiveRecord' do
207
207
  it 'should be able to load an item via ActiveRecord when requesting a feed' do
208
- ActivityFeed.item_loader = Proc.new do |id|
209
- ActivityFeed::ActiveRecord::Item.find(id)
208
+ ActivityFeed.items_loader = Proc.new do |ids|
209
+ ActivityFeed::ActiveRecord::Item.find(ids)
210
210
  end
211
211
 
212
212
  feed = ActivityFeed.feed('david', 1)
@@ -228,7 +228,9 @@ describe ActivityFeed::Feed do
228
228
 
229
229
  describe 'Mongoid' do
230
230
  it 'should be able to load an item via Mongoid when requesting a feed' do
231
- ActivityFeed.item_loader = Proc.new { |id| ActivityFeed::Mongoid::Item.find(id) }
231
+ ActivityFeed.items_loader = Proc.new do |ids|
232
+ ActivityFeed::Mongoid::Item.find(ids)
233
+ end
232
234
 
233
235
  feed = ActivityFeed.feed('david', 1)
234
236
  feed.length.should eql(0)
@@ -249,8 +251,8 @@ describe ActivityFeed::Feed do
249
251
  end
250
252
  end
251
253
 
252
- describe '#expire_feed' do
253
- it 'should set an expiration on an activity feed' do
254
+ describe '#expire_feed and #expire_feed_in' do
255
+ it 'should set an expiration on an activity feed using #expire_feed' do
254
256
  add_items_to_feed('david', Leaderboard::DEFAULT_PAGE_SIZE)
255
257
 
256
258
  ActivityFeed.expire_feed('david', 10)
@@ -259,6 +261,16 @@ describe ActivityFeed::Feed do
259
261
  ttl.should be <= 10
260
262
  end
261
263
  end
264
+
265
+ it 'should set an expiration on an activity feed using #expire_feed_in' do
266
+ add_items_to_feed('david', Leaderboard::DEFAULT_PAGE_SIZE)
267
+
268
+ ActivityFeed.expire_feed_in('david', 10)
269
+ ActivityFeed.redis.ttl(ActivityFeed.feed_key('david')).tap do |ttl|
270
+ ttl.should be > 1
271
+ ttl.should be <= 10
272
+ end
273
+ end
262
274
  end
263
275
 
264
276
  describe '#expire_feed_at' do
data/spec/spec_helper.rb CHANGED
@@ -17,7 +17,7 @@ RSpec.configure do |config|
17
17
  DatabaseCleaner.clean
18
18
 
19
19
  ActivityFeed.configure do |configuration|
20
- configuration.item_loader = nil
20
+ configuration.items_loader = nil
21
21
  configuration.aggregate = false
22
22
  configuration.redis = Redis.new(:db => 15)
23
23
  end
data/spec/version_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'ActivityFeed::VERSION' do
4
- it "should be the correct version" do
5
- ActivityFeed::VERSION.should == '2.3.0'
4
+ it 'should be the correct version' do
5
+ ActivityFeed::VERSION.should == '3.0.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activity_feed
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0
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: 2013-05-03 00:00:00.000000000 Z
12
+ date: 2013-07-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -216,7 +216,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
216
216
  version: '0'
217
217
  segments:
218
218
  - 0
219
- hash: 4479539862674226365
219
+ hash: 3361752817333604694
220
220
  required_rubygems_version: !ruby/object:Gem::Requirement
221
221
  none: false
222
222
  requirements:
@@ -225,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
225
  version: '0'
226
226
  segments:
227
227
  - 0
228
- hash: 4479539862674226365
228
+ hash: 3361752817333604694
229
229
  requirements: []
230
230
  rubyforge_project: activity_feed
231
231
  rubygems_version: 1.8.25