simple-feed 2.1.0 → 3.0.1

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.

Potentially problematic release.


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

@@ -2,11 +2,17 @@
2
2
 
3
3
  require_relative 'providers'
4
4
  require_relative 'activity/base'
5
- require 'simplefeed/key/template'
5
+ require_relative 'providers/key'
6
6
 
7
7
  module SimpleFeed
8
8
  class Feed
9
- attr_accessor :per_page, :max_size, :batch_size, :meta, :namespace
9
+ attr_accessor :per_page,
10
+ :max_size,
11
+ :batch_size,
12
+ :namespace,
13
+ :data_key_transformer,
14
+ :meta_key_transformer
15
+
10
16
  attr_reader :name
11
17
 
12
18
  SimpleFeed::Providers.define_provider_methods(self) do |feed, method, opts, &block|
@@ -14,19 +20,21 @@ module SimpleFeed
14
20
  end
15
21
 
16
22
  def initialize(name)
17
- @name = name
18
- @name = name.underscore.to_sym unless name.is_a?(Symbol)
23
+ @name = name
24
+ @name = name.underscore.to_sym unless name.is_a?(Symbol)
19
25
  # set the defaults if not passed in
20
- @meta = {}
21
- @namespace = nil
26
+ @meta = {}
27
+ @namespace = nil
22
28
  @per_page ||= 50
23
29
  @max_size ||= 1000
24
30
  @batch_size ||= 10
31
+ @meta_key_transformer = nil
32
+ @data_key_transformer = nil
25
33
  @proxy = nil
26
34
  end
27
35
 
28
36
  def provider=(definition)
29
- @proxy = Providers::Proxy.from(definition)
37
+ @proxy = Providers::Proxy.from(definition)
30
38
  @proxy.feed = self
31
39
  @proxy
32
40
  end
@@ -63,12 +71,15 @@ module SimpleFeed
63
71
  end
64
72
 
65
73
  def key(user_id)
66
- SimpleFeed::Providers::Key.new(user_id, key_template)
74
+ SimpleFeed::Providers::Key.new(user_id,
75
+ namespace: namespace,
76
+ data_key_transformer: data_key_transformer,
77
+ meta_key_transformer: meta_key_transformer)
67
78
  end
68
79
 
69
80
  def eql?(other)
70
81
  other.class == self.class &&
71
- %i(per_page max_size name).all? { |m| send(m).equal?(other.send(m)) } &&
82
+ %i(per_page max_size name namespace data_key_transformer meta_key_transformer).all? { |m| send(m).equal?(other.send(m)) } &&
72
83
  provider.provider.class == other.provider.provider.class
73
84
  end
74
85
 
@@ -58,7 +58,7 @@ module SimpleFeed
58
58
  def with_response_batched(user_ids, external_response = nil)
59
59
  with_response(external_response) do |response|
60
60
  batch(user_ids) do |key|
61
- response.for(key.user_id) { yield(key, response) }
61
+ response.for(key.consumer) { yield(key, response) }
62
62
  end
63
63
  end
64
64
  end
@@ -46,7 +46,7 @@ module SimpleFeed
46
46
  def delete_if(user_ids:)
47
47
  with_response_batched(user_ids) do |key|
48
48
  activity(key).map do |event|
49
- if yield(event, key.user_id)
49
+ if yield(event, key.consumer)
50
50
  __delete(key, event)
51
51
  event
52
52
  end
@@ -80,7 +80,7 @@ module SimpleFeed
80
80
  def fetch(user_ids:, since: nil, reset_last_read: false)
81
81
  response = with_response_batched(user_ids) do |key|
82
82
  if since == :unread
83
- activity(key).reject { |event| event.at < user_record(key).last_read.to_f }
83
+ activity(key).reject { |event| event.at < user_meta_record(key).last_read.to_f }
84
84
  elsif since
85
85
  activity(key).reject { |event| event.at < since.to_f }
86
86
  else
@@ -94,7 +94,7 @@ module SimpleFeed
94
94
 
95
95
  def reset_last_read(user_ids:, at: Time.now)
96
96
  with_response_batched(user_ids) do |key|
97
- user_record(key)[:last_read] = at
97
+ user_meta_record(key)[:last_read] = at
98
98
  at
99
99
  end
100
100
  end
@@ -107,13 +107,13 @@ module SimpleFeed
107
107
 
108
108
  def unread_count(user_ids:)
