random-port 0.7.6 → 0.8.1
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 +4 -4
- data/Gemfile +6 -2
- data/Gemfile.lock +42 -22
- data/LICENSE.txt +1 -1
- data/LICENSES/MIT.txt +1 -1
- data/README.md +11 -3
- data/Rakefile +16 -2
- data/lib/random-port/module.rb +13 -3
- data/lib/random-port/pool.rb +51 -39
- data/lib/random-port.rb +1 -1
- data/random-port.gemspec +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c6250d7a7a9a68ca737b299b7cef6b4816e35a6fe9452b78633c2df1132bd41
|
|
4
|
+
data.tar.gz: 9ec96d9ae9ce5e2f58c4bd3821f24877cfbc7a88913005d21a32c90d8f465b77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da1f7e7b9daeaf7a60fd935cbc8b0c578a352c558683a85f7c6d66c4a7ef391586a02b389107516c270d2a38215979aa8f4f6cdba5b70f7f128515cc21058a8c
|
|
7
|
+
data.tar.gz: bf6db1f8503993e5388b4cb48909f2684a0618eb26e4f5bc5677fe92b248c67a22e11f9ad8e9f5405223718d7f7287dc51ea50ffe47def18b6b8561ea3dab582
|
data/Gemfile
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
source 'https://rubygems.org'
|
|
7
7
|
gemspec
|
|
8
8
|
|
|
9
|
-
gem 'minitest', '~>
|
|
9
|
+
gem 'minitest', '~>6.0', require: false
|
|
10
|
+
gem 'minitest-mock', '~>5.27', require: false
|
|
11
|
+
gem 'minitest-reporters', '~>1.7', require: false
|
|
12
|
+
gem 'os', '~> 1.1', require: false
|
|
10
13
|
gem 'qbash', '~>0.2', require: false
|
|
11
14
|
gem 'rake', '~>13.2', require: false
|
|
12
15
|
gem 'rubocop', '~>1.75', require: false
|
|
@@ -15,5 +18,6 @@ gem 'rubocop-performance', '~>1.25', require: false
|
|
|
15
18
|
gem 'rubocop-rake', '~>0.7', require: false
|
|
16
19
|
gem 'rubocop-rspec', '~> 3.7', require: false
|
|
17
20
|
gem 'simplecov', '~>0.22', require: false
|
|
21
|
+
gem 'simplecov-cobertura', '~>3.0', require: false
|
|
18
22
|
gem 'threads', '~>0.4', require: false
|
|
19
23
|
gem 'yard', '~>0.9', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -7,35 +7,48 @@ PATH
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
+
ansi (1.5.0)
|
|
10
11
|
ast (2.4.3)
|
|
11
12
|
backtrace (0.4.1)
|
|
12
|
-
|
|
13
|
+
builder (3.3.0)
|
|
14
|
+
concurrent-ruby (1.3.6)
|
|
13
15
|
docile (1.4.1)
|
|
14
|
-
elapsed (0.
|
|
16
|
+
elapsed (0.3.1)
|
|
15
17
|
loog (~> 0.6)
|
|
16
18
|
tago (~> 0.1)
|
|
17
|
-
|
|
19
|
+
ellipsized (0.3.0)
|
|
20
|
+
json (2.18.1)
|
|
18
21
|
language_server-protocol (3.17.0.5)
|
|
19
22
|
lint_roller (1.1.0)
|
|
20
23
|
logger (1.7.0)
|
|
21
|
-
loog (0.
|
|
24
|
+
loog (0.8.0)
|
|
25
|
+
ellipsized
|
|
22
26
|
logger (~> 1.0)
|
|
23
|
-
minitest (
|
|
27
|
+
minitest (6.0.1)
|
|
28
|
+
prism (~> 1.5)
|
|
29
|
+
minitest-mock (5.27.0)
|
|
30
|
+
minitest-reporters (1.7.1)
|
|
31
|
+
ansi
|
|
32
|
+
builder
|
|
33
|
+
minitest (>= 5.0)
|
|
34
|
+
ruby-progressbar
|
|
35
|
+
os (1.1.4)
|
|
24
36
|
parallel (1.27.0)
|
|
25
|
-
parser (3.3.
|
|
37
|
+
parser (3.3.10.1)
|
|
26
38
|
ast (~> 2.4.1)
|
|
27
39
|
racc
|
|
28
|
-
prism (1.
|
|
29
|
-
qbash (0.
|
|
40
|
+
prism (1.9.0)
|
|
41
|
+
qbash (0.7.2)
|
|
30
42
|
backtrace (> 0)
|
|
31
43
|
elapsed (> 0)
|
|
32
44
|
loog (> 0)
|
|
33
45
|
tago (> 0)
|
|
34
46
|
racc (1.8.1)
|
|
35
47
|
rainbow (3.1.1)
|
|
36
|
-
rake (13.3.
|
|
48
|
+
rake (13.3.1)
|
|
37
49
|
regexp_parser (2.11.3)
|
|
38
|
-
|
|
50
|
+
rexml (3.4.4)
|
|
51
|
+
rubocop (1.84.1)
|
|
39
52
|
json (~> 2.3)
|
|
40
53
|
language_server-protocol (~> 3.17.0.2)
|
|
41
54
|
lint_roller (~> 1.1.0)
|
|
@@ -43,41 +56,44 @@ GEM
|
|
|
43
56
|
parser (>= 3.3.0.2)
|
|
44
57
|
rainbow (>= 2.2.2, < 4.0)
|
|
45
58
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
46
|
-
rubocop-ast (>= 1.
|
|
59
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
47
60
|
ruby-progressbar (~> 1.7)
|
|
48
61
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
49
|
-
rubocop-ast (1.
|
|
62
|
+
rubocop-ast (1.49.0)
|
|
50
63
|
parser (>= 3.3.7.2)
|
|
51
|
-
prism (~> 1.
|
|
64
|
+
prism (~> 1.7)
|
|
52
65
|
rubocop-minitest (0.38.2)
|
|
53
66
|
lint_roller (~> 1.1)
|
|
54
67
|
rubocop (>= 1.75.0, < 2.0)
|
|
55
68
|
rubocop-ast (>= 1.38.0, < 2.0)
|
|
56
|
-
rubocop-performance (1.26.
|
|
69
|
+
rubocop-performance (1.26.1)
|
|
57
70
|
lint_roller (~> 1.1)
|
|
58
71
|
rubocop (>= 1.75.0, < 2.0)
|
|
59
|
-
rubocop-ast (>= 1.
|
|
72
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
60
73
|
rubocop-rake (0.7.1)
|
|
61
74
|
lint_roller (~> 1.1)
|
|
62
75
|
rubocop (>= 1.72.1)
|
|
63
|
-
rubocop-rspec (3.
|
|
76
|
+
rubocop-rspec (3.9.0)
|
|
64
77
|
lint_roller (~> 1.1)
|
|
65
|
-
rubocop (~> 1.
|
|
78
|
+
rubocop (~> 1.81)
|
|
66
79
|
ruby-progressbar (1.13.0)
|
|
67
80
|
simplecov (0.22.0)
|
|
68
81
|
docile (~> 1.1)
|
|
69
82
|
simplecov-html (~> 0.11)
|
|
70
83
|
simplecov_json_formatter (~> 0.1)
|
|
84
|
+
simplecov-cobertura (3.1.0)
|
|
85
|
+
rexml
|
|
86
|
+
simplecov (~> 0.19)
|
|
71
87
|
simplecov-html (0.13.2)
|
|
72
88
|
simplecov_json_formatter (0.1.4)
|
|
73
|
-
tago (0.
|
|
74
|
-
threads (0.
|
|
89
|
+
tago (0.7.0)
|
|
90
|
+
threads (0.5.0)
|
|
75
91
|
backtrace (~> 0)
|
|
76
92
|
concurrent-ruby (~> 1.0)
|
|
77
93
|
unicode-display_width (3.2.0)
|
|
78
94
|
unicode-emoji (~> 4.1)
|
|
79
|
-
unicode-emoji (4.
|
|
80
|
-
yard (0.9.
|
|
95
|
+
unicode-emoji (4.2.0)
|
|
96
|
+
yard (0.9.38)
|
|
81
97
|
|
|
82
98
|
PLATFORMS
|
|
83
99
|
arm64-darwin-22
|
|
@@ -87,7 +103,10 @@ PLATFORMS
|
|
|
87
103
|
x86_64-linux
|
|
88
104
|
|
|
89
105
|
DEPENDENCIES
|
|
90
|
-
minitest (~>
|
|
106
|
+
minitest (~> 6.0)
|
|
107
|
+
minitest-mock (~> 5.27)
|
|
108
|
+
minitest-reporters (~> 1.7)
|
|
109
|
+
os (~> 1.1)
|
|
91
110
|
qbash (~> 0.2)
|
|
92
111
|
rake (~> 13.2)
|
|
93
112
|
random-port!
|
|
@@ -97,6 +116,7 @@ DEPENDENCIES
|
|
|
97
116
|
rubocop-rake (~> 0.7)
|
|
98
117
|
rubocop-rspec (~> 3.7)
|
|
99
118
|
simplecov (~> 0.22)
|
|
119
|
+
simplecov-cobertura (~> 3.0)
|
|
100
120
|
threads (~> 0.4)
|
|
101
121
|
yard (~> 0.9)
|
|
102
122
|
|
data/LICENSE.txt
CHANGED
data/LICENSES/MIT.txt
CHANGED
data/README.md
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
[](https://github.com/yegor256/random-port/actions/workflows/rake.yml)
|
|
7
7
|
[](https://badge.fury.io/rb/random-port)
|
|
8
|
-
[](https://codeclimate.com/github/yegor256/random-port/maintainability)
|
|
9
8
|
[](https://rubydoc.info/github/yegor256/random-port/master/frames)
|
|
10
9
|
[](https://github.com/yegor256/random-port/blob/master/LICENSE.txt)
|
|
11
10
|
[](https://codecov.io/github/yegor256/random-port?branch=master)
|
|
12
|
-
[](https://hitsofcode.com/view/github/random-port
|
|
11
|
+
[](https://hitsofcode.com/view/github/yegor256/random-port)
|
|
13
12
|
|
|
14
13
|
It's a simple Ruby gem to get a random TCP port.
|
|
15
14
|
|
|
@@ -52,6 +51,15 @@ RandomPort::Pool::SINGLETON.acquire do |port|
|
|
|
52
51
|
end
|
|
53
52
|
```
|
|
54
53
|
|
|
54
|
+
Or use shortened version, all methods called in `RandomPort`
|
|
55
|
+
will be delegated to `Pool::SINGLETON`:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
RandomPort.acquire do |port|
|
|
59
|
+
# Use it here...
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
55
63
|
The pool is thread-safe by default.
|
|
56
64
|
You can configure it to be
|
|
57
65
|
not-thread-safe, using optional `sync` argument of the constructor.
|
|
@@ -62,7 +70,7 @@ Read
|
|
|
62
70
|
[these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
|
|
63
71
|
Make sure your build is green before you contribute
|
|
64
72
|
your pull request. You will need to have
|
|
65
|
-
[Ruby](https://www.ruby-lang.org/en/)
|
|
73
|
+
[Ruby](https://www.ruby-lang.org/en/) 3.3+ and
|
|
66
74
|
[Bundler](https://bundler.io/) installed. Then:
|
|
67
75
|
|
|
68
76
|
```bash
|
data/Rakefile
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
+
require 'os'
|
|
7
|
+
require 'qbash'
|
|
6
8
|
require 'rubygems'
|
|
7
9
|
require 'rake'
|
|
8
10
|
require 'rake/clean'
|
|
11
|
+
require 'shellwords'
|
|
9
12
|
|
|
10
13
|
CLEAN << 'coverage'
|
|
11
14
|
|
|
@@ -17,7 +20,7 @@ def version
|
|
|
17
20
|
Gem::Specification.load(Dir['*.gemspec'].first).version
|
|
18
21
|
end
|
|
19
22
|
|
|
20
|
-
task default: %i[clean test yard rubocop]
|
|
23
|
+
task default: %i[clean test picks yard rubocop]
|
|
21
24
|
|
|
22
25
|
require 'rake/testtask'
|
|
23
26
|
desc 'Run all unit tests'
|
|
@@ -27,6 +30,16 @@ Rake::TestTask.new(:test) do |test|
|
|
|
27
30
|
test.verbose = false
|
|
28
31
|
end
|
|
29
32
|
|
|
33
|
+
desc 'Run them via Ruby, one by one'
|
|
34
|
+
task :picks do
|
|
35
|
+
next if OS.windows?
|
|
36
|
+
%w[test lib].each do |d|
|
|
37
|
+
Dir["#{d}/**/*.rb"].each do |f|
|
|
38
|
+
qbash("bundle exec ruby #{Shellwords.escape(f)}", stdout: $stdout, env: { 'PICKS' => 'yes' })
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
30
43
|
require 'rubocop/rake_task'
|
|
31
44
|
desc 'Run RuboCop on all directories'
|
|
32
45
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
|
@@ -37,4 +50,5 @@ require 'yard'
|
|
|
37
50
|
desc 'Build Yard documentation'
|
|
38
51
|
YARD::Rake::YardocTask.new do |t|
|
|
39
52
|
t.files = ['lib/**/*.rb']
|
|
53
|
+
t.options = ['--fail-on-warning']
|
|
40
54
|
end
|
data/lib/random-port/module.rb
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
require 'forwardable'
|
|
7
|
+
|
|
8
|
+
# Main module that contains all RandomPort classes and utilities.
|
|
9
|
+
#
|
|
10
|
+
# This module provides a simple way to acquire random TCP ports
|
|
11
|
+
# that are guaranteed to be available for use. It includes a Pool
|
|
12
|
+
# class that manages port allocation and ensures thread safety.
|
|
7
13
|
#
|
|
8
14
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
9
|
-
# Copyright:: Copyright (c) 2018-
|
|
15
|
+
# Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
10
16
|
# License:: MIT
|
|
11
17
|
module RandomPort
|
|
18
|
+
extend Forwardable
|
|
19
|
+
|
|
20
|
+
def_delegators :'RandomPort::Pool::SINGLETON', :acquire, :release, :count, :size, :empty?
|
|
21
|
+
module_function :acquire, :release, :count, :size, :empty?
|
|
12
22
|
end
|
data/lib/random-port/pool.rb
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
+
require 'minitest/mock'
|
|
6
7
|
require 'monitor'
|
|
7
8
|
require 'socket'
|
|
8
9
|
require 'tago'
|
|
9
10
|
require_relative 'module'
|
|
10
11
|
|
|
11
|
-
# Pool of
|
|
12
|
+
# Pool of TCP ports.
|
|
12
13
|
#
|
|
13
14
|
# Use it like this:
|
|
14
15
|
#
|
|
@@ -17,26 +18,27 @@ require_relative 'module'
|
|
|
17
18
|
# # to the pool afterwards.
|
|
18
19
|
# end
|
|
19
20
|
#
|
|
20
|
-
# You can specify the maximum
|
|
21
|
-
# If more
|
|
21
|
+
# You can specify the maximum number of ports to acquire using +limit+.
|
|
22
|
+
# If more acquisition requests arrive, an exception will be raised.
|
|
22
23
|
#
|
|
23
|
-
# The class is thread-safe
|
|
24
|
-
#
|
|
24
|
+
# The class is thread-safe by default. You can configure it to be
|
|
25
|
+
# non-thread-safe using the optional +sync+ argument of the constructor,
|
|
25
26
|
# passing <tt>FALSE</tt>.
|
|
26
27
|
#
|
|
27
28
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
28
|
-
# Copyright:: Copyright (c) 2018-
|
|
29
|
+
# Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
29
30
|
# License:: MIT
|
|
30
31
|
class RandomPort::Pool
|
|
31
|
-
#
|
|
32
|
+
# Raised when a port cannot be acquired within the timeout period.
|
|
32
33
|
class Timeout < StandardError; end
|
|
33
34
|
|
|
35
|
+
# @return [Integer] The maximum number of ports that can be acquired from this pool
|
|
34
36
|
attr_reader :limit
|
|
35
37
|
|
|
36
|
-
#
|
|
37
|
-
# @param [Boolean] sync Set
|
|
38
|
-
# @param [Integer] limit
|
|
39
|
-
# @param [Integer] start The
|
|
38
|
+
# Constructor.
|
|
39
|
+
# @param [Boolean] sync Set to FALSE if you want this pool to be non-thread-safe
|
|
40
|
+
# @param [Integer] limit The maximum number of ports that can be acquired from the pool
|
|
41
|
+
# @param [Integer] start The first port number to try when acquiring
|
|
40
42
|
def initialize(sync: true, limit: 65_536, start: 1025)
|
|
41
43
|
@ports = []
|
|
42
44
|
@sync = sync
|
|
@@ -45,27 +47,33 @@ class RandomPort::Pool
|
|
|
45
47
|
@next = start
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
# Application
|
|
50
|
+
# Application-wide singleton pool of ports.
|
|
49
51
|
SINGLETON = RandomPort::Pool.new
|
|
50
52
|
|
|
51
|
-
#
|
|
53
|
+
# Returns the number of ports currently acquired from the pool.
|
|
54
|
+
# @return [Integer] The count of acquired ports
|
|
52
55
|
def count
|
|
53
56
|
@ports.count
|
|
54
57
|
end
|
|
55
58
|
alias size count
|
|
56
59
|
|
|
57
|
-
#
|
|
60
|
+
# Checks if the pool is empty (no ports are currently acquired).
|
|
61
|
+
# @return [Boolean] TRUE if no ports are acquired, FALSE otherwise
|
|
58
62
|
def empty?
|
|
59
63
|
@ports.empty?
|
|
60
64
|
end
|
|
61
65
|
|
|
62
|
-
#
|
|
66
|
+
# Acquires one or more available TCP ports from the pool.
|
|
63
67
|
#
|
|
64
68
|
# You can specify the number of ports to acquire. If it's more than one,
|
|
65
|
-
# an array will be returned.
|
|
69
|
+
# an array will be returned. If a block is given, the port(s) will be
|
|
70
|
+
# automatically released after the block execution.
|
|
66
71
|
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
72
|
+
# @param [Integer] total The number of ports to acquire (default: 1)
|
|
73
|
+
# @param [Integer] timeout The maximum seconds to wait for port availability
|
|
74
|
+
# @yield [Integer|Array<Integer>] The acquired port(s)
|
|
75
|
+
# @return [Integer|Array<Integer>] The acquired port(s) if no block given
|
|
76
|
+
# @raise [Timeout] If ports cannot be acquired within the timeout period
|
|
69
77
|
def acquire(total = 1, timeout: 4)
|
|
70
78
|
start = Time.now
|
|
71
79
|
attempt = 0
|
|
@@ -77,7 +85,7 @@ class RandomPort::Pool
|
|
|
77
85
|
"(#{@ports.size} already occupied) " \
|
|
78
86
|
"for #{total} port(s), after #{attempt} attempts in #{start.ago}"
|
|
79
87
|
end
|
|
80
|
-
attempt +=
|
|
88
|
+
attempt += 1
|
|
81
89
|
opts = safe { group(total) }
|
|
82
90
|
if opts.nil?
|
|
83
91
|
@next += 1
|
|
@@ -96,9 +104,9 @@ class RandomPort::Pool
|
|
|
96
104
|
end
|
|
97
105
|
end
|
|
98
106
|
|
|
99
|
-
#
|
|
100
|
-
# @param [Integer] port TCP port number to release
|
|
101
|
-
# @return nil
|
|
107
|
+
# Releases one or more ports back to the pool.
|
|
108
|
+
# @param [Integer|Array<Integer>] port The TCP port number(s) to release
|
|
109
|
+
# @return [nil]
|
|
102
110
|
def release(port)
|
|
103
111
|
safe do
|
|
104
112
|
if port.is_a?(Array)
|
|
@@ -111,12 +119,12 @@ class RandomPort::Pool
|
|
|
111
119
|
|
|
112
120
|
private
|
|
113
121
|
|
|
114
|
-
#
|
|
115
|
-
# @param [Integer] total
|
|
116
|
-
# @return [Array<Integer>|nil]
|
|
122
|
+
# Attempts to acquire a contiguous group of ports.
|
|
123
|
+
# @param [Integer] total The number of ports to acquire
|
|
124
|
+
# @return [Array<Integer>|nil] An array of port numbers if successful, nil otherwise
|
|
117
125
|
def group(total)
|
|
118
126
|
return nil if @ports.count + total > @limit
|
|
119
|
-
opts = Array.new(
|
|
127
|
+
opts = Array.new(total, 0)
|
|
120
128
|
begin
|
|
121
129
|
(0..(total - 1)).each do |i|
|
|
122
130
|
port = i.zero? ? @next : opts[i - 1] + 1
|
|
@@ -127,31 +135,35 @@ class RandomPort::Pool
|
|
|
127
135
|
end
|
|
128
136
|
return nil if opts.any? { |p| @ports.include?(p) }
|
|
129
137
|
d = total * (total - 1) / 2
|
|
130
|
-
return nil unless opts.
|
|
138
|
+
return nil unless opts.sum - (total * opts.min) == d
|
|
131
139
|
@ports += opts
|
|
132
140
|
opts
|
|
133
141
|
end
|
|
134
142
|
|
|
135
|
-
#
|
|
143
|
+
# Verifies that a specific TCP port is available for use.
|
|
136
144
|
#
|
|
137
|
-
#
|
|
145
|
+
# Attempts to bind to the port on various interfaces to ensure availability.
|
|
146
|
+
# If the port is occupied, this method raises an error (+Errno::EADDRINUSE+).
|
|
138
147
|
#
|
|
139
|
-
# @param [Integer] port
|
|
140
|
-
# @return [Integer] The same port number
|
|
148
|
+
# @param [Integer] port The port number to verify
|
|
149
|
+
# @return [Integer] The same port number if available
|
|
150
|
+
# @raise [Errno::EADDRINUSE] If the port is already in use
|
|
151
|
+
# @raise [SocketError] If there's a socket-related error
|
|
141
152
|
def take(port)
|
|
142
153
|
['127.0.0.1', '::1', '0.0.0.0', 'localhost'].each do |host|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
next
|
|
147
|
-
end
|
|
154
|
+
TCPServer.new(host, port).close
|
|
155
|
+
rescue Errno::EADDRNOTAVAIL
|
|
156
|
+
next
|
|
148
157
|
end
|
|
149
158
|
port
|
|
150
159
|
end
|
|
151
160
|
|
|
152
|
-
|
|
161
|
+
# Executes a block of code with or without thread synchronization.
|
|
162
|
+
# @yield The block of code to execute
|
|
163
|
+
# @return The result of the block execution
|
|
164
|
+
def safe(&)
|
|
153
165
|
if @sync
|
|
154
|
-
@monitor.synchronize(&
|
|
166
|
+
@monitor.synchronize(&)
|
|
155
167
|
else
|
|
156
168
|
yield
|
|
157
169
|
end
|
data/lib/random-port.rb
CHANGED
data/random-port.gemspec
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'English'
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
|
9
|
-
s.required_ruby_version = '>=
|
|
9
|
+
s.required_ruby_version = '>=3.3'
|
|
10
10
|
s.name = 'random-port'
|
|
11
|
-
s.version = '0.
|
|
11
|
+
s.version = '0.8.1'
|
|
12
12
|
s.license = 'MIT'
|
|
13
13
|
s.summary = 'Random TCP port'
|
|
14
14
|
s.description = 'Reserves a random TCP port'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: random-port
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
@@ -54,7 +54,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
54
54
|
requirements:
|
|
55
55
|
- - ">="
|
|
56
56
|
- !ruby/object:Gem::Version
|
|
57
|
-
version: '
|
|
57
|
+
version: '3.3'
|
|
58
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
60
|
- - ">="
|