random-port 0.7.6 → 0.8.0

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: 19a3b6d51277760ad0638f741ef63bf1fbc8a4b77663b41569da4c34e251353a
4
- data.tar.gz: 96e0c4061b43248cbf091e318b9e6645371a7fd11189a43cd1cadccf23b9704d
3
+ metadata.gz: dd90fdffc75dd2489cab29b75ddadb118d7399fc51acf86d0c7588cff3656bef
4
+ data.tar.gz: f8f40a67dd0fd7daf6fd7ad67e9272035a587b96dbaf581777f659a3d1779bd3
5
5
  SHA512:
6
- metadata.gz: 6ac6711969efbcd97a534391cff9b3bb3e4244a5fe0a4518d7cbb3644a6b849507db8025af1491fac615c1aa9f3edf4db7d7bd9e42faf5619304191c1265afa0
7
- data.tar.gz: f01a9a30993fcc100fd5946290a8f8b60d94cb8a19db6ab8b918527ca48086f92cff89723391d99302f79fc264ed9f4d76a2225bfdfa24819e3af51ec8971396
6
+ metadata.gz: 9b076ebfe2d5b5ec19a2252783e2e1d01050feebb698d5ef1066aefbb230708617fabba95f9a363b3c6dc03204ce8eb7de92d1d902c572374f69d7d1c979e9d5
7
+ data.tar.gz: c6f56a56d9b510904a982a78ed9e2cab315cdd8d5e21a0587ac3aae10c9da9e1435ebbf1bd888d92a0f34930b3032f99febcaae593268988685ea060ba2db70c
data/Gemfile CHANGED
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
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', '~>5.25', require: false
9
+ gem 'minitest', '~>6.0', require: false
10
+ gem 'minitest-mock', '~>5.27', require: false
11
+ gem 'minitest-reporters', '~>1.7', require: false
10
12
  gem 'qbash', '~>0.2', require: false
11
13
  gem 'rake', '~>13.2', require: false
12
14
  gem 'rubocop', '~>1.75', require: false
@@ -15,5 +17,6 @@ gem 'rubocop-performance', '~>1.25', require: false
15
17
  gem 'rubocop-rake', '~>0.7', require: false
16
18
  gem 'rubocop-rspec', '~> 3.7', require: false
17
19
  gem 'simplecov', '~>0.22', require: false
20
+ gem 'simplecov-cobertura', '~>3.0', require: false
18
21
  gem 'threads', '~>0.4', require: false
19
22
  gem 'yard', '~>0.9', require: false
data/Gemfile.lock CHANGED
@@ -7,35 +7,47 @@ 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
- concurrent-ruby (1.3.5)
13
+ builder (3.3.0)
14
+ concurrent-ruby (1.3.6)
13
15
  docile (1.4.1)
14
- elapsed (0.2.0)
16
+ elapsed (0.2.2)
15
17
  loog (~> 0.6)
16
18
  tago (~> 0.1)
17
- json (2.15.0)
19
+ ellipsized (0.3.0)
20
+ json (2.18.0)
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.6.1)
24
+ loog (0.7.2)
25
+ ellipsized
22
26
  logger (~> 1.0)
23
- minitest (5.25.5)
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
24
35
  parallel (1.27.0)
25
- parser (3.3.9.0)
36
+ parser (3.3.10.1)
26
37
  ast (~> 2.4.1)
27
38
  racc
28
- prism (1.5.1)
29
- qbash (0.4.5)
39
+ prism (1.8.0)
40
+ qbash (0.7.2)
30
41
  backtrace (> 0)
31
42
  elapsed (> 0)
32
43
  loog (> 0)
33
44
  tago (> 0)
34
45
  racc (1.8.1)
35
46
  rainbow (3.1.1)
36
- rake (13.3.0)
47
+ rake (13.3.1)
37
48
  regexp_parser (2.11.3)
38
- rubocop (1.80.2)
49
+ rexml (3.4.4)
50
+ rubocop (1.84.1)
39
51
  json (~> 2.3)
40
52
  language_server-protocol (~> 3.17.0.2)
41
53
  lint_roller (~> 1.1.0)
@@ -43,41 +55,44 @@ GEM
43
55
  parser (>= 3.3.0.2)
44
56
  rainbow (>= 2.2.2, < 4.0)
45
57
  regexp_parser (>= 2.9.3, < 3.0)