109
109
  with_response_batched(user_ids) do |key|
110
- activity(key).count { |event| event.at > user_record(key).last_read.to_f }
110
+ activity(key).count { |event| event.at > user_meta_record(key).last_read.to_f }
111
111
  end
112
112
  end
113
113
 
114
114
  def last_read(user_ids:)
115
115
  with_response_batched(user_ids) do |key|
116
- user_record(key).last_read
116
+ user_meta_record(key).last_read
117
117
  end
118
118
  end
119
119
 
@@ -122,7 +122,7 @@ module SimpleFeed
122
122
  end
123
123
 
124
124
  def total_users
125
- h.size
125
+ h.size / 2
126
126
  end
127
127
 
128
128
  private
@@ -139,27 +139,37 @@ module SimpleFeed
139
139
  (size_before > size_after)
140
140
  end
141
141
 
142
- def create_user_record
142
+ def create_meta_record
143
143
  Hashie::Mash.new(
144
- { last_read: 0, activity: SortedSet.new }
144
+ { last_read: 0 }
145
145
  )
146
146
  end
147
147
 
148
- def user_record(key)
149
- h[key.data] ||= create_user_record
148
+ def create_data_record
149
+ Hashie::Mash.new(
150
+ { activity: SortedSet.new }
151
+ )
152
+ end
153
+
154
+ def user_data_record(key)
155
+ h[key.data] ||= create_data_record
156
+ end
157
+
158
+ def user_meta_record(key)
159
+ h[key.meta] ||= create_meta_record
150
160
  end
151
161
 
152
162
  def wipe_user_record(key)
153
- h[key.data] = create_user_record
163
+ h[key.data] = create_data_record
154
164
  end
155
165
 
156
166
  def activity(key, event = nil)
157
- user_record(key)[:activity] << event if event
158
- user_record(key)[:activity].to_a
167
+ user_data_record(key)[:activity] << event if event
168
+ user_data_record(key)[:activity].to_a
159
169
  end
160
170
 
161
171
  def add_event(event, key)
162
- uas = user_record(key)[:activity]
172
+ uas = user_data_record(key)[:activity]
163
173
  if uas.include?(event)
164
174
  false
165
175
  else
@@ -172,11 +182,11 @@ module SimpleFeed
172
182
  end
173
183
 
174
184
  def __last_read(key, _value = nil)
175
- user_record(key)[:last_read]
185
+ user_meta_record(key)[:last_read]
176
186
  end
177
187
 
178
188
  def __delete(key, event)
179
- user_record(key)[:activity].delete(event)
189
+ user_data_record(key)[:activity].delete(event)
180
190
  end
181
191
 
182
192
  def create_event(*args, **opts)
@@ -2,10 +2,6 @@
2
2
 
3
3
  require 'base62-rb'
4
4
  require 'hashie/mash'
5
- require 'simplefeed/key/template'
6
- require 'simplefeed/key/type'
7
-
8
- require 'forwardable'
9
5
 
10
6
  module SimpleFeed
11
7
  module Providers
@@ -15,66 +11,85 @@ module SimpleFeed
15
11
  # ↓ ↓
16
12
  # "ff|u.f23098.m"
17
13
  # ↑ ↑
18
- # namespace user_id(base62)
14
+ # namespace consumer(base62)
19
15
  #
20
16
  class Key
21
- attr_accessor :user_id, :key_template
17
+ class << self
18
+ def rot13(value)
19
+ value.tr('abcdefghijklmnopqrstuvwxyz',
20
+ 'nopqrstuvwxyzabcdefghijklm')
21
+ end
22
+ end
22
23
 
23
- extend Forwardable
24
- def_delegators :@key_template, :key_names, :key_types
24
+ SERIALIZED_DATA_TEMPLATE = '{{namespace}}u.{{data_id}}.d'
25
+ SERIALIZED_META_TEMPLATE = '{{namespace}}u.{{meta_id}}.m'
25
26
 
26
- def initialize(user_id, key_template)
27
- self.user_id = user_id
28
- self.key_template = key_template
27
+ attr_reader :consumer, :namespace, :data_key_transformer, :meta_key_transformer
29
28
 
30
- define_key_methods
29
+ def initialize(consumer,
30
+ namespace: nil,
31
+ data_key_transformer: nil,
32
+ meta_key_transformer: nil)
33
+ @consumer = consumer
34
+ @namespace = namespace
35
+ @data_key_transformer = data_key_transformer
36
+ @meta_key_transformer = meta_key_transformer
31
37
  end
