always 0.0.1 → 0.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: 95841105f15ff9ce3bbaf1e683874442ac7b6001470cbb001800461bdbfcac08
4
- data.tar.gz: 2bd3f82bd21442bbb0649e6178855cb3a92655e1de9092e8428efeada20eb824
3
+ metadata.gz: ed19cd7a3109c141b0537f2229876cc00f5d0a70740095b810b281c47fe44834
4
+ data.tar.gz: 793763757135f8492edb8bb6b6abb6b9ee19459c7e35d3acde3ac13f0c97a230
5
5
  SHA512:
6
- metadata.gz: 72fcd1877695615e951d78a68caaece60904ac76c6668a80fb4d7f00a5f23514b575ef1499c9fef57e3162368df7b96a3df5280eb531469339a7f5fdaedbb6ce
7
- data.tar.gz: d11c2fc0c61a531dfb20826b9daa760c4da5f214f030a2024086e9b23367acaf3e98c4d6ffebf009986b85cc78557e296ffd752d630b77679d4e29f1dfd233e8
6
+ metadata.gz: 3c09324fe351d257d252e466e9be7d263ffb0e9781d1134b777ae207ee0321779273b82771d595fad47f4ca67ed2bebbc4a8864758c0f522f0233f66b5745b79
7
+ data.tar.gz: 44c0a7f8d9117e69845c58577b6f40ccd29f7292e07c9df0cc18a05870a3fb4b5795c85cc0bfcd5434c543ed5575a081b35de6cc7a402ef59d70459ac87659de
data/Gemfile CHANGED
@@ -23,15 +23,11 @@
23
23
  source 'https://rubygems.org'
24
24
  gemspec
25
25
 
26
- gem 'cucumber', '9.2.0', require: false
27
26
  gem 'minitest', '5.23.1', require: false
28
- gem 'net-ping', '2.0.8', require: false
29
27
  gem 'rake', '13.2.1', require: false
30
28
  gem 'rspec-rails', '6.1.2', require: false
31
- gem 'rubocop', '1.64.0', require: false
32
- gem 'rubocop-performance', '1.21.0', require: false
29
+ gem 'rubocop', '1.64.1', require: false
33
30
  gem 'rubocop-rspec', '2.29.2', require: false
34
31
  gem 'simplecov', '0.22.0', require: false
35
32
  gem 'simplecov-cobertura', '2.1.0', require: false
36
- gem 'webmock', '3.23.1', require: false
37
33
  gem 'yard', '0.9.36', require: false
data/Gemfile.lock CHANGED
@@ -2,6 +2,7 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  always (0.0.0)
5
+ concurrent-ruby (~> 1.1)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
@@ -32,50 +33,17 @@ GEM
32
33
  minitest (>= 5.1)
33
34
  mutex_m
34
35
  tzinfo (~> 2.0)
35
- addressable (2.8.6)
36
- public_suffix (>= 2.0.2, < 6.0)
37
36
  ast (2.4.2)
38
37
  base64 (0.2.0)
39
38
  bigdecimal (3.1.8)
40
39
  builder (3.2.4)
41
- concurrent-ruby (1.2.3)
40
+ concurrent-ruby (1.3.1)
42
41
  connection_pool (2.4.1)
43
- crack (1.0.0)
44
- bigdecimal
45
- rexml
46
42
  crass (1.0.6)
47
- cucumber (9.2.0)
48
- builder (~> 3.2)
49
- cucumber-ci-environment (> 9, < 11)
50
- cucumber-core (> 13, < 14)
51
- cucumber-cucumber-expressions (~> 17.0)
52
- cucumber-gherkin (> 24, < 28)
53
- cucumber-html-formatter (> 20.3, < 22)
54
- cucumber-messages (> 19, < 25)
55
- diff-lcs (~> 1.5)
56
- mini_mime (~> 1.1)
57
- multi_test (~> 1.1)
58
- sys-uname (~> 1.2)
59
- cucumber-ci-environment (10.0.1)
60
- cucumber-core (13.0.2)
61
- cucumber-gherkin (>= 27, < 28)
62
- cucumber-messages (>= 20, < 23)
63
- cucumber-tag-expressions (> 5, < 7)
64
- cucumber-cucumber-expressions (17.1.0)
65
- bigdecimal
66
- cucumber-gherkin (27.0.0)
67
- cucumber-messages (>= 19.1.4, < 23)
68
- cucumber-html-formatter (21.3.1)
69
- cucumber-messages (> 19, < 25)
70
- cucumber-messages (22.0.0)
71
- cucumber-tag-expressions (6.1.0)
72
43
  diff-lcs (1.5.1)
