progressrus 0.1.8 → 1.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1e63f1c18708a23b56833afb791eaf7bc27e05243fd4abbd65290e3100d5bf8
4
- data.tar.gz: 5387f3c957800d8292ea2f5ebb81b7e5fdacb3a4d045c0f9b2fb14686256f97f
3
+ metadata.gz: d353cca4bf4eca46acd2837f9e62f6dbe35834cd3efe00bf66ece1c02a2924d0
4
+ data.tar.gz: 2b8c0dc2e6ec18c4f22b3a911bedfbcd73232517c4576dcc4971c46fc7abaabb
5
5
  SHA512:
6
- metadata.gz: a5039104d899d32e43c908213170555ef5ab1b7031af6099497328195d6985643725c4b09cbd5411edbce03769cd98fcd368e2eca54a79ad78e86a471ba99a01
7
- data.tar.gz: 5ff5e57e00cd6ff54bc35479047a0d40ae41691fb34324697600f5c4c47b983128bc64e1165102f6e3d187f76aeaffa4e6d6920ca92c5adffd3b573d88711b77
6
+ metadata.gz: d1b1f0472d3ed65a214a020433315f7dd9cc37618fe992125e9a8836b320e0b92cc3adb5dca28f9109f15bb670abf6392a9493df3e7bd5921b9206f78e9d0b3c
7
+ data.tar.gz: 9823e1025dff167ffc79e33d12cc636fd5494a23cf5c97500fb655eb69a5aabbb0df45518ed8928f11ac41cf8b62f9f0f196d125cde2f3f98b0e5e3980206e21
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby: ["2.6", "2.7", "3.0", "3.1"]
17
+ services:
18
+ redis:
19
+ image: redis
20
+ options: >-
21
+ --health-cmd "redis-cli ping"
22
+ --health-interval 10s
23
+ --health-timeout 5s
24
+ --health-retries 5
25
+ ports:
26
+ - 6379:6379
27
+
28
+ steps:
29
+ - uses: actions/checkout@v2
30
+ - name: Set up Ruby
31
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
32
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
33
+ uses: ruby/setup-ruby@v1
34
+ with:
35
+ bundler-cache: true # 'bundle install' and cache gems
36
+ ruby-version: ${{ matrix.ruby }}
37
+ - name: Run tests
38
+ run: bundle exec rake
@@ -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
@@ -17,9 +17,9 @@ class Progressrus
17
17
  if outdated?(progress) || force
18
18
  key_for_scope = key(progress.scope)
19
19
 
20
- redis.pipelined do
21
- redis.hset(key_for_scope, progress.id, progress.to_serializeable.to_json)
22
- redis.expireat(key_for_scope, expires_at.to_i) if expires_at
20
+ redis.pipelined do |pipeline|
21
+ pipeline.hset(key_for_scope, progress.id, progress.to_serializeable.to_json)
22
+ pipeline.expireat(key_for_scope, expires_at.to_i) if expires_at
23
23
  end
24
24
 
25
25
  @persisted_ats[progress.scope][progress.id] = now
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Progressrus
4
- VERSION = '0.1.8'
4
+ VERSION = '1.0.3'
5
5
  end
data/lib/progressrus.rb CHANGED
@@ -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,8 +206,19 @@ 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
224
  rescue Progressrus::Store::BackendError
@@ -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
@@ -44,7 +44,7 @@ class IntegrationTest < Minitest::Test
44
44
  end
45
45
 
46
46
  def test_tick_on_enumerable
47
- a = (0..10)
47
+ a = (0..10).to_a
48
48
  b = a.with_progress(scope: "walrus").map(&:to_i)
49
49
 
50
50
  ticks = Progressrus.scope(["walrus"]).values
@@ -57,7 +57,7 @@ class IntegrationTest < Minitest::Test
57
57
  end
58
58
 
59
59
  def test_tick_on_enumerable_calls_fail_on_exception
60
- a = (0..10)
60
+ a = (0..10).to_a
61
61
 
62
62
  assert_raises ArgumentError do
63
63
  a.with_progress(scope: "walrus").each do
@@ -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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: progressrus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Eskildsen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-03 00:00:00.000000000 Z
11
+ date: 2022-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -129,8 +129,8 @@ executables: []
129
129
  extensions: []
130
130
  extra_rdoc_files: []
131
131
  files:
132
+ - ".github/workflows/ci.yml"
132
133
  - ".gitignore"
133
- - ".travis.yml"
134
134
  - Gemfile
135
135
  - LICENSE.txt
136
136
  - README.md
@@ -139,7 +139,6 @@ files:
139
139
  - lib/progressrus/core_ext/enumerable.rb
140
140
  - lib/progressrus/railtie.rb
141
141
  - lib/progressrus/server.rb
142
- - lib/progressrus/store.rb
143
142
  - lib/progressrus/store/base.rb
144
143
  - lib/progressrus/store/progressbar.rb
145
144
  - lib/progressrus/store/redis.rb
@@ -156,7 +155,7 @@ homepage: https://github.com/Sirupsen/progressrus
156
155
  licenses:
157
156
  - MIT
158
157
  metadata: {}
159
- post_install_message:
158
+ post_install_message:
160
159
  rdoc_options: []
161
160
  require_paths:
162
161
  - lib
@@ -171,8 +170,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
170
  - !ruby/object:Gem::Version
172
171
  version: '0'
173
172
  requirements: []
174
- rubygems_version: 3.0.3
175
- signing_key:
173
+ rubygems_version: 3.3.3
174
+ signing_key:
176
175
  specification_version: 4
177
176
  summary: Monitor the progress of remote, long-running jobs.
178
177
  test_files:
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- language: ruby
2
- services:
3
- - redis-server
4
- rvm:
5
- - 2.3
6
- - 2.4
7
- - 2.5
@@ -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