46
- rubocop-ast (>= 1.46.0, < 2.0)
58
+ rubocop-ast (>= 1.49.0, < 2.0)
47
59
  ruby-progressbar (~> 1.7)
48
60
  unicode-display_width (>= 2.4.0, < 4.0)
49
- rubocop-ast (1.47.1)
61
+ rubocop-ast (1.49.0)
50
62
  parser (>= 3.3.7.2)
51
- prism (~> 1.4)
63
+ prism (~> 1.7)
52
64
  rubocop-minitest (0.38.2)
53
65
  lint_roller (~> 1.1)
54
66
  rubocop (>= 1.75.0, < 2.0)
55
67
  rubocop-ast (>= 1.38.0, < 2.0)
56
- rubocop-performance (1.26.0)
68
+ rubocop-performance (1.26.1)
57
69
  lint_roller (~> 1.1)
58
70
  rubocop (>= 1.75.0, < 2.0)
59
- rubocop-ast (>= 1.44.0, < 2.0)
71
+ rubocop-ast (>= 1.47.1, < 2.0)
60
72
  rubocop-rake (0.7.1)
61
73
  lint_roller (~> 1.1)
62
74
  rubocop (>= 1.72.1)
63
- rubocop-rspec (3.7.0)
75
+ rubocop-rspec (3.9.0)
64
76
  lint_roller (~> 1.1)
65
- rubocop (~> 1.72, >= 1.72.1)
77
+ rubocop (~> 1.81)
66
78
  ruby-progressbar (1.13.0)
67
79
  simplecov (0.22.0)
68
80
  docile (~> 1.1)
69
81
  simplecov-html (~> 0.11)
70
82
  simplecov_json_formatter (~> 0.1)
83
+ simplecov-cobertura (3.1.0)
84
+ rexml
85
+ simplecov (~> 0.19)
71
86
  simplecov-html (0.13.2)
72
87
  simplecov_json_formatter (0.1.4)
73
- tago (0.2.0)
74
- threads (0.4.1)
88
+ tago (0.7.0)
89
+ threads (0.5.0)
75
90
  backtrace (~> 0)
76
91
  concurrent-ruby (~> 1.0)
77
92
  unicode-display_width (3.2.0)
78
93
  unicode-emoji (~> 4.1)
79
- unicode-emoji (4.1.0)
80
- yard (0.9.37)
94
+ unicode-emoji (4.2.0)
95
+ yard (0.9.38)
81
96
 
82
97
  PLATFORMS
83
98
  arm64-darwin-22
@@ -87,7 +102,9 @@ PLATFORMS
87
102
  x86_64-linux
88
103
 
89
104
  DEPENDENCIES
90
- minitest (~> 5.25)
105
+ minitest (~> 6.0)
106
+ minitest-mock (~> 5.27)
107
+ minitest-reporters (~> 1.7)
91
108
  qbash (~> 0.2)
92
109
  rake (~> 13.2)
93
110
  random-port!
@@ -97,6 +114,7 @@ DEPENDENCIES
97
114
  rubocop-rake (~> 0.7)
98
115
  rubocop-rspec (~> 3.7)
99
116
  simplecov (~> 0.22)
117
+ simplecov-cobertura (~> 3.0)
100
118
  threads (~> 0.4)
101
119
  yard (~> 0.9)