73
44
  docile (1.4.0)
74
45
  drb (2.2.1)
75
46
  erubi (1.12.0)
76
- ffi (1.16.3)
77
- ffi (1.16.3-x64-mingw-ucrt)
78
- hashdiff (1.1.0)
79
47
  i18n (1.14.5)
80
48
  concurrent-ruby (~> 1.0)
81
49
  io-console (0.7.2)
@@ -87,11 +55,8 @@ GEM
87
55
  loofah (2.22.0)
88
56
  crass (~> 1.0.2)
89
57
  nokogiri (>= 1.12.0)
90
- mini_mime (1.1.5)
91
58
  minitest (5.23.1)
92
- multi_test (1.1.0)
93
59
  mutex_m (0.2.0)
94
- net-ping (2.0.8)
95
60
  nokogiri (1.16.5-aarch64-linux)
96
61
  racc (~> 1.4)
97
62
  nokogiri (1.16.5-arm-linux)
@@ -112,7 +77,6 @@ GEM
112
77
  racc
113
78
  psych (5.1.2)
114
79
  stringio
115
- public_suffix (5.0.5)
116
80
  racc (1.8.0)
117
81
  rack (3.0.11)
118
82
  rack-session (2.0.0)
@@ -163,7 +127,7 @@ GEM
163
127
  rspec-mocks (~> 3.13)
164
128
  rspec-support (~> 3.13)
165
129
  rspec-support (3.13.1)
166
- rubocop (1.64.0)
130
+ rubocop (1.64.1)
167
131
  json (~> 2.3)
168
132
  language_server-protocol (>= 3.17.0)
169
133
  parallel (~> 1.10)
@@ -180,9 +144,6 @@ GEM
180
144
  rubocop (~> 1.41)
181
145
  rubocop-factory_bot (2.25.1)
182
146
  rubocop (~> 1.41)
183
- rubocop-performance (1.21.0)
184
- rubocop (>= 1.48.1, < 2.0)
185
- rubocop-ast (>= 1.31.1, < 2.0)
186
147
  rubocop-rspec (2.29.2)
187
148
  rubocop (~> 1.40)
188
149
  rubocop-capybara (~> 2.17)
@@ -202,16 +163,10 @@ GEM
202
163
  simplecov_json_formatter (0.1.4)
203
164
  stringio (3.1.0)
204
165
  strscan (3.1.0)
205
- sys-uname (1.2.3)
206
- ffi (~> 1.1)
207
166
  thor (1.3.1)
208
167
  tzinfo (2.0.6)
209
168
  concurrent-ruby (~> 1.0)
210
169
  unicode-display_width (2.5.0)
211
- webmock (3.23.1)
212
- addressable (>= 2.8.0)
213
- crack (>= 0.3.2)
214
- hashdiff (>= 0.4.0, < 2.0.0)
215
170
  webrick (1.8.1)
216
171
  yard (0.9.36)
217
172
  zeitwerk (2.6.15)
@@ -227,17 +182,13 @@ PLATFORMS
227
182
 
228
183
  DEPENDENCIES
229
184
  always!
230
- cucumber (= 9.2.0)
231
185
  minitest (= 5.23.1)
232
- net-ping (= 2.0.8)
233
186
  rake (= 13.2.1)
234
187
  rspec-rails (= 6.1.2)
235
- rubocop (= 1.64.0)
236
- rubocop-performance (= 1.21.0)
188
+ rubocop (= 1.64.1)
237
189
  rubocop-rspec (= 2.29.2)
238
190
  simplecov (= 0.22.0)
239
191
  simplecov-cobertura (= 2.1.0)
240
- webmock (= 3.23.1)
241
192
  yard (= 0.9.36)
242
193
 
243
194
  BUNDLED WITH
data/always.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=3.2'
28
28
  s.name = 'always'
29
- s.version = '0.0.1'
29
+ s.version = '0.0.3'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'A simple Ruby framework that spins a loop forever, in a background thread'
32
32
  s.description =
@@ -40,5 +40,6 @@ Gem::Specification.new do |s|
40
40
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
41
41
  s.rdoc_options = ['--charset=UTF-8']
42
42
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
43
+ s.add_runtime_dependency 'concurrent-ruby', '~>1.1'
43
44
  s.metadata['rubygems_mfa_required'] = 'true'
44
45
  end
data/lib/always.rb CHANGED
@@ -20,50 +20,101 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ require 'concurrent/atom'
24
+
23
25
  # Always.
