progressrus 0.1.8 → 1.0.3

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
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