simple-feed 2.1.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of simple-feed might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d5d6262c071651937d3f12fee27461af0cd5ecbb037046e290225ae9d108e83
4
- data.tar.gz: cbae3163cc06bdb4c1e3b2de129c3c7b6a6a489d4d0f74142d329fbed88efd26
3
+ metadata.gz: 57cc396d4f1f0874ef1af3004236cd679bc7130ebcf3635c5c4fe083830e1524
4
+ data.tar.gz: 03c951557b3bf046e4f10265d6bdee091d71d696a70c4c62ce6222ff5a1bedfe
5
5
  SHA512:
6
- metadata.gz: aca24056e250a7dc32111ae81f04f7d7bc8859ae4f1f9cfbffb1d1fd7982ebe493e6761e9acb3415a5da7fdae259dad3a22e08dfbfffe388bd9bec3989c41b75
7
- data.tar.gz: '08a870bfddb1db99baa1eeea4281b0af5645e5f74731352c46e29e32dcf807983427439a6847d56c1b789f8723606e28f6a92d37e1760fd6e2cb3beb1eced066'
6
+ metadata.gz: 7b0647a8834a77c2a4f41308ba027d0d6c8ebd5dc9da920ac12ba49ed5c77e7f9592e5874e2b6c5235943e3b007f1af6ad160942f3e97f0697f608211324110f
7
+ data.tar.gz: 3e521906bdff013234e00cf03a7c1e91975c75276f4cf7a279d5ab7abde9cc92741763ed73065e7caf77f71233361654a8ae5f7f4fcca1509ed2db2b06efcdc4
data/.envrc ADDED
@@ -0,0 +1 @@
1
+ export RUBYOPT="-W0"
@@ -31,5 +31,6 @@ jobs:
31
31
  bundle install --jobs 4 --retry 3
32
32
  bundle exec rspec --format documentation
33
33
  env:
34
+ CODECOV_TOKEN: "8314c388-54a3-4125-915b-3d4836c15b29"
34
35
  REDIS_HOST: redis
35
36
  REDIS_PORT: ${{ job.services.redis.ports[6379] }}
data/.gitignore CHANGED
@@ -14,4 +14,4 @@
14
14
  ._*
15
15
  .Spotlight-V100
16
16
  .Trashes
17
- /lib/simplefeed/providers/serialization/key.rb
17
+ .rakeTasks
@@ -1,21 +1,11 @@
1
+ language: ruby
1
2
  cache: bundler
2
3
  rvm:
3
4
  - 2.3.8
4
5
  - 2.4.10
5
6
  - 2.5.3
6
- - 2.6.2
7
+ - 2.6.6
7
8
  - 2.7.1
8
9
  services:
9
10
  - redis-server