26
+ #
27
+ # In order to start five threads performing the same piece of code
28
+ # over and over again, with a 60-seconds pause between cycles, do this:
29
+ #
30
+ # require 'always'
31
+ # a = Always.new(5)
32
+ # a.start(60) do
33
+ # puts 'Hello, world!
34
+ # end
35
+ #
36
+ # Then, in order stop them all together:
37
+ #
38
+ # a.stop
39
+ #
40
+ # It's possible to get a quick summary of the thread pool, by calling +to_s+.
41
+ #
24
42
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
25
43
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
26
44
  # License:: MIT
27
45
  class Always
28
46
  # The version of the framework.
29
- VERSION = '0.0.1'
47
+ VERSION = '0.0.3'
30
48
 
31
49
  # Constructor.
32
- def initialize(total, pause = 0)
50
+ # @param [Integer] total The number of threads to run
51
+ def initialize(total)
52
+ raise "The number of threads (#{total}) must be positive" unless total.positive?
53
+
33
54
  @total = total
34
- @pause = pause
35
55
  @on_error = nil
36
56
  @threads = []
57
+ @cycles = Concurrent::Atom.new(0)
58
+ @errors = Concurrent::Atom.new(0)
37
59
  end
38
60
 
39
61
  # What to do when an exception occurs?
62
+ #
63
+ # Call it like this (the +e+ provided is the exception and +i+ is the
64
+ # number of the thread where it occured):
65
+ #
66
+ # a = Always.new(5)
67
+ # a.on_error do |e, i|
68
+ # puts e.message
69
+ # end
70
+ #
71
+ # If the block that you provided will also throw an error, it will
72
+ # simply be ignored (not logged anywhere, just ignored!)
73
+ # @return [Always] Returns itself
40
74
  def on_error(&block)
41
75
  @on_error = block
76
+ self
42
77
  end
43
78
 
44
- def start
79
+ # Start them all.
80
+ # @param [Integer] pause The delay between cycles, in seconds
81
+ def start(pause = 0, &)
82
+ raise 'It is running now, call .stop() first' unless @threads.empty?
83
+
45
84
  (0..@total - 1).each do |i|
46
85
  @threads[i] = Thread.new do
47
- body(i)
86
+ body(i, pause, &)
87
+ @cycles.swap { |c| c + 1 }
48
88
  end
49
89
  end
50
90
  end
51
91
 
92
+ # Stop them all.
52
93
  def stop
53
94
  @threads.each(&:terminate)
95
+ @threads = []
96
+ end
97
+
98
+ # Represent its internal state as a string.
99
+ # @return [String] Something like "4/230/23", where 4 is the number of running
100
+ # threads, 230 is the number of successfull loops, and 23 is the number
101
+ # of failures occured so far.
102
+ def to_s
103
+ "#{@threads.size}/#{@cycles.value}/#{@errors.value}"
54
104
  end
55
105
 
56
106
  private
57
107
 
58
108
  # rubocop:disable Lint/RescueException
59
- def body(idx)
109
+ def body(idx, pause)
60
110
  loop do
61
111
  begin
62
112
  yield
63
113
  rescue Exception => e
114
+ @errors.swap { |c| c + 1 }
64
115
  @on_error&.call(e, idx)
65
116
  end
66
- sleep(@pause)
117
+ sleep(pause)
67
118
  rescue Exception
68
119
  # If we reach this point, we must not even try to
69
120
  # do anything. Here we must quietly ignore everything
data/test/test_always.rb CHANGED
@@ -35,4 +35,35 @@ class TestAlways < Minitest::Test
35
35
  end
36
36
  a.stop
37
37
  end
38
+
39
+ def test_with_error
40
+ a = Always.new(5)
41
+ failures = 0
42
+ a.on_error { |_e, i| failures += i }.start do
43
+ raise 'intentionally'
44
+ end
45
+ sleep(0.1)
46
+ a.stop
47
+ assert(failures.positive?)
48
+ end
49
+
50
+ def test_converts_to_string
51
+ a = Always.new(5)
52
+ a.start do
53
+ # nothing
54
+ end
55
+ assert(a.to_s.start_with?('5/'))
56
+ a.stop
57
+ end
58
+
59
+ def test_with_counter
60
+ a = Always.new(1)
61
+ done = 0
62
+ a.start do
63
+ done += 1
64
+ end
65
+ sleep(0.1)
66
+ a.stop
67
+ assert(done.positive?)
68
+ end
38
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: always
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-05-31 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
13
27
  description: You may need this framework if you have a routine task that must be performed
14
28
  every once in a while, but may raise exceptions which you don't want to cause a
15
29
  termination of the entire routine cycle.