always 0.0.1 → 0.0.2

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: 95841105f15ff9ce3bbaf1e683874442ac7b6001470cbb001800461bdbfcac08
4
- data.tar.gz: 2bd3f82bd21442bbb0649e6178855cb3a92655e1de9092e8428efeada20eb824
3
+ metadata.gz: 1d5c02ea320168984342dcf8805da07bec45d9a685097400c9f3e406a75a96b9
4
+ data.tar.gz: 0db1ae1c2006db2de79982172f8fd7cc1d53e3fb8dfaffc8e474ea5972139224
5
5
  SHA512:
6
- metadata.gz: 72fcd1877695615e951d78a68caaece60904ac76c6668a80fb4d7f00a5f23514b575ef1499c9fef57e3162368df7b96a3df5280eb531469339a7f5fdaedbb6ce
7
- data.tar.gz: d11c2fc0c61a531dfb20826b9daa760c4da5f214f030a2024086e9b23367acaf3e98c4d6ffebf009986b85cc78557e296ffd752d630b77679d4e29f1dfd233e8
6
+ metadata.gz: 628d7ddcbc48d5e1b87adcccb7446a60c0ec1b4f1e047ee85b9a3188f76e3dbd42de40d384fc7e4f84de21c750ba26312b136d63a1248b575a1d3c2d68430a0a
7
+ data.tar.gz: d9e259a904b1785543bb0282f026b0ee08e7ec1b641ee2243bd23d063a99df90b9dc69c69438f6d36f09bc7351a893b32581d0f475b7761d9997d7f112afa75a
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.2'
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.2'
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,24 @@ 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
38
58
  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.2
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.