32
38
 
33
- # Defines #data and #meta methods.
34
- def define_key_methods
35
- key_template.key_types.each do |type|
36
- key_name = type.name
37
- next if respond_to?(key_name)
38
-
39
- self.class.send(:define_method, key_name) do
40
- instance_variable_get("@#{key_name}") ||
41
- instance_variable_set("@#{key_name}", type.render(render_options))
42
- end
43
- end
39
+ def data
40
+ @data ||= render(SERIALIZED_DATA_TEMPLATE)
44
41
  end
45
42
 
46
- def base62_user_id
47
- @base62_user_id ||= if user_id.is_a?(Numeric)
48
- ::Base62.encode(user_id)
49
- else
50
- rot13(user_id.to_s)
51
- end
43
+ def meta
44
+ @meta ||= render(SERIALIZED_META_TEMPLATE)
52
45
  end
53
46
 
54
47
  def keys
55
- key_names.map { |name| send(name) }
56
- end
57
-
58
- def render_options
59
- key_template.render_options.merge!({
60
- 'user_id' => user_id,
61
- 'base62_user_id' => base62_user_id
62
- })
48
+ [data, meta]
63
49
  end
64
50
 
65
51
  def to_s
66
- super + { user_id: user_id, base62_user_id: base62_user_id, keys: keys }.to_s
52
+ super + key_params.to_s
67
53
  end
68
54
 
69
55
  def inspect
70
- render_options.inspect
56
+ super + key_params.inspect
71
57
  end
72
58
 
73
59
  private
74
60
 
