random-port 0.7.3 → 0.7.5
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/.0pdd.yml +1 -1
- data/.github/workflows/actionlint.yml +1 -1
- data/.github/workflows/codecov.yml +5 -2
- data/.github/workflows/copyrights.yml +5 -1
- data/.github/workflows/markdown-lint.yml +1 -1
- data/.github/workflows/pdd.yml +2 -2
- data/.github/workflows/rake.yml +4 -4
- data/.github/workflows/xcop.yml +6 -2
- data/.gitignore +1 -1
- data/.rubocop.yml +7 -1
- data/.rultor.yml +1 -1
- data/Gemfile +5 -3
- data/LICENSE.txt +1 -1
- data/Rakefile +1 -1
- data/lib/random-port/module.rb +2 -2
- data/lib/random-port/pool.rb +45 -29
- data/lib/random-port.rb +1 -1
- data/random-port.gemspec +2 -2
- data/test/test__helper.rb +2 -1
- data/test/test_pool.rb +59 -12
- 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: 685cbbb964686d55837c88f3856b60207d3abaadb76e96ba9f9093bc8aba0a9c
|
4
|
+
data.tar.gz: 83e7ea6c0ac635b3c06cb1d190d3a991be61d4d534596ae10852c1a7a8df542d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48adf68a56c6ac4550287538b7cefa09cf033575e56dd8cdd6d53f0bc49004c87270f4c3b1d5c30576e721bf9c0589245c50854b494a3ec191588fc9e974253a
|
7
|
+
data.tar.gz: bd33bb2321ea165a1e9e546fa257db2a824572a07462af36ebd0e4e2fe93a4679c16f269170f51042046e139c7ed35a76bd4bd39338dd6a00777ddb4c1fb1214
|
data/.0pdd.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -19,12 +19,13 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
---
|
21
21
|
name: codecov
|
22
|
-
on:
|
22
|
+
'on':
|
23
23
|
push:
|
24
24
|
branches:
|
25
25
|
- master
|
26
26
|
jobs:
|
27
27
|
codecov:
|
28
|
+
timeout-minutes: 5
|
28
29
|
runs-on: ubuntu-24.04
|
29
30
|
steps:
|
30
31
|
- uses: actions/checkout@v4
|
@@ -36,3 +37,5 @@ jobs:
|
|
36
37
|
- uses: codecov/codecov-action@v5
|
37
38
|
with:
|
38
39
|
token: ${{ secrets.CODECOV_TOKEN }}
|
40
|
+
files: coverage/.resultset.json
|
41
|
+
fail_ci_if_error: true
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -21,7 +21,11 @@
|
|
21
21
|
name: copyrights
|
22
22
|
'on':
|
23
23
|
push:
|
24
|
+
branches:
|
25
|
+
- master
|
24
26
|
pull_request:
|
27
|
+
branches:
|
28
|
+
- master
|
25
29
|
jobs:
|
26
30
|
copyrights:
|
27
31
|
runs-on: ubuntu-24.04
|
data/.github/workflows/pdd.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -19,7 +19,7 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
---
|
21
21
|
name: pdd
|
22
|
-
on:
|
22
|
+
'on':
|
23
23
|
push:
|
24
24
|
branches:
|
25
25
|
- master
|
data/.github/workflows/rake.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -19,7 +19,7 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
---
|
21
21
|
name: rake
|
22
|
-
on:
|
22
|
+
'on':
|
23
23
|
push:
|
24
24
|
branches:
|
25
25
|
- master
|
@@ -27,8 +27,8 @@ on:
|
|
27
27
|
branches:
|
28
28
|
- master
|
29
29
|
jobs:
|
30
|
-
|
31
|
-
|
30
|
+
rake:
|
31
|
+
timeout-minutes: 5
|
32
32
|
strategy:
|
33
33
|
matrix:
|
34
34
|
os: [ubuntu-24.04, macos-15, windows-2022]
|
data/.github/workflows/xcop.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -19,9 +19,13 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
---
|
21
21
|
name: xcop
|
22
|
-
on:
|
22
|
+
'on':
|
23
23
|
push:
|
24
|
+
branches:
|
25
|
+
- master
|
24
26
|
pull_request:
|
27
|
+
branches:
|
28
|
+
- master
|
25
29
|
jobs:
|
26
30
|
xcop:
|
27
31
|
runs-on: ubuntu-24.04
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018-
|
1
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -23,7 +23,11 @@ AllCops:
|
|
23
23
|
TargetRubyVersion: 2.3.3
|
24
24
|
NewCops: enable
|
25
25
|
SuggestExtensions: false
|
26
|
+
require:
|
27
|
+
- rubocop-minitest
|
26
28
|
|
29
|
+
Minitest/EmptyLineBeforeAssertionMethods:
|
30
|
+
Enabled: false
|
27
31
|
Layout/EmptyLineAfterGuardClause:
|
28
32
|
Enabled: false
|
29
33
|
Style/ClassAndModuleChildren:
|
@@ -44,3 +48,5 @@ Metrics/CyclomaticComplexity:
|
|
44
48
|
Max: 20
|
45
49
|
Metrics/AbcSize:
|
46
50
|
Max: 60
|
51
|
+
Metrics/ClassLength:
|
52
|
+
Max: 150
|
data/.rultor.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2025 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
|
@@ -24,9 +24,11 @@ source 'https://rubygems.org'
|
|
24
24
|
gemspec
|
25
25
|
|
26
26
|
gem 'minitest', '5.25.4', require: false
|
27
|
+
gem 'qbash', '>=0.2.2', require: false
|
27
28
|
gem 'rake', '13.2.1', require: false
|
28
|
-
gem 'rubocop', '1.
|
29
|
-
gem 'rubocop-
|
29
|
+
gem 'rubocop', '1.71.0', require: false
|
30
|
+
gem 'rubocop-minitest', '0.36.0', require: false
|
31
|
+
gem 'rubocop-rspec', '3.4.0', require: false
|
30
32
|
gem 'simplecov', '0.22.0', require: false
|
31
33
|
gem 'threads', '0.4.1', require: false
|
32
34
|
gem 'yard', '0.9.37', require: false
|
data/LICENSE.txt
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2025 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/lib/random-port/module.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# (The MIT License)
|
4
4
|
#
|
5
|
-
# Copyright (c) 2018-
|
5
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -25,7 +25,7 @@
|
|
25
25
|
# The module for all classes.
|
26
26
|
#
|
27
27
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
-
# Copyright:: Copyright (c) 2018-
|
28
|
+
# Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
|
29
29
|
# License:: MIT
|
30
30
|
module RandomPort
|
31
31
|
end
|
data/lib/random-port/pool.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# (The MIT License)
|
4
4
|
#
|
5
|
-
# Copyright (c) 2018-
|
5
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -44,7 +44,7 @@ require_relative 'module'
|
|
44
44
|
# passing <tt>FALSE</tt>.
|
45
45
|
#
|
46
46
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
47
|
-
# Copyright:: Copyright (c) 2018-
|
47
|
+
# Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
|
48
48
|
# License:: MIT
|
49
49
|
class RandomPort::Pool
|
50
50
|
# If can't acquire by time out.
|
@@ -55,12 +55,13 @@ class RandomPort::Pool
|
|
55
55
|
# Ctor.
|
56
56
|
# @param [Boolean] sync Set it to FALSE if you want this pool to be NOT thread-safe
|
57
57
|
# @param [Integer] limit Set the maximum number of ports in the pool
|
58
|
-
|
58
|
+
# @param [Integer] start The next port to try
|
59
|
+
def initialize(sync: true, limit: 65_536, start: 1025)
|
59
60
|
@ports = []
|
60
61
|
@sync = sync
|
61
62
|
@monitor = Monitor.new
|
62
63
|
@limit = limit
|
63
|
-
@next =
|
64
|
+
@next = start
|
64
65
|
end
|
65
66
|
|
66
67
|
# Application wide pool of ports
|
@@ -96,25 +97,14 @@ class RandomPort::Pool
|
|
96
97
|
"for #{total} port(s), after #{attempt} attempts in #{start.ago}"
|
97
98
|
end
|
98
99
|
attempt += 1
|
99
|
-
opts = safe
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
opts[i] = take(i.zero? ? @next : opts[i - 1] + 1)
|
105
|
-
end
|
106
|
-
rescue Errno::EADDRINUSE, SocketError
|
107
|
-
next
|
108
|
-
end
|
109
|
-
next if opts.any? { |p| @ports.include?(p) }
|
110
|
-
d = total * (total - 1) / 2
|
111
|
-
next unless opts.inject(&:+) - (total * opts.min) == d
|
112
|
-
@ports += opts
|
113
|
-
opts
|
100
|
+
opts = safe { group(total) }
|
101
|
+
if opts.nil?
|
102
|
+
@next += 1
|
103
|
+
else
|
104
|
+
@next = opts.max + 1
|
114
105
|
end
|
115
|
-
next if opts.nil?
|
116
|
-
@next = opts.max + 1
|
117
106
|
@next = 0 if @next > 65_535
|
107
|
+
next if opts.nil?
|
118
108
|
opts = opts[0] if total == 1
|
119
109
|
return opts unless block_given?
|
120
110
|
begin
|
@@ -126,6 +116,8 @@ class RandomPort::Pool
|
|
126
116
|
end
|
127
117
|
|
128
118
|
# Return it/them back to the pool.
|
119
|
+
# @param [Integer] port TCP port number to release
|
120
|
+
# @return nil
|
129
121
|
def release(port)
|
130
122
|
safe do
|
131
123
|
if port.is_a?(Array)
|
@@ -138,14 +130,38 @@ class RandomPort::Pool
|
|
138
130
|
|
139
131
|
private
|
140
132
|
|
141
|
-
#
|
142
|
-
# @param [Integer]
|
143
|
-
# @return [Integer]
|
144
|
-
def
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
133
|
+
# Take a group of ports, if possible.
|
134
|
+
# @param [Integer] total How many ports to take
|
135
|
+
# @return [Array<Integer>|nil] Ports found or NIL if impossible now
|
136
|
+
def group(total)
|
137
|
+
return nil if @ports.count + total > @limit
|
138
|
+
opts = Array.new(0, total)
|
139
|
+
begin
|
140
|
+
(0..(total - 1)).each do |i|
|
141
|
+
port = i.zero? ? @next : opts[i - 1] + 1
|
142
|
+
opts[i] = take(port)
|
143
|
+
end
|
144
|
+
rescue Errno::EADDRINUSE, SocketError
|
145
|
+
return nil
|
146
|
+
end
|
147
|
+
return nil if opts.any? { |p| @ports.include?(p) }
|
148
|
+
d = total * (total - 1) / 2
|
149
|
+
return nil unless opts.inject(&:+) - (total * opts.min) == d
|
150
|
+
@ports += opts
|
151
|
+
opts
|
152
|
+
end
|
153
|
+
|
154
|
+
# Find one possible TCP port or raise exception if this port can't be used.
|
155
|
+
#
|
156
|
+
# If port is occupied, this method raises an error (+Errno::EADDRINUSE+).
|
157
|
+
#
|
158
|
+
# @param [Integer] port Suggested port number
|
159
|
+
# @return [Integer] The same port number
|
160
|
+
def take(port)
|
161
|
+
['127.0.0.1', '::1', '0.0.0.0', 'localhost'].each do |host|
|
162
|
+
TCPServer.new(host, port).close
|
163
|
+
end
|
164
|
+
port
|
149
165
|
end
|
150
166
|
|
151
167
|
def safe(&block)
|
data/lib/random-port.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# (The MIT License)
|
4
4
|
#
|
5
|
-
# Copyright (c) 2018-
|
5
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the 'Software'), to deal
|
data/random-port.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# (The MIT License)
|
4
4
|
#
|
5
|
-
# Copyright (c) 2018-
|
5
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
28
28
|
s.required_ruby_version = '>=2.3'
|
29
29
|
s.name = 'random-port'
|
30
|
-
s.version = '0.7.
|
30
|
+
s.version = '0.7.5'
|
31
31
|
s.license = 'MIT'
|
32
32
|
s.summary = 'Random TCP port'
|
33
33
|
s.description = 'Reserves a random TCP port'
|
data/test/test__helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2025 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
|
@@ -24,4 +24,5 @@ $stdout.sync = true
|
|
24
24
|
|
25
25
|
require 'simplecov'
|
26
26
|
SimpleCov.start
|
27
|
+
|
27
28
|
require 'minitest/autorun'
|
data/test/test_pool.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# (The MIT License)
|
4
4
|
#
|
5
|
-
# Copyright (c) 2018-
|
5
|
+
# Copyright (c) 2018-2025 Yegor Bugayenko
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -23,13 +23,15 @@
|
|
23
23
|
# SOFTWARE.
|
24
24
|
|
25
25
|
require 'minitest/autorun'
|
26
|
-
require '
|
26
|
+
require 'qbash'
|
27
|
+
require 'shellwords'
|
27
28
|
require 'socket'
|
29
|
+
require 'threads'
|
28
30
|
require_relative '../lib/random-port/pool'
|
29
31
|
|
30
32
|
# Pool test.
|
31
33
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
-
# Copyright:: Copyright (c) 2018-
|
34
|
+
# Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
|
33
35
|
# License:: MIT
|
34
36
|
class RandomPort::TestPool < Minitest::Test
|
35
37
|
def test_acquires_and_releases
|
@@ -37,8 +39,8 @@ class RandomPort::TestPool < Minitest::Test
|
|
37
39
|
port = pool.acquire
|
38
40
|
server = TCPServer.new('localhost', port)
|
39
41
|
server.close
|
40
|
-
|
41
|
-
|
42
|
+
refute_nil(port)
|
43
|
+
assert_predicate(port, :positive?)
|
42
44
|
pool.release(port)
|
43
45
|
end
|
44
46
|
|
@@ -56,11 +58,56 @@ class RandomPort::TestPool < Minitest::Test
|
|
56
58
|
assert_equal(0, pool.size)
|
57
59
|
end
|
58
60
|
|
61
|
+
def test_skips_truly_busy_port
|
62
|
+
port = RandomPort::Pool.new.acquire
|
63
|
+
server = TCPServer.new('127.0.0.1', port)
|
64
|
+
other = RandomPort::Pool.new(start: port).acquire
|
65
|
+
refute_equal(other, port)
|
66
|
+
server.close
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_skips_externally_busy_port
|
70
|
+
skip 'Not supported on Windows' if Gem.win_platform?
|
71
|
+
['127.0.0.1', 'localhost', '::1', '0.0.0.0'].each do |host|
|
72
|
+
Dir.mktmpdir do |home|
|
73
|
+
port = RandomPort::Pool.new.acquire
|
74
|
+
started = File.join(home, 'started.txt')
|
75
|
+
enough = File.join(home, 'enough.txt')
|
76
|
+
t =
|
77
|
+
Thread.new do
|
78
|
+
qbash(
|
79
|
+
[
|
80
|
+
'ruby', '-e',
|
81
|
+
Shellwords.escape(
|
82
|
+
"
|
83
|
+
require 'socket'
|
84
|
+
require 'fileutils'
|
85
|
+
TCPServer.new('#{host}', #{port})
|
86
|
+
FileUtils.touch('#{started}')
|
87
|
+
loop do
|
88
|
+
break if File.exist?('#{enough}')
|
89
|
+
end
|
90
|
+
"
|
91
|
+
)
|
92
|
+
]
|
93
|
+
)
|
94
|
+
end
|
95
|
+
loop do
|
96
|
+
break if File.exist?(started)
|
97
|
+
end
|
98
|
+
other = RandomPort::Pool.new(start: port).acquire
|
99
|
+
FileUtils.touch(enough)
|
100
|
+
t.join
|
101
|
+
refute_equal(other, port)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
59
106
|
def test_acquires_and_releases_three_ports_in_block
|
60
107
|
pool = RandomPort::Pool.new(limit: 3)
|
61
108
|
assert_equal(0, pool.size)
|
62
109
|
pool.acquire(3, timeout: 16) do |ports|
|
63
|
-
|
110
|
+
assert_kind_of(Array, ports)
|
64
111
|
assert_equal(3, ports.count)
|
65
112
|
assert_equal(3, pool.size)
|
66
113
|
ports.each do |p|
|
@@ -73,8 +120,8 @@ class RandomPort::TestPool < Minitest::Test
|
|
73
120
|
|
74
121
|
def test_acquires_and_releases_in_block
|
75
122
|
result = RandomPort::Pool.new.acquire do |port|
|
76
|
-
|
77
|
-
|
123
|
+
refute_nil(port)
|
124
|
+
assert_predicate(port, :positive?)
|
78
125
|
123
|
79
126
|
end
|
80
127
|
assert_equal(123, result)
|
@@ -94,18 +141,18 @@ class RandomPort::TestPool < Minitest::Test
|
|
94
141
|
|
95
142
|
def test_acquires_and_releases_safely
|
96
143
|
pool = RandomPort::Pool.new
|
97
|
-
assert_raises do
|
144
|
+
assert_raises(StandardError) do
|
98
145
|
pool.acquire do
|
99
146
|
raise 'Itended'
|
100
147
|
end
|
101
148
|
end
|
102
|
-
|
149
|
+
assert_predicate(pool.count, :zero?)
|
103
150
|
end
|
104
151
|
|
105
152
|
def test_acquires_and_releases_from_singleton
|
106
153
|
RandomPort::Pool::SINGLETON.acquire do |port|
|
107
|
-
|
108
|
-
|
154
|
+
refute_nil(port)
|
155
|
+
assert_predicate(port, :positive?)
|
109
156
|
end
|
110
157
|
end
|
111
158
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: random-port
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tago
|