progressrus 0.1.6 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a654e74220bfd54eb96f2c18390e8fcc794ae937
4
- data.tar.gz: db38bb7f163a7ef1d2cca42fde38a644464e0316
2
+ SHA256:
3
+ metadata.gz: 564bda7bfb2cfd735379ef412a908303655e1fe2853cd666d6d6fcbcefca5a6b
4
+ data.tar.gz: 0acaae1e3e6cdd2d69be60b27dfbe5d5185af7f7d6677b5ad0e190918cbab43b
5
5
  SHA512:
6
- metadata.gz: 80adef7173fa11523e3ea323333d8b4dd50cfdc9b88c41dc85ba718b9c2b5f0e25a97086f9e0e552e9b1878ac4c0e07aefd20e8d9370ca7ffe0f776d7d78a5b1
7
- data.tar.gz: 2a4bdbef69f9f31d8675f922ff73d02325c1732d8fb24823b12b6765ca1451cb6f0176af7c45e08b817663d1fa65e613951300480a88941f2818fb045863cc08
6
+ metadata.gz: 417d841b14a93351ed90ff754706467c42e29663bd076d55b9d7e23bca8ceef7989095f8eab1ce14cfc97caf51ed9497079f79498c775a6f06a4a20358c7417a
7
+ data.tar.gz: 514c8bcf9fb63500629630255861d590c35cbbdb5ab05c4798a37d30a32ffe51b4a8c59d11cb3f53ccc5d86aafdb52bab48c0c23972596e2a6f96208b9eb557d
@@ -2,5 +2,7 @@ language: ruby
2
2
  services:
3
3
  - redis-server
4
4
  rvm:
5
- - 2.0.0
6
- - 2.1.1
5
+ - 2.4
6
+ - 2.5
7
+ - 2.6
8
+ - 2.7
@@ -2,29 +2,75 @@ require 'json'
2
2
  require 'securerandom'
3
3
  require 'redis'
4
4
  require 'time'
5
- require_relative "progressrus/store"
6
5
  require_relative "progressrus/store/base"
7
6
  require_relative "progressrus/store/redis"
8
7
  require_relative "progressrus/store/progressbar"
9
8
  require_relative "progressrus/core_ext/enumerable"
10
9
 
11
10
  class Progressrus
11
+ @mutex = Mutex.new
12
+
13
+ class InvalidStoreError < StandardError
14
+ def initialize
15
+ message = <<~MSG
16
+ The store needs to implement `persist`, `scope`, `find` and `flush`
17
+ We have a base class that your store can inherit from:
18
+ Progressrus::Store::Base
19
+ MSG
20
+ super(message)
21
+ end
22
+ end
23
+
24
+ class StoreNotFoundError < StandardError
25
+ def initialize(store)
26
+ message = <<~MSG
27
+ The store `#{store}` does not exists.
28
+ Available stores: #{Progressrus.stores.keys.join(', ')}
29
+ MSG
30
+ super(message)
31
+ end
32
+ end
33
+
12
34
  class << self
35
+ attr_reader :mutex
36
+
37
+ def clear_stores
38
+ @stores = {}
39
+ end
40
+
13
41
  def stores
14
- @@stores ||= Store.new(Store::Redis.new(::Redis.new(host: ENV["PROGRESSRUS_REDIS_HOST"] || "localhost")))
42
+ mutex.synchronize do
43
+ @stores ||= {
44
+ redis: Store::Redis.new(::Redis.new(host: ENV["PROGRESSRUS_REDIS_HOST"] || "localhost"))
45
+ }
46
+ end
15
47
  end
16
48
 
17
- def scope(scope, store: :first)
18
- stores.find_by_name(store).scope(scope)
49
+ def add_store(name, store)
50
+ validate_store!(store)
51
+ stores[name] = store
52
+ end
53
+
54
+ def scope(scope, store: :redis)
55
+ stores[store].scope(scope)
19
56
  end
20
57
  alias_method :all, :scope
21
58
 