102
120
 
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2018-2025 Yegor Bugayenko
3
+ Copyright (c) 2018-2026 Yegor Bugayenko
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the 'Software'), to deal
data/LICENSES/MIT.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2018-2025 Yegor Bugayenko
3
+ Copyright (c) 2018-2026 Yegor Bugayenko
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the 'Software'), to deal
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/yegor256/random-port/master/frames)
10
10
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/random-port/blob/master/LICENSE.txt)
11
11
  [![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/random-port.svg)](https://codecov.io/github/yegor256/random-port?branch=master)
12
- [![Hits-of-Code](https://hitsofcode.com/github/yegor256/random-port)](https://hitsofcode.com/view/github/random-port/mailanes)
12
+ [![Hits-of-Code](https://hitsofcode.com/github/yegor256/random-port)](https://hitsofcode.com/view/github/yegor256/random-port)
13
13
 
14
14
  It's a simple Ruby gem to get a random TCP port.
15
15
 
@@ -52,6 +52,15 @@ RandomPort::Pool::SINGLETON.acquire do |port|
52
52
  end
53
53
  ```
54
54
 
55
+ Or use shortened version, all methods called in `RandomPort`
56
+ will be delegated to `Pool::SINGLETON`:
57
+
58
+ ```ruby
59
+ RandomPort.acquire do |port|
60
+ # Use it here...
61
+ end
62
+ ```
63
+
55
64
  The pool is thread-safe by default.
56
65
  You can configure it to be
57
66
  not-thread-safe, using optional `sync` argument of the constructor.
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
3
+ # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require 'rubygems'
@@ -37,4 +37,5 @@ require 'yard'
37
37
  desc 'Build Yard documentation'
38
38
  YARD::Rake::YardocTask.new do |t|
39
39
  t.files = ['lib/**/*.rb']
40
+ t.options = ['--fail-on-warning']
40
41
  end
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
3
+ # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
- # The module for all classes.
6
+ # Main module that contains all RandomPort classes and utilities.
7
+ #
8
+ # This module provides a simple way to acquire random TCP ports
9
+ # that are guaranteed to be available for use. It includes a Pool
10
+ # class that manages port allocation and ensures thread safety.
7
11
  #
8
12
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
9
- # Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
13
+ # Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
10
14
  # License:: MIT
11
15
  module RandomPort
16
+ extend Forwardable
17
+
18
+ def_delegators :'RandomPort::Pool::SINGLETON', :acquire, :release, :count, :size, :empty?
19
+ module_function :acquire, :release, :count, :size, :empty?
12
20
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
3
+ # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require 'monitor'
@@ -8,7 +8,7 @@ require 'socket'
8
8
  require 'tago'
9
9
  require_relative 'module'
10
10
 
11
- # Pool of TPC ports.
11
+ # Pool of TCP ports.
12
12
  #
13
13
  # Use it like this:
14
14
  #
@@ -17,26 +17,27 @@ require_relative 'module'
17
17
  # # to the pool afterwards.
18
18
  # end
19
19
  #
20
- # You can specify the maximum amount of ports to acquire, using +limit+.
21
- # If more acquiring requests will arrive, an exception will be raised.
20
+ # You can specify the maximum number of ports to acquire using +limit+.
21
+ # If more acquisition requests arrive, an exception will be raised.
22
22
  #
23
- # The class is thread-safe, by default. You can configure it to be
24
- # not-thread-safe, using optional +sync+ argument of the constructor,
23
+ # The class is thread-safe by default. You can configure it to be
24
+ # non-thread-safe using the optional +sync+ argument of the constructor,
25
25
  # passing <tt>FALSE</tt>.
26
26
  #
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
28
+ # Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
29
29
  # License:: MIT
30
30
  class RandomPort::Pool
31
- # If can't acquire by time out.
31
+ # Raised when a port cannot be acquired within the timeout period.
32
32
  class Timeout < StandardError; end
33
33
 
34
+ # @return [Integer] The maximum number of ports that can be acquired from this pool
34
35
  attr_reader :limit
35
36
 
36
- # Ctor.
37
- # @param [Boolean] sync Set it to FALSE if you want this pool to be NOT thread-safe
38
- # @param [Integer] limit Set the maximum number of ports in the pool
39
- # @param [Integer] start The next port to try
37
+ # Constructor.
38
+ # @param [Boolean] sync Set to FALSE if you want this pool to be non-thread-safe
39
+ # @param [Integer] limit The maximum number of ports that can be acquired from the pool
40
+ # @param [Integer] start The first port number to try when acquiring
40
41
  def initialize(sync: true, limit: 65_536, start: 1025)
41
42
  @ports = []
42
43
  @sync = sync
@@ -45,27 +46,33 @@ class RandomPort::Pool
45
46
  @next = start
46
47
  end
47
48
 
48
- # Application wide pool of ports
49
+ # Application-wide singleton pool of ports.
49
50
  SINGLETON = RandomPort::Pool.new
50
51
 
51
- # How many ports acquired now?
52
+ # Returns the number of ports currently acquired from the pool.
53
+ # @return [Integer] The count of acquired ports
52
54
  def count
53
55
  @ports.count
54
56
  end
55
57
  alias size count
56
58
 
57
- # Is it empty?
59
+ # Checks if the pool is empty (no ports are currently acquired).
60
+ # @return [Boolean] TRUE if no ports are acquired, FALSE otherwise
58
61
  def empty?
59
62
  @ports.empty?
60
63
  end
61
64
 
62
- # Acquire a new random TCP port.
65
+ # Acquires one or more available TCP ports from the pool.
63
66
  #
64
67
  # You can specify the number of ports to acquire. If it's more than one,
65
- # an array will be returned.
68
+ # an array will be returned. If a block is given, the port(s) will be
69
+ # automatically released after the block execution.
66
70
  #
67
- # You can specify the amount of seconds to wait until a new port
68
- # is available.
71
+ # @param [Integer] total The number of ports to acquire (default: 1)
72
+ # @param [Integer] timeout The maximum seconds to wait for port availability
73
+ # @yield [Integer|Array<Integer>] The acquired port(s)
74
+ # @return [Integer|Array<Integer>] The acquired port(s) if no block given
75
+ # @raise [Timeout] If ports cannot be acquired within the timeout period
69
76
  def acquire(total = 1, timeout: 4)
70
77
  start = Time.now
71
78
  attempt = 0
@@ -77,7 +84,7 @@ class RandomPort::Pool
77
84
  "(#{@ports.size} already occupied) " \
78
85
  "for #{total} port(s), after #{attempt} attempts in #{start.ago}"
79
86
  end
80
- attempt += 1
87
+ attempt += 1
81
88
  opts = safe { group(total) }
82
89
  if opts.nil?
83
90
  @next += 1
@@ -96,9 +103,9 @@ class RandomPort::Pool
96
103
  end
97
104
  end
98
105
 
99
- # Return it/them back to the pool.
100
- # @param [Integer] port TCP port number to release
101
- # @return nil
106
+ # Releases one or more ports back to the pool.
107
+ # @param [Integer|Array<Integer>] port The TCP port number(s) to release
108
+ # @return [nil]
102
109
  def release(port)
103
110
  safe do
104
111
  if port.is_a?(Array)
@@ -111,12 +118,12 @@ class RandomPort::Pool
111
118
 
112
119
  private
113
120
 
114
- # Take a group of ports, if possible.
115
- # @param [Integer] total How many ports to take
116
- # @return [Array<Integer>|nil] Ports found or NIL if impossible now
121
+ # Attempts to acquire a contiguous group of ports.
122
+ # @param [Integer] total The number of ports to acquire
123
+ # @return [Array<Integer>|nil] An array of port numbers if successful, nil otherwise
117
124
  def group(total)
118
125
  return nil if @ports.count + total > @limit
119
- opts = Array.new(0, total)
126
+ opts = Array.new(total, 0)
120
127
  begin
121
128
  (0..(total - 1)).each do |i|
122
129
  port = i.zero? ? @next : opts[i - 1] + 1
@@ -132,12 +139,15 @@ class RandomPort::Pool
132
139
  opts
133
140
  end
134
141
 
135
- # Find one possible TCP port or raise exception if this port can't be used.
142
+ # Verifies that a specific TCP port is available for use.
136
143
  #
137
- # If port is occupied, this method raises an error (+Errno::EADDRINUSE+).
144
+ # Attempts to bind to the port on various interfaces to ensure availability.
145
+ # If the port is occupied, this method raises an error (+Errno::EADDRINUSE+).
138
146
  #
139
- # @param [Integer] port Suggested port number
140
- # @return [Integer] The same port number
147
+ # @param [Integer] port The port number to verify
148
+ # @return [Integer] The same port number if available
149
+ # @raise [Errno::EADDRINUSE] If the port is already in use
150
+ # @raise [SocketError] If there's a socket-related error
141
151
  def take(port)
142
152
  ['127.0.0.1', '::1', '0.0.0.0', 'localhost'].each do |host|
143
153
  begin
@@ -149,6 +159,9 @@ class RandomPort::Pool
149
159
  port
150
160
  end
151
161
 
162
+ # Executes a block of code with or without thread synchronization.
163
+ # @param block The block of code to execute
164
+ # @return The result of the block execution
152
165
  def safe(&block)
153
166
  if @sync
154
167
  @monitor.synchronize(&block)
data/lib/random-port.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
3
+ # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require_relative 'random-port/module'
data/random-port.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
3
+ # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require 'English'
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
9
9
  s.required_ruby_version = '>=2.3'
10
10
  s.name = 'random-port'
11
- s.version = '0.7.6'
11
+ s.version = '0.8.0'
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.7.6
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko