simple-feed 2.0.2 → 3.1.2

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.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.envrc +3 -0
  3. data/.github/workflows/rubocop.yml +33 -0
  4. data/.github/workflows/ruby.yml +34 -0
  5. data/.gitignore +2 -1
  6. data/.relaxed-rubocop-2.4.yml +174 -0
  7. data/.rspec +1 -1
  8. data/.rubocop.yml +43 -1150
  9. data/.rubocop_todo.yml +203 -0
  10. data/.travis.yml +7 -10
  11. data/CHANGELOG.md +120 -0
  12. data/Gemfile +4 -0
  13. data/Guardfile +3 -3
  14. data/README.adoc +601 -0
  15. data/Rakefile +5 -6
  16. data/bin/console +1 -0
  17. data/codecov.yml +28 -0
  18. data/examples/shared/provider_example.rb +51 -26
  19. data/lib/simple-feed.rb +2 -0
  20. data/lib/simple_feed.rb +2 -0
  21. data/lib/simplefeed/activity/base.rb +2 -0
  22. data/lib/simplefeed/activity/multi_user.rb +8 -6
  23. data/lib/simplefeed/activity/single_user.rb +7 -6
  24. data/lib/simplefeed/dsl/activities.rb +4 -3
  25. data/lib/simplefeed/dsl/formatter.rb +79 -40
  26. data/lib/simplefeed/dsl.rb +3 -1
  27. data/lib/simplefeed/event.rb +52 -13
  28. data/lib/simplefeed/feed.rb +36 -28
  29. data/lib/simplefeed/providers/base/provider.rb +7 -4
  30. data/lib/simplefeed/providers/hash.rb +2 -0
  31. data/lib/simplefeed/providers/key.rb +60 -36
  32. data/lib/simplefeed/providers/proxy.rb +28 -14
  33. data/lib/simplefeed/providers/redis/driver.rb +25 -27
  34. data/lib/simplefeed/providers/redis/provider.rb +41 -39
  35. data/lib/simplefeed/providers/redis/stats.rb +12 -13
  36. data/lib/simplefeed/providers/redis.rb +2 -0
  37. data/lib/simplefeed/providers.rb +24 -10
  38. data/lib/simplefeed/response.rb +7 -7
  39. data/lib/simplefeed/version.rb +3 -1
  40. data/lib/simplefeed.rb +27 -21
  41. data/man/running-example-redis-debug.png +0 -0
  42. data/man/running-example.png +0 -0
  43. data/man/sf-color-dump.png +0 -0
  44. data/simple-feed.gemspec +23 -16
  45. metadata +115 -44
  46. data/README.md +0 -415
  47. data/examples/hash_provider_example.rb +0 -24
  48. data/lib/simplefeed/key/template.rb +0 -52
  49. data/lib/simplefeed/key/type.rb +0 -26
  50. data/lib/simplefeed/providers/hash/paginator.rb +0 -31
  51. data/lib/simplefeed/providers/hash/provider.rb +0 -198
data/README.md DELETED
@@ -1,415 +0,0 @@
1
- # SimpleFeed — Scalable, easy to use activity feed implementation.
2
-
3
-
4
- [![Gem Version](https://img.shields.io/gem/v/simple-feed.svg)](https://rubygems.org/gems/simple-feed)
5
- [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/kigster/simple-feed/master/LICENSE.txt)
6
-
7
- [![Build Status](https://travis-ci.org/kigster/simple-feed.svg?branch=master)](https://travis-ci.org/kigster/simple-feed)
8
- [![Code Climate](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/badges/8b899f6df4fc1ed93759/gpa.svg)](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/feed)
9
- [![Test Coverage](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/badges/8b899f6df4fc1ed93759/coverage.svg)](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/coverage)
10
- [![Issue Count](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/badges/8b899f6df4fc1ed93759/issue_count.svg)](https://codeclimate.com/repos/58339a5b3d9faa74ac006b36/feed)
11
- [![Inline docs](http://inch-ci.org/github/kigster/simple-feed.svg?branch=master)](http://inch-ci.org/github/kigster/simple-feed)
12
- [![Talk on Gitter](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/kigster/simple-feed)
13
-
14
- ---
15
-
16
- **February 20th, 2017**: Please read the blog post [Feeding Frenzy with SimpleFeed](http://kig.re/2017/02/19/feeding-frenzy-with-simple-feed-activity-feed-ruby-gem.html) launching this library. Please leave comments or questions in the discussion thread at the bottom of that post. Thanks!
17
-
18
- ---
19
-
20
- If you like to see this project grow, your donation of any amount is much appreciated.
21
-
22
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FSFYYNEQ8RKWU)
23
-
24
- ---
25
-
26
- 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.
27
-
28
- __Important Notes and Acknowledgements:__
29
-
30
- * SimpleFeed *does not depend on Ruby on Rails* and is a __pure-ruby__ implementation
31
- * SimpleFeed requires ruby 2.3 or later
32
- * SimpleFeed is currently live in production
33
- * SimpleFeed is open source thanks to the generosity of __[Simbi, Inc](http://simbi.com)__.
34
-
35
- ## Background, Examples, Serialization, etc
36
-
37
- Please read the additional documentation, including the examples, on the [project's Github Wiki](https://github.com/kigster/simple-feed/wiki).
38
-
39
- ## Usage
40
-
41
- 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.
42
-
43
- Two providers are supplied with this gem:
44
-
45
- * The production-ready `:redis` provider, which uses the [sorted set Redis data type](https://redislabs.com/ebook/redis-in-action/part-2-core-concepts-2/chapter-3-commands-in-redis/3-5-sorted-sets) to store and fetch the events, scored by time (but not necessarily).
46
-
47
- * The naïve `:hash` provider based on the ruby `Hash` class, that can be useful in unit tests, or in simple simulations.
48
-
49
- You initialize a provider by using the `SimpleFeed.provider([Symbol])` method.
50
-
51
- ### Configuration
52
-
53
- Below we configure a feed called `:newsfeed`, which in this example will be populated with the various events coming from the followers.
54
-
55
- ```ruby
56
- require 'simplefeed'
57
-
58
- # Let's define a Redis-based feed, and wrap Redis in a in a ConnectionPool.
59
- SimpleFeed.define(:newsfeed) do |f|
60
- f.provider = SimpleFeed.provider(:redis,
61
- redis: -> { ::Redis.new },
62
- pool_size: 10)
63
- f.per_page = 50 # default page size
64
- f.batch_size = 10 # default batch size
65
- f.namespace = 'nf' # only needed if you use the same redis for more than one feed
66
- end
67
- ```
68
-
69
- After the feed is defined, the gem creates a similarly named method under the `SimpleFeed` namespace to access the feed. For example, given a name such as `:newsfeed` the following are all valid ways of accessing the feed:
70
-
71
- * `SimpleFeed.newsfeed`
72
- * `SimpleFeed.get(:newsfeed)`
73
-
74
- You can also get a full list of currently defined feeds with `SimpleFeed.feed_names` method.
75
-
76
- ### Reading from and writing to the feed
77
-
78
- For the impatient here is a quick way to get started with the `SimpleFeed`.
79
-
80
- ```ruby
81
- # This assumes we have previously defined a feed named :newsfeed (see above)
82
- activity = SimpleFeed.newsfeed.activity(@current_user.id)
83
- # Store directly the value and the optional time stamp
84
- activity.store(value: 'hello')
85
- # => true
86
-
87
- # or equivalent:
88
- @event = SimpleFeed::Event.new('hello', Time.now)
89
- activity.store(event: @event)
90
- # => false # false indicates that the same event is already in the feed.
91
- ```
92
-
93
- As we've added events for this user, we can request them back, sorted by
94
- the time and paginated. If you are using a distributed provider, such as
95
- `Redis`, the events can be retrieved by any ruby process in your
96
- application, not just the one that published the event (which is the
97
- case for the "toy" `Hash::Provider`.
98
-
99
- ```ruby
100
- activity.paginate(page: 1, reset_last_read: true)
101
- # => [ <SimpleFeed::Event#0x2134afa value='hello' at='2016-11-20 23:32:56 -0800'> ]
102
- ```
103
-
104
- ### The Two Forms of the API
105
-
106
- The feed API is offered in two forms:
107
-
108
- 1. single-user form, and
109
- 2. a batch (multi-user) form.
110
-
111
- The method names and signatures are the same. The only difference is in what the methods return:
112
-
113
- 1. In the single user case, the return of, say, `#total_count` is an `Integer` value representing the total count for this user.
114
- 2. In the multi-user case, the return is a `SimpleFeed::Response` instance, that can be thought of as a `Hash`, that has the user IDs as the keys, and return results for each user as a value.
115
-
116
- Please see further below the details about the [Batch API](#batch-api).
117
-
118
- <a name="single-user-api"/>
119
-
120
- ##### Single-User API
121
-
122
- 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.
123
-
124
- Let's take a look at a ruby session, which demonstrates return values of the feed operations for a single user:
125
-
126
- ```ruby
127
- require 'simplefeed'
128
-
129
- # Define the feed using an in-memory Hash provider, which uses
130
- # SortedSet to keep user's events sorted.
131
- SimpleFeed.define(:followers) do |f|
132
- f.provider = SimpleFeed.provider(:hash)
133
- f.per_page = 50
134
- f.per_page = 2
135
- end
136
-
137
- # Let's get the Activity instance that wraps this user_id
138
- activity = SimpleFeed.followers.activity(user_id) # => [... complex object removed for brevity ]
139
- # let's clear out this feed to ensure it's empty
140
- activity.wipe # => true
141
- # Let's verify that the counts for this feed are at zero
142
- activity.total_count # => 0
143
- activity.unread_count # => 0
144
- # Store some events
145
- activity.store(value: 'hello') # => true
146
- activity.store(value: 'goodbye', at: Time.now - 20) # => true
147
- activity.unread_count # => 2
148
- # Now we can paginate the events, while resetting this user's last-read timestamp:
149
- activity.paginate(page: 1, reset_last_read: true)
150
- # [
151
- # [0] #<SimpleFeed::Event: value=good bye, at=1480475294.0579991>,
152
- # [1] #<SimpleFeed::Event: value=hello, at=1480475294.057138>
153
- # ]
154
- # Now the unread_count should return 0 since the user just "viewed" the feed.
155
- activity.unread_count # => 0
156
- activity.delete(value: 'hello') # => true
157
- # the next method yields to a passed in block for each event in the user's feed, and deletes
158
- # all events for which the block returns true. The return of this call is the
159
- # array of all events that have been deleted for this user.
160
- activity.delete_if do |event, user_id|
161
- event.value =~ /good/
162
- end
163
- # => [
164
- # [0] #<SimpleFeed::Event: value=good bye, at=1480475294.0579991>
165
- # ]
166
- activity.total_count # => 0
167
- ```
168
-
169
- You can fetch all items (optionally filtered by time) in the feed using `#fetch`,
170
- `#paginate` and reset the `last_read` timestamp by passing the `reset_last_read: true` as a parameter.
171
-
172
- <a name="batch-api"/>
173
-
174
- ##### Batch (Multi-User) API
175
-
176
- This API should be used when dealing with an array of users (or, in the
177
- future, a Proc or an ActiveRecord relation).
178
-
179
- > There are several reasons why this API should be preferred for
180
- > operations that perform a similar action across a range of users:
181
- > _various provider implementations can be heavily optimized for
182
- > concurrency, and performance_.
183
- >
184
- > The Redis Provider, for example, uses a notion of `pipelining` to send
185
- > updates for different users asynchronously and concurrently.
186
-
187
- Multi-user operations return a `SimpleFeed::Response` object, which can
188
- be used as a hash (keyed on user_id) to fetch the result of a given
189
- user.
190
-
191
- ```ruby
192
- # Using the Feed API with, eg #find_in_batches
193
- @event_producer.followers.find_in_batches do |group|
194
-
195
- # Convert a group to the array of IDs and get ready to store
196
- activity = SimpleFeed.get(:followers).activity(group.map(&:id))
197
- activity.store(value: "#{@event_producer.name} liked an article")
198
-
199
- # => [Response] { user_id1 => [Boolean], user_id2 => [Boolean]... }
200
- # true if the value was stored, false if it wasn't.
201
- end
202
- ```
203
-
204
- ##### Activity Feed DSL (Domain-Specific Language)
205
-
206
- The library offers a convenient DSL for adding feed functionality into
207
- your current scope.
208
-
209
- To use the module, just include `SimpleFeed::DSL` where needed, which
210
- exports just one primary method `#with_activity`. You call this method
211
- and pass an activity object created for a set of users (or a single
212
- user), like so:
213
-
214
- ```ruby
215
- require 'simplefeed/dsl'
216
- include SimpleFeed::DSL
217
-
218
- feed = SimpleFeed.newsfeed
219
- activity = feed.activity(current_user.id)
220
- data_to_store = %w(France Germany England)
221
-
222
- def report(value)
223
- puts value
224
- end
225
-
226
- with_activity(activity, countries: data_to_store) do
227
- # we can use countries as a variable because it was passed above in **opts
228
- countries.each do |country|
229
- # we can call #store without a receiver because the block is passed to
230
- # instance_eval
231
- store(value: country) { |result| report(result ? 'success' : 'failure') }
232
- # we can call #report inside the proc because it is evaluated in the
233
- # outside context of the #with_activity
234
-
235
- # now let's print a color ASCII dump of the entire feed for this user:
236
- color_dump
237
- end
238
- printf "Activity counts are: %d unread of %d total\n", unread_count, total_count
239
- end
240
- ```
241
-
242
- The DSL context has access to two additional methods:
243
-
244
- * `#event(value, at)` returns a fully constructed `SimpleFeed::Event` instance
245
- * `#color_dump` prints to STDOUT the ASCII text dump of the current user's activities (events), as well as the counts and the `last_read` shown visually on the time line.
246
-
247
- ##### `#color_dump`
248
-
249
- Below is an example output of `color_dump` method, which is intended for the debugging purposes.
250
-
251
- [<img src="https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png" width="450" alt="color_dump output" style="width: 300px; max-width:100%;">](https://raw.githubusercontent.com/kigster/simple-feed/master/man/sf-color-dump.png)
252
-
253
- <a name="api"/>
254
-
255
- ## Complete API
256
-
257
- For completeness sake we'll show the multi-user API responses only. For a single-user use-case the response is typically a scalar, and the input is a singular `user_id`, not an array of ids.
258
-
259
- #### Multi-User (Batch) API
260
-
261
- Each API call at this level expects an array of user IDs, therefore the
262
- return value is an object, `SimpleFeed::Response`, containing individual
263
- responses for each user, accessible via `response[user_id]` method.
264
-
265
- ```ruby
266
- @multi = SimpleFeed.get(:feed_name).activity(User.active.map(&:id))
267
-
268
- @multi.store(value:, at:)
269
- @multi.store(event:)
270
- # => [Response] { user_id => [Boolean], ... } true if the value was stored, false if it wasn't.
271
-
272
- @multi.delete(value:, at:)
273
- @multi.delete(event:)
274
- # => [Response] { user_id => [Boolean], ... } true if the value was removed, false if it didn't exist
275
-
276
- @multi.delete_if do |event, user_id|
277
- # if the block returns true, the event is deleted and returned
278
- end
279
- # => [Response] { user_id => [deleted_event1, deleted_event2, ...], ... }
280
-
281
- # Wipe the feed for a given user(s)
282
- @multi.wipe
283
- # => [Response] { user_id => [Boolean], ... } true if user activity was found and deleted, false otherwise
284
-
285
- # Return a paginated list of all items, optionally with the total count of items
286
- @multi.paginate(page: 1,
287
- per_page: @multi.feed.per_page,
288
- with_total: false,
289
- reset_last_read: false)
290
- # => [Response] { user_id => [Array]<Event>, ... }
291
- # Options:
292
- # reset_last_read: false — reset last read to Time.now (true), or the provided timestamp
293
- # with_total: true — returns a hash for each user_id:
294
- # => [Response] { user_id => { events: Array<Event>, total_count: 3 }, ... }
295
-
296
- # Return un-paginated list of all items, optionally filtered
297
- @multi.fetch(since: nil, reset_last_read: false)
298
- # => [Response] { user_id => [Array]<Event>, ... }
299
- # Options:
300
- # reset_last_read: false — reset last read to Time.now (true), or the provided timestamp
301
- # since: <timestamp> — if provided, returns all items posted since then
302
- # since: :last_read — if provided, returns all unread items and resets +last_read+
303
-
304
- @multi.reset_last_read
305
- # => [Response] { user_id => [Time] last_read, ... }
306
-
307
- @multi.total_count
308
- # => [Response] { user_id => [Integer] total_count, ... }
309
-
310
- @multi.unread_count
311
- # => [Response] { user_id => [Integer] unread_count, ... }
312
-
313
- @multi.last_read
314
- # => [Response] { user_id => [Time] last_read, ... }
315
-
316
- ```
317
-
318
- ## Providers in Depth
319
-
320
- As we've discussed above, a provider is an underlying persistence mechanism implementation.
321
-
322
- It is the intention of this gem that:
323
-
324
- * it should be easy to write new providers
325
- * it should be easy to swap out providers
326
-
327
- To create a new provider please use `SimpleFeed::Providers::Hash::Provider` class as a starting point.
328
-
329
- Two providers are available with this gem:
330
-
331
- ### `SimpleFeed::Providers::Redis::Provider`
332
-
333
- Redis Provider is a production-ready persistence adapter that uses the [sorted set Redis data type](https://redislabs.com/ebook/redis-in-action/part-2-core-concepts-2/chapter-3-commands-in-redis/3-5-sorted-sets).
334
-
335
- This provider is optimized for large writes and can use either a single Redis instance for all users of your application, or any number of Redis [shards](https://en.wikipedia.org/wiki/Shard_(database_architecture)) by using a [_Twemproxy_](https://github.com/twitter/twemproxy) in front of the Redis shards.
336
-
337
- While future
338
-
339
- * `SimpleFeed::Providers::HashProvider` is a pure Hash-like implementation of a provider that can be useful in unit tests of a host application. This provider could be used to write and read events within a single ruby process, can be serialized to and from a YAML file, and is therefore intended primarily for Feed emulations in automated tests.
340
-
341
-
342
- ### Redis Provider
343
-
344
- If you set environment variable `REDIS_DEBUG` to `true` and run the example (see below) you will see every operation redis performs. This could be useful in debugging an issue or submitting a bug report.
345
-
346
- ## Running the Examples
347
-
348
- Source code for the gem contains the `examples` folder with an example file that can be used to test out the providers, and see what they do under the hood.
349
-
350
- To run it, checkout the source of the library, and then:
351
-
352
- ```bash
353
- git clone https://github.com/kigster/simple-feed.git
354
- cd simple-feed
355
- bundle
356
- be rspec # make sure tests are passing
357
- ruby examples/redis_provider_example.rb
358
- ```
359
-
360
- The above command will help you download, setup all dependencies, and run the examples for a single user:
361
-
362
- [![Example](https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png)](https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example.png)
363
-
364
- 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:
365
-
366
- [![Example with Debugging](https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png)](https://raw.githubusercontent.com/kigster/simple-feed/master/man/running-example-redis-debug.png)
367
-
368
- ### Generating Ruby API Documentation
369
-
370
- ```bash
371
- rake doc
372
- ```
373
-
374
- This should use Yard to generate the documentation, and open your browser once it's finished.
375
-
376
- ### Installation
377
-
378
- Add this line to your application's Gemfile:
379
-
380
- ```ruby
381
- gem 'simple-feed'
382
- ```
383
-
384
- And then execute:
385
-
386
- ```
387
- $ bundle
388
- ```
389
-
390
- Or install it yourself as:
391
-
392
- ```
393
- $ gem install simple-feed
394
- ```
395
-
396
- ### Development
397
-
398
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
399
-
400
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
401
-
402
- ### Contributing
403
-
404
- Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/simple-feed
405
-
406
- ### License
407
-
408
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
409
-
410
- ### Acknowledgements
411
-
412
- * This project is conceived and sponsored by [Simbi, Inc.](https://simbi.com).
413
- * Author's personal experience at [Wanelo, Inc.](https://wanelo.com) has served as an inspiration.
414
-
415
-
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # This is an executable example of working with a Redis feed, and storing
4
- # events for various users.
5
- #
6
- # DEPENDENCIES:
7
- # gem install colored2
8
- # gem install awesome_print
9
- #
10
- # RUNNING
11
- # ruby redis-feed.rb
12
- #
13
-
14
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
15
-
16
- require 'simplefeed'
17
-
18
- @feed = SimpleFeed.define(:news) do |f|
19
- f.provider = SimpleFeed.provider(:hash)
20
- f.max_size = 1000
21
- end
22
-
23
- require_relative 'shared/provider_example'
24
-
@@ -1,52 +0,0 @@
1
- require 'base62-rb'
2
- require 'hashie/mash'
3
-
4
- module SimpleFeed
5
- module Key
6
-
7
- class TextTemplate < Struct.new(:text)
8
- def render(params = {})
9
- output = self.text.dup
10
- params.each_pair do |key, value|
11
- output.gsub!(%r[{{\s*#{key}\s*}}], value.to_s)
12
- end
13
- output
14
- end
15
- end
16
-
17
- DEFAULT_TEXT_TEMPLATE = TextTemplate.new('{{ namespace }}u.{{ base62_user_id }}.{{ key_marker }}')
18
-
19
- class Template
20
- attr_accessor :namespace, :key_types, :text_template
21
-
22
- def initialize(namespace,
23
- key_types = DEFAULT_TYPES,
24
- text_template = DEFAULT_TEXT_TEMPLATE
25
- )
26
-
27
- self.namespace = namespace
28
- self.key_types = key_types
29
- self.text_template = text_template
30
-
31
- self.key_types.each do |type|
32
- type.template ||= text_template if text_template
33
- end
34
- end
35
-
36
- def render_options
37
- h = {}
38
- h.merge!({ 'namespace' => namespace ? "#{namespace}|" : '' })
39
- h
40
- end
41
-
42
- # Returns array of key names, such as [:meta, :data]
43
- def key_names
44
- key_types.map(&:name).map(&:to_s).sort
45
- end
46
-
47
- private
48
-
49
- end
50
- end
51
- end
52
-
@@ -1,26 +0,0 @@
1
- require_relative 'template'
2
-
3
- module SimpleFeed
4
- module Key
5
- class Type < Struct.new(:name, :marker)
6
- attr_accessor :template
7
-
8
- def initialize(name, marker, template = nil)
9
- super(name, marker)
10
- self.template = template
11
- end
12
-
13
- def render(opts = {})
14
- self.template.render(opts.merge({ 'key_type' => name, 'key_marker' => marker }))
15
- end
16
- end
17
-
18
- DEFAULT_TYPES = [
19
- { name: :data, marker: 'd' },
20
- { name: :meta, marker: 'm' }
21
- ].map do |type|
22
- Type.new(type[:name], type[:marker], DEFAULT_TEXT_TEMPLATE)
23
- end
24
-
25
- end
26
- end
@@ -1,31 +0,0 @@
1
- module SimpleFeed
2
- module Providers
3
- module Hash
4
- # Include this module into any provider etc that has access to the +feed.fetch+
5
- # methods, and it will provide +paginate+ method based on all.
6
- #
7
- # Of course this is not very efficient, because it requires fetching all events for the user.
8
- module Paginator
9
-
10
- def paginate(user_ids:, page: nil, per_page: feed.per_page, &block)
11
- response = feed.fetch(user_ids: user_ids)
12
- response = SimpleFeed::Response.new(response.to_h)
13
- response.transform do |*, events|
14
- paginate_items(order_events(events, &block), page: page, per_page: per_page)
15
- end
16
- end
17
-
18
- def paginate_items(items, page: nil, per_page: nil)
19
- (page && page > 0) ? items[((page - 1) * per_page)...(page * per_page)] : items
20
- end
21
-
22
- def order_events(events, &block)
23
- return nil unless events
24
- events.sort do |a, b|
25
- block ? yield(a, b) : b.at <=> a.at
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end