22
- def find(scope, id, store: :first)
23
- stores.find_by_name(store).find(scope, id)
59
+ def find(scope, id, store: :redis)
60
+ stores[store].find(scope, id)
61
+ end
62
+
63
+ def flush(scope, id = nil, store: :redis)
64
+ stores[store].flush(scope, id)
24
65
  end
25
66
 
26
- def flush(scope, id = nil, store: :first)
27
- stores.find_by_name(store).flush(scope, id)
67
+ private
68
+
69
+ def validate_store!(store)
70
+ valid = Store::Base.new.public_methods(false).all? do |method|
71
+ store.respond_to?(method)
72
+ end
73
+ raise InvalidStoreError unless valid
28
74
  end
29
75
  end
30
76
 
@@ -38,7 +84,7 @@ class Progressrus
38
84
  attr_writer :params
39
85
 
40
86
  def initialize(scope: "progressrus", total: nil, name: nil,
41
- id: SecureRandom.uuid, params: {}, stores: Progressrus.stores,
87
+ id: SecureRandom.uuid, params: {}, stores: nil,
42
88
  completed_at: nil, started_at: nil, count: 0, failed_at: nil,
43
89
  error_count: 0, persist: false, expires_at: nil, persisted: false)
44
90
 
@@ -49,7 +95,7 @@ class Progressrus
49
95
  @total = total
50
96
  @id = id
51
97
  @params = params
52
- @stores = stores
98
+ @stores = extract_stores(stores)
53
99
  @count = count
54
100
  @error_count = error_count
55
101
 
@@ -84,7 +130,7 @@ class Progressrus
84
130
  end
85
131
 
86
132
  def flush
87
- stores.each { |store| store.flush(scope, id) }
133
+ stores.each_value { |store| store.flush(scope, id) }
88
134
  end
89
135
 
90
136
  def status
@@ -160,11 +206,23 @@ class Progressrus
160
206
 
161
207
  private
162
208
 
209
+ def extract_stores(stores)
210
+ return Progressrus.stores unless stores
211
+
212
+ Array(stores).each_with_object({}) do |store, hash|
213
+ stored_found = Progressrus.stores[store]
214
+ raise StoreNotFoundError, store unless stored_found
215
+
216
+ hash[store] = stored_found
217
+ end
218
+ end
219
+
163
220
  def persist(force: false)
164
- stores.each do |store|
221
+ stores.each_value do |store|
165
222
  begin
166
223
  store.persist(self, force: force, expires_at: expires_at)
167
- rescue Progressrus::Store::BackendError => e
224
+ rescue Progressrus::Store::BackendError
225
+ # noop
168
226
  end
169
227
  end
170
228
  @persisted = true
@@ -1,5 +1,5 @@
1
1
  module Enumerable
2
- def with_progress(**args, &block)
2
+ def with_progress(args = {}, &block)
3
3
  if block_given?
4
4
  progresser = progress(args)
5
5
  begin
@@ -25,7 +25,7 @@ module Enumerable
25
25
  # Lazily read the size, for some enumerable this may be quite expensive and
26
26
  # using this method should come with a warning in the documentation.
27
27
  total = self.size unless args[:total]
28
- @progress = Progressrus.new({total: total}.merge(args))
28
+ @progress = Progressrus.new(total: total, **args)
29
29
  end
30
30
  end
31
31
  end
@@ -3,7 +3,7 @@ class Progressrus
3
3
  class Redis < Base
4
4
  BACKEND_EXCEPTIONS = [ ::Redis::BaseError ]
5
5
 
6
- attr_reader :redis, :interval, :persisted_at, :prefix, :name
6
+ attr_reader :redis, :interval, :prefix, :name
7
7
 
8
8
  def initialize(instance, prefix: "progressrus", interval: 1, now: Time.now)
9
9
  @name = :redis
@@ -31,7 +31,7 @@ class Progressrus
31
31
  def scope(scope)
32
32
  scope = redis.hgetall(key(scope))