10
- before_script:
11
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
12
- - chmod +x ./cc-test-reporter
13
- - ./cc-test-reporter before-build
14
- script: bundle exec rspec --format=documentation
15
- after_script:
16
- - bash <(curl -s https://codecov.io/bash)
17
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
18
- env:
19
- global:
20
- CODECOV_TOKEN="2085c087-f833-49c7-a105-703bce882653"
21
- secure: cdUlrz0XNCu0HB5lNLYZBF6yaukIkDZRlVsAbeeaNhPKCVj7MOvuGEUZ9TzQP0yXRaGXHy3xXem0MdDbnli5WYvHxj2MTrRVEDBiRm4jaZFHe3Rewr2mWmLqK1c4g9gvOTgjPNPTesdft87+wQuPedQLpfMGuedA86tkKzA2Tkc4J69DI93C02h6H89iiQFHL9ISNk5DzZh3FJo+fyi0JQlD6CAzWrVplCqf088qGdAk3Hy77Q2GKkVEdOb/P0cdmDLnFjekdh4b0TPI/uaqgu4cZeoebWQgg61K/enGLqxY2Lp0f4DsXQev+06d14KxIJMYHLuDgvlVwYMDInxQU7kXgTRgAnaxRdm0S7NbP89uBVkfIQiNGan7Qkvw2ayGhYCcu7Vgvjo6C2btZWLpxT0XvpQGfpvHrRrPnzFbFLLtG4rhJd3iiTbSa5LPDEi4Qx9uwGNy4iR6IB69R6dPwAR8P45XZE4JnJVUvrM/X9v9Yv2hAxnuCb48whalIozGqpwavLdYrgCf2pQecls74uw4mCxvDAg0EoskrDYuk4DYeZ507ajor4zX1avLUVfYk/0igpp6KeLENY5ozl1zsEvRcOldfdV8R9tKEGxliIgffe67Hc5/ZP+C/53lcK0nIxXYrB1I7Q+CVlEDNutNQNZRDfrNBYJVe/+RvmmdD+w=
11
+ script: bundle exec rspec
@@ -0,0 +1,93 @@
1
+ # Changelog
2
+
3
+ ## [v3.0.0](https://github.com/kigster/simple-feed/tree/v3.0.0) (2020-05-25)
4
+
5
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v2.1.0...v3.0.0)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - First pass on meta/data refactor to allow different publisher/consumer [\#18](https://github.com/kigster/simple-feed/pull/18) ([kigster](https://github.com/kigster))
10
+ - \(v2.1.0\) Support for non-integer user\_ids [\#17](https://github.com/kigster/simple-feed/pull/17) ([kigster](https://github.com/kigster))
11
+
12
+ ## [v2.1.0](https://github.com/kigster/simple-feed/tree/v2.1.0) (2020-05-24)
13
+
14
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v2.0.2...v2.1.0)
15
+
16
+ **Closed issues:**
17
+
18
+ - Support string or UUID user\_id across the board [\#16](https://github.com/kigster/simple-feed/issues/16)
19
+ - Document overwriting logic, provide override? [\#13](https://github.com/kigster/simple-feed/issues/13)
20
+ - How exactly is data structured and stored into keys? [\#12](https://github.com/kigster/simple-feed/issues/12)
21
+ - Base62 encoding for @user\_id is problematic for namespacing [\#11](https://github.com/kigster/simple-feed/issues/11)
22
+ - Caching conventions? [\#10](https://github.com/kigster/simple-feed/issues/10)
23
+ - Optional secondary index? [\#9](https://github.com/kigster/simple-feed/issues/9)
24
+ - Group feeds? [\#8](https://github.com/kigster/simple-feed/issues/8)
25
+
26
+ **Merged pull requests:**
27
+
28
+ - Not sure how this is working for everyone else? [\#15](https://github.com/kigster/simple-feed/pull/15) ([rromanchuk](https://github.com/rromanchuk))
29
+ - Adding Codecov [\#14](https://github.com/kigster/simple-feed/pull/14) ([kigster](https://github.com/kigster))
30
+
31
+ ## [v2.0.2](https://github.com/kigster/simple-feed/tree/v2.0.2) (2017-12-07)
32
+
33
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v2.0.1...v2.0.2)
34
+
35
+ **Closed issues:**
36
+
37
+ - Permissions on all .rb file are not correct [\#7](https://github.com/kigster/simple-feed/issues/7)
38
+ - Can I add a connector to use Elasticsearch? [\#6](https://github.com/kigster/simple-feed/issues/6)
39
+ - Multi-feeds aggregation ? [\#4](https://github.com/kigster/simple-feed/issues/4)
40
+ - Explain when feed items are removed/expire from the feed [\#3](https://github.com/kigster/simple-feed/issues/3)
41
+ - how I can periodic export data from Redis to DB \(Postgres, MySQL, etc\) ? [\#2](https://github.com/kigster/simple-feed/issues/2)
42
+
43
+ **Merged pull requests:**
44
+
45
+ - Silence Hashie warnings [\#5](https://github.com/kigster/simple-feed/pull/5) ([wa0x6e](https://github.com/wa0x6e))
46
+
47
+ ## [v2.0.1](https://github.com/kigster/simple-feed/tree/v2.0.1) (2016-12-29)
48
+
49
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v1.0.4...v2.0.1)
50
+
51
+ ## [v1.0.4](https://github.com/kigster/simple-feed/tree/v1.0.4) (2016-12-13)
52
+
53
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v1.0.3...v1.0.4)
54
+
55
+ ## [v1.0.3](https://github.com/kigster/simple-feed/tree/v1.0.3) (2016-12-13)
56
+
57
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v1.0.2...v1.0.3)
58
+
59
+ ## [v1.0.2](https://github.com/kigster/simple-feed/tree/v1.0.2) (2016-12-08)
60
+
61
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v1.0.1...v1.0.2)
62
+
63
+ ## [v1.0.1](https://github.com/kigster/simple-feed/tree/v1.0.1) (2016-12-08)
64
+
65
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v1.0.0...v1.0.1)
66
+
67
+ ## [v1.0.0](https://github.com/kigster/simple-feed/tree/v1.0.0) (2016-12-02)
68
+
69
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v0.5.1...v1.0.0)
70
+
71
+ ## [v0.5.1](https://github.com/kigster/simple-feed/tree/v0.5.1) (2016-12-01)
72
+
73
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v0.5.0...v0.5.1)
74
+
75
+ ## [v0.5.0](https://github.com/kigster/simple-feed/tree/v0.5.0) (2016-11-30)
76
+
77
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v0.4.1...v0.5.0)
78
+
79
+ **Merged pull requests:**
80
+
81
+ - Redis provider implementation \[DO NOT MERGE\] [\#1](https://github.com/kigster/simple-feed/pull/1) ([kigster](https://github.com/kigster))
82
+
83
+ ## [v0.4.1](https://github.com/kigster/simple-feed/tree/v0.4.1) (2016-11-22)
84
+
85
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/v0.4.0...v0.4.1)
86
+
87
+ ## [v0.4.0](https://github.com/kigster/simple-feed/tree/v0.4.0) (2016-11-22)
88
+
89
+ [Full Changelog](https://github.com/kigster/simple-feed/compare/1255221c85540264be91293f2927ddf5a9754dd1...v0.4.0)
90
+
91
+
92
+
93
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
@@ -6,64 +6,107 @@
6
6
 
7
7
  == Scalable, Easy to Use Activity Feed Implementation.
8
8
 
9
+ === Build & Gem Status
10
+
9
11
  image:https://img.shields.io/gem/v/simple-feed.svg[Gem Version,link=https://rubygems.org/gems/simple-feed]
10
12
  image:https://img.shields.io/badge/license-MIT-blue.svg[MIT licensed,link=https://github.com/kigster/simple-feed/master/LICENSE.txt]
13
+ image:http://inch-ci.org/github/kigster/simple-feed.svg?branch=master[Inline docs,link=http://inch-ci.org/github/kigster/simple-feed]
11
14
 
15
+ image:https://travis-ci.org/kigster/simple-feed.svg?branch=master[Build Status,link=https://travis-ci.org/kigster/simple-feed]
12
16
  image:https://github.com/kigster/simple-feed/workflows/Ruby/badge.svg?branch=master[Ruby,link=https://github.com/kigster/simple-feed/actions?query=workflow%3ARuby]
13
17
  image:https://github.com/kigster/simple-feed/workflows/Rubocop/badge.svg?branch=master[Ruby,link=https://github.com/kigster/simple-feed/actions?query=workflow%3ARubocop]
14
18
 
15
- image:https://travis-ci.org/kigster/simple-feed.svg?branch=master[Build Status,link=https://travis-ci.org/kigster/simple-feed]
19
+ image:https://codecov.io/gh/kigster/simple-feed/branch/master/graph/badge.svg[Coverage,link=https://codecov.io/gh/kigster/simple-feed]
16
20
  image:https://api.codeclimate.com/v1/badges/a11061820895fcde635e/maintainability[Maintainability,link=https://codeclimate.com/github/kigster/simple-feed/maintainability]
17
21
  image:https://api.codeclimate.com/v1/badges/a11061820895fcde635e/test_coverage[Test Coverage,link=https://codeclimate.com/github/kigster/simple-feed/test_coverage]
18
22
 
19
- image:http://inch-ci.org/github/kigster/simple-feed.svg?branch=master[Inline docs,link=http://inch-ci.org/github/kigster/simple-feed]
20
- image:https://img.shields.io/gitter/room/gitterHQ/gitter.svg[Talk on Gitter,link=https://gitter.im/kigster/simple-feed]
23
+ === Test Coverage Map
24
+
25
+ image:https://codecov.io/gh/kigster/simple-feed/branch/master/graphs/sunburst.svg[Coverage Map,link=https://codecov.io/gh/kigster/simple-feed/branch/master]
21
26
 
22
27
  IMPORTANT: Please read the (somewhat outdated) blog post http://kig.re/2017/02/19/feeding-frenzy-with-simple-feed-activity-feed-ruby-gem.html[Feeding Frenzy with SimpleFeed] launching this library. Please leave comments or questions in the discussion thread at the bottom of that post. Thanks!
23
28
 
24
29
  If you like to see this project grow, your donation of any amount is much appreciated.
25
30
 
26
31
  image::https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif[Donate,link=https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FSFYYNEQ8RKWU]
27
- '''
28
32
 
29
33
  This is a fast, pure-ruby implementation of an activity feed concept commonly used in social networking applications. The implementation is optimized for *read-time performance* and high concurrency (lots of users), and can be extended with custom backend providers. Two providers come bundled: the production-ready Redis provider, and a naive Ruby Hash-based provider.
30
34
 
31
35
  *Important Notes and Acknowledgements:*
32
36
 
33
37
  * SimpleFeed _does not depend on Ruby on Rails_ and is a *pure-ruby* implementation
34
- * SimpleFeed requires ruby 2.3 or later
38
+ * SimpleFeed requires ruby 2.4 or later
35
39
  * SimpleFeed is currently live in production
36
40
  * SimpleFeed is open source thanks to the generosity of *http://simbi.com[Simbi, Inc]*.
37
41
 
38
42
  == Features
39
43
 
40
- SimpleFeed offers the following features:
44
+ SimpleFeed is a Ruby Library that can be plugged into any application to power a fast, Redis-based activity feed implementation so common on social networking sites. SimpleFeed offers the following features:
41
45
 
42
- * Highly performant Redis-based activity feed
46
+ * Scalable and well performing Redis-based activity feed
43
47
 
44
- * Scales to millions of users (may need to use Twemproxy to shard across several Redis instances)
48
+ * Scales to millions of users (will need to use Twemproxy to shard across several Redis instances)
45
49
 
46
- * Stores a fixed number of events per unique activity ID (eg, a user) — the default is 2000. When the full list is used, the oldest events are bumped off the feed (and are effectively trashed).
50
+ * Stores a fixed number of events for each unique "user" — the default is 1000. When the feed reaches 1001 events, the oldest event is offloaded from the activity.
47
51
 
48
- * Store user_id as either a string or an integer (the latter is base62 encoded when serialized, so very large users_ids are OK)
52
+ * Thread-safe implementation.
49
53
 
50
- * Updating feeds of N users is roughly a O(N * log(N)) operation
54
+ * Zero assumptions about what you are storing: the "data" is just a string. Serialize it with JSON, Marshall, YAML, or whatever.
51
55
 
52
- * Reading feed for one user (or one type of user) is a O(1) operation
56
+ * You can create as many different types of feeds per application as you like. No Singletons are used.
53
57
 
54
- * For each activity (user) read the number of total and new items in the feed, computed since the user last saw their feed.
58
+ * Customize mapping from `user_id` to the activity id based on your business logic (more on this later).
55
59
 
56
- * Delete items from user's feed selectively (for instance, if a user unfollows someone they shouldn't see their events anymore).
60
+ === Publishing Events
57
61
 
58
- * Automatically reset the timestamp when the user last read their feed when reading from the feed (or not, it's an argument). As soon as the user reads their feed (you call the `paginate` method), the "unread counter" is reset to 0.
62
+ Pushing events to the feed requires the following:
59
63
 
60
- * You can create as many different types of feeds per application as you like. No Singletons are used.
64
+ * An `Event` consisting of:
65
+ ** String `data` that, most commonly, is a foreign key to a database table, but can really be anything you like.
66
+ ** Float `at` (typically, the timestamp, but can be any `float` number)
67
+ * One or more user IDs, or event consumers: basically — who should see the event being published in their feed.
61
68
 
62
- * Thread-safe implementation.
69
+ You publish an event by choosing a set of users whose feed should be updated. For example, were you re-implementing Twitter, your array of `user_ids` when publishing an event would be all followers of the Tweet's author. While the `data` would probably be the Tweet ID.
63
70
 
64
- * Zero assumptions about what you are storing: the "data" is just a string. Serialize it with JSON, Marshall, YAML, or whatever.
65
71
 
66
- == Background, Examples, Serialization, etc
72
+ NOTE: Publishing an event to the feeds of N users is roughly a O(N * log(N)) operation
73
+
74
+ === Consuming Events (Reading / Rendering the Feed)
75
+
76
+ You can fetch the chronologically ordered events for a particular user, using:
77
+
78
+ * Methods on the `activity` such as `paginate`, `fetch`.
79
+
80
+ ** Reading feed for one user (or one type of user) is a `O(1)` operation
81
+
82
+ * For each activity (user) you can fetch the `total_count` and the `unread_count` — the number of total and new items in the feed, where `unread_count` is computed since the user last reset their `read status`.
83
+
84
+ ** Note: `total_count` can never exceed the maximum size of the feed that you configured. The default is 1000 items.
85
+
86
+ ** The `last_read` timestamp can be automatically reset when the user is shown the feed via `paginate` method (whether or not its reset is controlled via a method argument).
87
+
88
+ === Modifying User's Feed
89
+
90
+ For any given user, you can:
91
+
92
+ * Wipe their feed with `wipe`
93
+
94
+ * Selectively remove items from the feed with `delete_if`.
95
+ ** For instance, if a user un-follows someone they shouldn't see their events anymore, so you'd have to call `delete_if` and remove any events published by the unfollowed user.
96
+
97
+ === Aggregating Events
98
+
99
+ This is a feature planned for future versions.
100
+
101
+ Help us much appreciated, even if you are not a developer, but have a clear idea about how it should work.
102
+
103
+ == Commercial & Enterprise Support
104
+
105
+ Commercial Support plans are available for SimpleFeed through author's https://reinvent.one[ReinventONE Inc] consulting company. Please reach out to kig AT reinvent.one for more information.
106
+
107
+ == Usage
108
+
109
+ === Example
67
110
 
68
111
  Please read the additional documentation, including the examples, on the https://github.com/kigster/simple-feed/wiki[project's Github Wiki].
69
112
 
@@ -71,7 +114,7 @@ Below is a screen shot of an actual activity feed powered by this library.
71
114
 
72
115
  image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/activity-feed-action.png[usage]
73
116
 
74
- == Usage
117
+ === Providers
75
118
 
76
119
  A key concept to understanding SimpleFeed gem, is that of a _provider_, which is effectively a persistence implementation for the events belonging to each user.
77
120
 
@@ -108,55 +151,130 @@ After the feed is defined, the gem creates a similarly named method under the `S
108
151
 
109
152
  You can also get a full list of currently defined feeds with `SimpleFeed.feed_names` method.
110
153
 
154
+ === Reading from and writing to the feed
155
+
156
+ For the impatient, here is a quick way to get started with the `SimpleFeed`.
157
+
158
+ [source,ruby]
159
+ ----
160
+ # Let's use the feed we defined earlier and create activity for all followers of the current user
161
+ publish_activity = SimpleFeed.newsfeed.activity(@current_user.followers.map(&:id))
162
+
163
+ # Store directly the value and the optional time stamp
164
+ publish_activity.store(value: 'hello', at: Time.now)
165
+ # => true # indicates that value 'hello' was not yet in the feed (all events must be unique)
166
+
167
+ # Or, using the event form:
168
+ publish_activity.store(event: SimpleFeed::Event.new('good bye', Time.now))
169
+ # => true
170
+ ----
171
+
172
+ As we've added the two events for these users, we can now read them back, sorted by
173
+ the time and paginated:
174
+
175
+ [source,ruby]
176
+ ----
177
+ # Let's grab the first follower
178
+ user_activity = SimpleFeed.newsfeed.activity(@current_user.followers.first.id)
179
+
180
+ # Now we can paginate the events, while resetting this user's last-read timestamp:
181
+ user_activity.paginate(page: 1, reset_last_read: true)
182
+ # [
183
+ # [0] #<SimpleFeed::Event: value=hello, at=1480475294.0579991>,
184
+ # [1] #<SimpleFeed::Event: value=good bye, at=1480472342.8979871>,
185
+ # ]
186
+ ----
187
+
188
+ IMPORTANT: Note that we stored the activity by passing an array of users, but read the activity for just one user. This is how you'd use SimpleFeed most of the time, with the exception of the alternative mapping described below.
189
+
111
190
  === User IDs
112
191
 
113
- In the following section you will see the examples of reading and writing activity for users based on their ID.
192
+ In the previous section you saw the examples of publishing events to many feeds, and then reading the activity for a given user.
193
+
194
+ SimpleFeed supports user IDs that are either numeric (integer) or string-based (eg, UUID). Numeric IDs are best for simplest cases, and are the most compact. String keys offer the most flexibility.
195
+
196
+ ==== Activity Keys
114
197
 
115
- SimpleFeed supports user IDs that are either numeric (integer) or string-based (eg, UUID).
198
+ In the next section we'll talk about generating `keys` from user_ids. We mean — Redis Hash keys that uniquely map a user (or a set of users) to the activity feed they should see.
116
199
 
117
- If your User IDs are numeric, they generate redis keys using Base62 encoding (which makes them shorter, and more compact).
200
+ There are up to two keys that are computed depending on the situation:
118
201
 
119
- For string User IDs, the only transformation performed is the basic link:https://en.wikipedia.org/wiki/ROT13[`rot13`] in case user ids are semi-sensitive.
202
+ * `data_key` is used to store the actual feed events
203
+ * `meta_key` is used to store user's `last_read` status
120
204
 
121
205
  ==== Partitioning Schema
122
206
 
123
- You can take advantage of string user IDs for situations where your feed requires a composite keys for instance. Just remember that SimpleFeed does not care about what's in your user ID, and even what you call "a user". It's convenient to think of the activities in terms of users, because typically each user has a unique feed that only they see.
207
+ NOTE: This feature is only available in **SimpleFeed Version 3+**.
208
+
209
+ You can take advantage of string user IDs for situations where your feed requires keys to be composite for instance. Just remember that SimpleFeed does not care about what's in your user ID, and even what you call "a user". It's convenient to think of the activities in terms of users, because typically each user has a unique feed that only they see.
124
210
 
125
211
  But you can just as easily use zip code as the unique activity ID, and create one feed of events per geographical location, that all folks living in that zip code share. But what about other countries?
126
212
 
127
- Now you use partioning scheme: make "user_id" a combination `iso_country_code.postal_code`, eg for San Francisco, you'd use `us.94107`, but for Australia you could use, eg `au.3148`.
213
+ Now you use partitioning scheme: make the "user_id" argument a combination `iso_country_code.postal_code`, eg for San Francisco, you'd use `us.94107`, but for Australia you could use, eg `au.3148`.
128
214
 
129
- === Reading from and writing to the feed
215
+ ==== Relationship between an Activity and a User
130
216
 
131
- For the impatient, here is a quick way to get started with the `SimpleFeed`.
217
+ ===== One to One
218
+
219
+ In the most common case, you will have one activity per user.
220
+
221
+ For instance, in the Twitter example, each Twitter user has a unique tweeter feed that only they see.
222
+
223
+ The events are published when someone posts a tweet, to the array of all users that follow the Tweet author.
224
+
225
+ ===== One to Many
226
+
227
+ However, SimpleFeed supports one additional use-case, where you might have one activity shared among many users.
228
+
229
+ Imagine a service that notifies residents of important announcements based on user's zip code of residence.
230
+
231
+ We want this feed to work as follows:
232
+
233
+ * All users that share a zip-code should see the same exact feed.
234
+ * However, all users should never share the individual's `last_read` status: so if two people read the same activity from the same zip code, their `unread_count` should change independently.
235
+
236
+ In terms of the activity keys, this means:
237
+
238
+ * `data_key` should be based on the zip-code of each user, and be one to many with users.
239
+ * `meta_key` should be based on the user ID as we want it to be 1-1 with users.
240
+
241
+ To support this use-case, SimpleFeed supports two optional transformer lambdas that can be applied to each user object when computing their activity feed hash key:
132
242
 
133
243
  [source,ruby]
134
244
  ----
135
- # This assumes we have previously defined a feed named :newsfeed (see above)
136
- activity = SimpleFeed.newsfeed.activity(@current_user.id)
137
- # Store directly the value and the optional time stamp
138
- activity.store(value: 'hello')
139
- # => true
140
-
141
- # or equivalent:
142
- @event = SimpleFeed::Event.new('hello', Time.now)
143
- activity.store(event: @event)
144
- # => false # false indicates that the same event is already in the feed.
245
+ SimpleFeed.define(:zipcode_alerts) do |f|
246
+ f.provider = SimpleFeed.provider(:redis, redis: -> { ::Redis.new }, pool_size: 10)
247
+ f.namespace = 'zc'
248
+ f.data_key_transformer = ->(user) { user.zip_code } # actual feed data is stored once per zip code
249
+ f.meta_key_transformer = ->(user) { user.id } # last_read status is stored once per user
250
+ end
145
251
  ----
146
252
 
147
- As we've added events for this user, we can request them back, sorted by
148
- the time and paginated. If you are using a distributed provider, such as
149
- `Redis`, the events can be retrieved by any ruby process in your
150
- application, not just the one that published the event (which is the
151
- case for the "toy" `Hash::Provider`.
253
+ When you publish events into this feed, you would need to provide `User` objects that all respond to `.zip_code` method (based on the above configuration). Since the data is only defined by Zip Code, you probably don't want to be publishing it via a giant array of users. Most likely, you'll want to publish event based on the zip code, and consume them based on the user ID.
254
+
255
+ To support this user-case, let's modify our transformer lambda (only the `data` one) as follows — so that it can support both the consuming read by a user case, and the publishing a feed by zip code case:
256
+
257
+ Alternatively, you could do something like this:
152
258
 
153
259
  [source,ruby]
154
260
  ----
155
- activity.paginate(page: 1, reset_last_read: true)
156
- # => [ <SimpleFeed::Event#0x2134afa value='hello' at='2016-11-20 23:32:56 -0800'> ]
261
+ f.data_key_transformer = ->(entity) do
262
+ case entity
263
+ when User
264
+ entity.zip_code.to_i
265
+ when String # UUIDs
266
+ User.find(entity)&.zip_code.to_i
267
+ when ZipCode, Numeric
268
+ entity.to_i
269
+ else
270
+ raise ArgumentError, "Invalid type #{entity.class.name}"
271
+ end
272
+ end
157
273
  ----
158
274
 
159
- === The Two Forms of the API
275
+ Just make sure that your users always have `.zip_code` defined, and that `ZipCode.new(94107).to_i` returns exactly the same thing as `@user.zip_code.to_i` or your users won't see the feeds they are supposed to see.
276
+
277
+ === The Two Forms of the Feed API
160
278
 
161
279
  The feed API is offered in two forms:
162
280
 
@@ -170,9 +288,8 @@ The method names and signatures are the same. The only difference is in what the
170
288
 
171
289
  Please see further below the details about the <<batch-api,Batch API>>.
172
290
 
173
- +++<a name="single-user-api">++++++</a>+++
174
-
175
291
  [discrete]
292
+
176
293
  ===== Single-User API
177
294
 
178
295
  In the examples below we show responses based on a single-user usage. As previously mentioned, the multi-user usage is the same, except what the response values are, and is discussed further down below.
@@ -316,7 +433,7 @@ The DSL context has access to two additional methods:
316
433
 
317
434
  Below is an example output of `color_dump` method, which is intended for the debugging purposes.
318
435
 
319
- [image:https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png[color_dump output,450]](https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png)
436
+ image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png[title=#color_dump method output, width=659, link=https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png]
320
437
 
321
438
  +++<a name="api">++++++</a>+++
322
439
 
@@ -428,11 +545,11 @@ ruby examples/redis_provider_example.rb
428
545
 
429
546
  The above command will help you download, setup all dependencies, and run the examples for a single user:
430
547
 
431
- image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png[Example,link=https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png]
548
+ image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png[title=Running Redis Example in a Terminal, width=663, link=https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png]
432
549
 
433
550
  If you set `REDIS_DEBUG` variable prior to running the example, you will be able to see every single Redis command executed as the example works its way through. Below is a sample output:
434
551
 
435
- image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png[Example with Debugging,link=https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png]
552
+ image::https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png[title=Running Redis Example with REDIS_DEBUG set, width=918, link=https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png]
436
553
 
437
554
  === Generating Ruby API Documentation
438
555