75
- def rot13(value)
76
- value.tr('abcdefghijklmnopqrstuvwxyz',
77
- 'nopqrstuvwxyzabcdefghijklm')
61
+ def render(template)
62
+ template.dup.tap do |output|
63
+ key_params.each_pair do |key, value|
64
+ output.gsub!(/{{#{key}}}/, value.to_s)
65
+ end
66
+ end
67
+ end
68
+
69
+ def obscure_value(id)
70
+ id = id.to_i if id.is_a?(String) && id =~ /^[\d]+$/
71
+
72
+ if id.is_a?(Numeric)
73
+ ::Base62.encode(id)
74
+ else
75
+ self.class.rot13(id.to_s)
76
+ end
77
+ end
78
+
79
+ def key_params
80
+ @key_params ||= Hashie::Mash.new(
81
+ namespace: namespace ? "#{namespace}|" : '',
82
+ data_id: obscure_value(data_id),
83
+ meta_id: obscure_value(meta_id)
84
+ )
85
+ end
86
+
87
+ def meta_id
88
+ meta_key_transformer&.call(consumer) || consumer
89
+ end
90
+
91
+ def data_id
92
+ data_key_transformer&.call(consumer) || consumer
78
93
  end
79
94
  end
80
95
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module SimpleFeed
4
4
  module Providers
5
+ RUBY_MAJOR_VERSION = RUBY_VERSION.split('.')[0..1].join.to_i
6
+
5
7
  class Proxy
6
8
  attr_accessor :provider
7
9
 
@@ -15,7 +17,7 @@ module SimpleFeed
15
17
  end
16
18
 
17
19
  def initialize(provider_or_klass, *args, **options)
18
- self.provider = if provider_or_klass.is_a?(::String)
20
+ self.provider = if provider_or_klass.is_a?(::String) || provider_or_klass.is_a?(::Symbol)
19
21
  ::Object.const_get(provider_or_klass).new(*args, **options)
20
22
  else
21
23
  provider_or_klass
@@ -26,12 +28,23 @@ module SimpleFeed
26
28
  end
27
29
  end
28
30
 
29
- # Forward all other method calls to Provider
30
- def method_missing(name, *args, **opts, &block)
31
- if provider&.respond_to?(name)
32
- provider.send(name, *args, **opts, &block)
33
- else
34
- super(name, *args, **opts, &block)
31
+ if RUBY_MAJOR_VERSION >= 27
32
+ # Forward all other method calls to Provider
33
+ def method_missing(name, *args, **opts, &block)
34
+ if provider&.respond_to?(name)
35
+ provider.send(name, *args, **opts, &block)
36
+ else
37
+ super(name, *args, **opts, &block)
38
+ end
39
+ end
40
+ else
41
+ # Forward all other method calls to Provider
42
+ def method_missing(name, *args, &block)
43
+ if provider&.respond_to?(name)
44
+ provider.send(name, *args, &block)
45
+ else
46
+ super(name, *args, &block)
47
+ end
35
48
  end
36
49
  end
37
50
  end
@@ -51,9 +51,9 @@ module SimpleFeed
51
51
  raise ArgumentError, '#delete_if must be called with a block that receives (user_id, event) as arguments.' unless block_given?
52
52
 
53
53
  with_response_batched(user_ids) do |key|
54
- fetch(user_ids: [key.user_id])[key.user_id].map do |event|
54
+ fetch(user_ids: [key.consumer])[key.consumer].map do |event|
55
55
  with_redis do |redis|
56
- if yield(event, key.user_id)
56
+ if yield(event, key.consumer)
57
57
  redis.zrem(key.data, event.value) ? event : nil
58
58
  end
59
59
  end
@@ -90,7 +90,7 @@ module SimpleFeed
90
90
 
91
91
  response = with_response_pipelined(user_ids) do |redis, key|
92
92
  if since == :unread
93
- redis.zrevrangebyscore(key.data, '+inf', (last_read_response.delete(key.user_id) || 0).to_f, withscores: true)
93
+ redis.zrevrangebyscore(key.data, '+inf', (last_read_response.delete(key.consumer) || 0).to_f, withscores: true)
94
94
  elsif since
95
95
  redis.zrevrangebyscore(key.data, '+inf', since.to_f, withscores: true)
96
96
  else
@@ -120,7 +120,7 @@ module SimpleFeed
120
120
  get_users_last_read(redis, key)
121
121
  end
122
122
  with_response_pipelined(response.user_ids, response) do |redis, key, _response|
123
- last_read = _response.delete(key.user_id).to_f
123
+ last_read = _response.delete(key.consumer).to_f
124
124
  redis.zcount(key.data, last_read, '+inf')
125
125
  end
126
126
  end
@@ -223,7 +223,7 @@ module SimpleFeed
223
223
  def with_response_pipelined(user_ids, response = nil)
224
224
  with_response(response) do |response|
225
225
  batch_pipelined(user_ids) do |redis, key|
226
- response.for(key.user_id) { yield(redis, key, response) }
226
+ response.for(key.consumer) { yield(redis, key, response) }
227
227
  end
228
228
  end
229
229
  end
@@ -231,7 +231,7 @@ module SimpleFeed
231
231
  def with_response_multi(user_ids, response = nil)
232
232
  with_response(response) do |response|
233
233
  batch_multi(user_ids) do |redis, key|
234
- response.for(key.user_id) { yield(redis, key, response) }
234
+ response.for(key.consumer) { yield(redis, key, response) }
235
235
  end
236
236
  end
237
237
  end
@@ -28,7 +28,7 @@ module SimpleFeed
28
28
 
29
29
  def for(key_or_user_id, result = nil)
30
30
  user_id = key_or_user_id.is_a?(SimpleFeed::Providers::Key) ?
31
- key_or_user_id.user_id :
31
+ key_or_user_id.consumer :
32
32
  key_or_user_id
33
33
 
34
34
  @result[user_id] = result || yield(@result[user_id])
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleFeed
4
- VERSION = '2.1.0'
4
+ VERSION = '3.0.1'
5
5
  end
Binary file
Binary file
@@ -2,7 +2,8 @@
2
2
 
3
3
  lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'simplefeed/version'
5
+ # noinspection RubyResolve
6
+ load File.expand_path("#{lib}/simplefeed/version.rb")
6
7
 
7
8
  Gem::Specification.new do |spec|
8
9
  spec.name = 'simple-feed'
@@ -30,10 +31,13 @@ Gem::Specification.new do |spec|
30
31
  spec.add_dependency 'hashie'
31
32
  spec.add_dependency 'hiredis'
32
33
  spec.add_dependency 'redis'
34
+ spec.add_dependency 'tty-box'
35
+ spec.add_dependency 'tty-screen'
33
36
 
34
37
  spec.add_development_dependency 'awesome_print'
35
38
  spec.add_development_dependency 'bundler'
36
39
  spec.add_development_dependency 'codeclimate-test-reporter'
40
+ spec.add_development_dependency 'codecov'
37
41
  spec.add_development_dependency 'rake'
38
42
  spec.add_development_dependency 'rspec'
39
43
  spec.add_development_dependency 'rspec-its'