33
33
  scope.each_pair { |id, value|
34
- scope[id] = Progressrus.new(deserialize(value))
34
+ scope[id] = Progressrus.new(**deserialize(value))
35
35
  }
36
36
  rescue *BACKEND_EXCEPTIONS => e
37
37
  raise Progressrus::Store::BackendError.new(e)
@@ -41,7 +41,7 @@ class Progressrus
41
41
  value = redis.hget(key(scope), id)
42
42
  return unless value
43
43
 
44
- Progressrus.new(deserialize(value))
44
+ Progressrus.new(**deserialize(value))
45
45
  rescue *BACKEND_EXCEPTIONS => e
46
46
  raise Progressrus::Store::BackendError.new(e)
47
47
  end
@@ -59,7 +59,11 @@ class Progressrus
59
59
  private
60
60
 
61
61
  def key(scope)
62
- "#{prefix}:#{scope.join(":")}"
62
+ if prefix.respond_to?(:call)
63
+ prefix.call(scope)
64
+ else
65
+ "#{prefix}:#{scope.join(":")}"
66
+ end
63
67
  end
64
68
 
65
69
  def deserialize(value)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Progressrus
2
- VERSION = "0.1.6"
4
+ VERSION = '1.0.2'
3
5
  end
@@ -18,10 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "redis", "~> 3.0"
21
+ spec.add_dependency "redis", ">= 3.0"
22
22
  spec.add_dependency "ruby-progressbar", "~> 1.0"
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.3"
25
24
  spec.add_development_dependency "rake"
26
25
  spec.add_development_dependency "mocha", "~> 0.14"
27
26
  spec.add_development_dependency "pry"
@@ -7,7 +7,7 @@ namespace :progressrus do
7
7
  task :flush, :environment do |t, args|
8
8
  scope = *args
9
9
  raise ArgumentError.new("Must pass [scope] to progressrus:store:flush[scope(,parts)] task.") unless scope.length > 0
10
- Progressrus.stores.first.flush(scope) if Progressrus.stores.first
10
+ Progressrus.stores[:redis].flush(scope) if Progressrus.stores[:redis]
11
11
  end
12
12
  end
13
13
  end
@@ -6,7 +6,7 @@ class IntegrationTest < Minitest::Test
6
6
  end
7
7
 
8
8
  def teardown
9
- Progressrus.stores.first.flush(@progress.scope)
9
+ Progressrus.stores[:redis].flush(@progress.scope)
10
10
  end
11
11
 
12
12
  def test_create_tick_and_see_status_in_redis
@@ -6,16 +6,23 @@ class ProgressrusTest < Minitest::Test
6
6
  end
7
7
 
8
8
  def teardown
9
- Progressrus.stores.default!
9
+ Progressrus.clear_stores
10
+ Progressrus.add_store(:redis, Progressrus::Store::Redis.new(::Redis.new(host: ENV["PROGRESSRUS_REDIS_HOST"] || "localhost")))
10
11
  end
11
12
 
12
13
  def test_defaults_to_redis_store
13
- assert_instance_of Progressrus::Store::Redis, Progressrus.stores.first
14
+ assert_instance_of Progressrus::Store::Redis, Progressrus.stores[:redis]
14
15
  end
15
16
 
16
17
  def test_add_to_store
17
- Progressrus.stores << Progressrus::Store::Base.new
18
- assert_instance_of Progressrus::Store::Base, Progressrus.stores[1]
18
+ Progressrus.add_store(:test, Progressrus::Store::Base.new)
19
+ assert_instance_of Progressrus::Store::Base, Progressrus.stores[:test]
20
+ end
21
+
22
+ def test_add_store_raise_error_when_invalid_store
23
+ assert_raises(Progressrus::InvalidStoreError) do
24
+ Progressrus.add_store(:test, mock)
25
+ end
19
26
  end
20
27
 
21
28
  def test_scope_should_initialize_with_symbol_or_string
@@ -33,6 +40,37 @@ class ProgressrusTest < Minitest::Test
33
40
  assert_equal 'Wally', progressrus.name
34
41
  end
35
42
 
43
+ def test_not_passing_stores_default_to_all_stores
44
+ progressrus = Progressrus.new(scope: ['walruses', 1])
45
+ assert_equal Progressrus.stores, progressrus.stores
46
+ end
47
+
48
+ def test_passing_stores
49
+ mysql = mock_store
50
+ Progressrus.add_store(:mysql, mysql)
51
+ progressrus = Progressrus.new(scope: ['walruses', 1], stores: :mysql)
52
+ assert_equal({ mysql: mysql }, progressrus.stores)
53
+ end
54
+
55
+ def test_passing_multiple_stores
56
+ Progressrus.clear_stores
57
+
58
+ mysql = mock_store
59
+ redis = mock_store
60
+
61
+ Progressrus.add_store(:mysql, mysql)
62
+ Progressrus.add_store(:redis, redis)
63
+
64
+ progressrus = Progressrus.new(scope: ['walruses', 1], stores: %i(mysql redis))
65
+ assert_equal({ mysql: mysql, redis: redis }, progressrus.stores)
66
+ end
67
+
68
+ def test_passing_non_existing_store_raises_error
69
+ assert_raises(Progressrus::StoreNotFoundError) do
70
+ Progressrus.new(scope: ['walruses', 1], stores: :not_found)
71
+ end
72
+ end
73
+
36
74
  def test_initialize_without_name_should_use_id
37
75
  progressrus = Progressrus.new(id: 'oemg')
38
76
  assert_equal 'oemg', progressrus.name
@@ -196,19 +234,20 @@ class ProgressrusTest < Minitest::Test
196
234
  end
197
235
 
198
236
  def test_persist_yields_persist_to_each_store
199
- mysql = mock()
237
+ mysql = mock_store
200
238
  mysql.expects(:persist).once
201
239
 
202
- redis = Progressrus.stores.first
240
+ redis = Progressrus.stores[:redis]
203
241
  redis.expects(:persist).once
204
242
 
205
- Progressrus.stores << mysql
243
+ Progressrus.add_store(:mysql, mysql)
206
244
 
207
- @progress.tick
245
+ progress = Progressrus.new(scope: :progressrus, total: 100)
246
+ progress.tick
208
247
  end
209
248
 
210
249
  def test_tick_and_complete_dont_raise_if_store_is_unavailable
211
- store = Progressrus.stores.first
250
+ store = Progressrus.stores[:redis]
212
251
  store.redis.expects(:hset).at_least_once.raises(::Redis::BaseError)
213
252
  @progress.tick
214
253
  @progress.complete
@@ -234,47 +273,32 @@ class ProgressrusTest < Minitest::Test
234
273
  end
235
274
 
236
275
 
237
- def test_default_scope_on_first
238
- Progressrus.stores.clear
239
-
240
- mysql = mock()
241
- redis = mock()
242
-
243
- Progressrus.stores << mysql
244
- Progressrus.stores << redis
245
-
246
- mysql.expects(:scope).once
247
- redis.expects(:scope).never
248
-
249
- Progressrus.scope(["oemg"])
250
- end
276
+ def test_default_scope_redis_store
277
+ Progressrus.clear_stores
251
278
 
252
- def test_support_scope_last
253
- Progressrus.stores.clear
279
+ mysql = mock_store
280
+ redis = mock_store
254
281
 
255
- mysql = mock()
256
- redis = mock()
257
-
258
- Progressrus.stores << mysql
259
- Progressrus.stores << redis
282
+ Progressrus.add_store(:mysql, mysql)
283
+ Progressrus.add_store(:redis, redis)
260
284
 
261
285
  mysql.expects(:scope).never
262
286
  redis.expects(:scope).once
263
287
 
264
- Progressrus.scope(["oemg"], store: :last)
288
+ Progressrus.scope(["oemg"])
265
289
  end
266
290
 
267
291
  def test_support_scope_by_name
268
- Progressrus.stores.clear
292
+ Progressrus.clear_stores
269
293
 
270
- mysql = mock()
271
- redis = mock()
294
+ mysql = mock_store
295
+ redis = mock_store
272
296
 
273
297
  mysql.stubs(:name).returns(:mysql)
274
298
  redis.stubs(:name).returns(:redis)
275
299
 
276
- Progressrus.stores << mysql
277
- Progressrus.stores << redis
300
+ Progressrus.add_store(:mysql, mysql)
301
+ Progressrus.add_store(:redis, redis)
278
302
 
279
303
  mysql.expects(:scope).never
280
304
  redis.expects(:scope).once
@@ -427,4 +451,10 @@ class ProgressrusTest < Minitest::Test
427
451
 
428
452
  refute progress.expired?(now: time)
429
453
  end
454
+
455
+ private
456
+
457
+ def mock_store
458
+ Progressrus::Store::Base.new
459
+ end
430
460
  end
@@ -1,6 +1,11 @@
1
1
  require_relative "../test_helper"
2
2
 
3
3
  class RedisStoreTest < Minitest::Test
4
+ class PrefixClass
5
+ def self.call(scope)
6
+ "custom_prefix:#{scope.join(':')}"
7
+ end
8
+ end
4
9
  def setup
5
10
  @scope = ["walrus", "1234"]
6
11
  @progress = Progressrus.new(
@@ -17,11 +22,19 @@ class RedisStoreTest < Minitest::Test
17
22
  name: "oemg-name-two"
18
23
  )
19
24
 
20
- @store = Progressrus::Store::Redis.new(::Redis.new(host: ENV["PROGRESSRUS_REDIS_HOST"] || "localhost"))
25
+ @redis = ::Redis.new(host: ENV["PROGRESSRUS_REDIS_HOST"] || "localhost")
26
+
27
+ @store = Progressrus::Store::Redis.new(@redis)
21
28
  end
22
29
 
23
30
  def teardown
24
- @store.flush(@scope)
31
+ @store.flush(@scope)
32
+ end
33
+
34
+ def test_prefix_can_be_a_proc
35
+ store = Progressrus::Store::Redis.new(@redis, prefix: PrefixClass)
36
+ store.persist(@progress)
37
+ refute_empty(@redis.hgetall('custom_prefix:walrus:1234'))
25
38
  end
26
39
 
27
40
  def test_persist_should_set_key_value_if_outdated
@@ -99,5 +112,4 @@ class RedisStoreTest < Minitest::Test
99
112
  @store.persist(@progress)
100
113
  @store.persist(@progress, force: true)
101
114
  end
102
-
103
115
  end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: progressrus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Eskildsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2020-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
27
  - !ruby/object:Gem::Dependency
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.3'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.3'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -153,7 +139,6 @@ files:
153
139
  - lib/progressrus/core_ext/enumerable.rb
154
140
  - lib/progressrus/railtie.rb
155
141
  - lib/progressrus/server.rb
156
- - lib/progressrus/store.rb
157
142
  - lib/progressrus/store/base.rb
158
143
  - lib/progressrus/store/progressbar.rb
159
144
  - lib/progressrus/store/redis.rb
@@ -185,8 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
170
  - !ruby/object:Gem::Version
186
171
  version: '0'
187
172
  requirements: []
188
- rubyforge_project:
189
- rubygems_version: 2.6.14
173
+ rubygems_version: 3.0.3
190
174
  signing_key:
191
175
  specification_version: 4
192
176
  summary: Monitor the progress of remote, long-running jobs.
@@ -1,24 +0,0 @@
1
- class Progressrus
2
- class Store < Array
3
- def initialize(default)
4
- @default = default
5
- self << default
6
- end
7
-
8
- def default
9
- @default
10
- end
11
-
12
- def default!
13
- clear
14
- self << default
15
- end
16
-
17
- def find_by_name(name)
18
- return first if name == :first
19
- return last if name == :last
20
-
21
- find { |store| store.name == name }
22
- end
23
- end
24
- end