net-ping 2.0.8 → 2.1.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 +5 -5
- data/CHANGES +28 -1
- data/CLAUDE.md +89 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +34 -16
- data/README.md +5 -3
- data/Rakefile +93 -8
- data/docs/superpowers/plans/2026-07-25-platform-specific-gems.md +317 -0
- data/docs/superpowers/specs/2026-07-25-platform-specific-gems-design.md +71 -0
- data/lib/net/ping/external.rb +5 -3
- data/lib/net/ping/ping.rb +2 -3
- data/lib/net/ping/version.rb +6 -0
- data/net-ping-universal-linux.gemspec +4 -0
- data/net-ping-universal-mingw-ucrt.gemspec +7 -0
- data/net-ping.gemspec +4 -16
- data/test/test_net_ping.rb +2 -4
- data/test/test_net_ping_external.rb +89 -0
- data/test/test_net_ping_gem_packaging.rb +333 -0
- data/test/test_net_ping_http.rb +27 -31
- data/test/test_net_ping_icmp.rb +6 -5
- data/test/test_net_ping_tcp.rb +2 -1
- metadata +14 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 27c470dd18b95b9b05e68e1dd6e79da70a8c8d4eaaa28581e770fa4d0d028aca
|
|
4
|
+
data.tar.gz: fc020ad255eb094dd057f552e67c36f83a00e87aa88e12837ceb3f2bf1c8673b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4fc2c4d695cbdb27ddd478b92929f6f9164eb07d768b56ee8f6d69cb102ded9bfe435ff0fd389136b77a86f200440da26f6078bca87561275f881f5b5abb7c24
|
|
7
|
+
data.tar.gz: 5c45a5a55df135b3145e6aab5b3286c27d92487e9a5ac0329ada3641659acef7a8c69a4fb8f22ac2d04b6c68627a6335fd7c9ca2c681987c35713da78472cdbe
|
data/CHANGES
CHANGED
|
@@ -1 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
== 2.1.0 - 08-Aug-2026
|
|
2
|
+
* Publish platform-specific gem metadata so Linux installs cap2 and current
|
|
3
|
+
Windows RubyInstaller installs win32-security for ICMP support
|
|
4
|
+
[#44](https://github.com/eitoball/net-ping/pull/44).
|
|
5
|
+
* Fix the FreeBSD ping6 timeout option
|
|
6
|
+
[#43](https://github.com/eitoball/net-ping/pull/43).
|
|
7
|
+
* Add Ruby 4.0 to the test matrix and add win32ole as an explicit Windows
|
|
8
|
+
dependency, since it is no longer a default gem as of Ruby 4.0
|
|
9
|
+
[#41](https://github.com/eitoball/net-ping/pull/41).
|
|
10
|
+
* Move Net::Ping::VERSION into its own file so the gemspec version can no
|
|
11
|
+
longer drift out of sync with it
|
|
12
|
+
[#37](https://github.com/eitoball/net-ping/pull/37).
|
|
13
|
+
* Fix `Net::Ping::External#ping6` setting a spurious "undefined method '=~'
|
|
14
|
+
for false" exception on success
|
|
15
|
+
[#39](https://github.com/eitoball/net-ping/pull/39).
|
|
16
|
+
|
|
17
|
+
== 2.0.9 - 25-Jul-2026
|
|
18
|
+
* Add GitHub Actions CI [#33](https://github.com/eitoball/net-ping/pull/33)
|
|
19
|
+
and update its supported Ruby versions [#38](https://github.com/eitoball/net-ping/pull/38).
|
|
20
|
+
* Replace FakeWeb with WebMock and update the test suite for current Ruby
|
|
21
|
+
versions [#38](https://github.com/eitoball/net-ping/pull/38).
|
|
22
|
+
* Skip external-ping tests when the system ping command is unavailable
|
|
23
|
+
[#33](https://github.com/eitoball/net-ping/pull/33).
|
|
24
|
+
* Fix the macOS ping6 interval option
|
|
25
|
+
[#40](https://github.com/eitoball/net-ping/pull/40).
|
|
26
|
+
* Update README wording [#30](https://github.com/eitoball/net-ping/pull/30).
|
|
27
|
+
* Align Net::Ping::VERSION with the gem version
|
|
28
|
+
[#37](https://github.com/eitoball/net-ping/pull/37).
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Development commands
|
|
6
|
+
|
|
7
|
+
Install dependencies:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bundle install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the default suite:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bundle exec rake test
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run one protocol-specific test file through its Rake task:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
bundle exec rake test:tcp
|
|
23
|
+
bundle exec rake test:http
|
|
24
|
+
bundle exec rake test:udp
|
|
25
|
+
bundle exec rake test:external
|
|
26
|
+
bundle exec rake test:icmp
|
|
27
|
+
bundle exec rake test:wmi
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
There is no lint task or linter configuration. Build the gem with
|
|
31
|
+
`bundle exec rake gem:create`; `bundle exec rake gem:install` builds and
|
|
32
|
+
installs it locally.
|
|
33
|
+
|
|
34
|
+
`test:icmp` requires elevated privileges: root or `net_raw` capability on
|
|
35
|
+
Unix (checked via the `cap2` gem, falling back to a root check if `cap2`
|
|
36
|
+
isn't available), or elevated security on Windows (via `win32-security`).
|
|
37
|
+
The aggregate `test` task (`test/test_net_ping.rb`) only requires the ICMP
|
|
38
|
+
test file when that privilege check passes. External-ping tests invoke the
|
|
39
|
+
system `ping` command; HTTP tests use FakeWeb/webmock except the timeout
|
|
40
|
+
case, which makes a real network connection.
|
|
41
|
+
|
|
42
|
+
CI (`.github/workflows/test.yml`) runs `bundle exec rake test` on
|
|
43
|
+
ubuntu-latest and windows-latest across Ruby 2.7-3.4.
|
|
44
|
+
|
|
45
|
+
## Architecture
|
|
46
|
+
|
|
47
|
+
This is a Ruby gem that exposes `Net::Ping` implementations for several
|
|
48
|
+
reachability mechanisms:
|
|
49
|
+
|
|
50
|
+
- `lib/net/ping/ping.rb` defines the abstract `Net::Ping` base class and its
|
|
51
|
+
shared state: `host`, `port`, `timeout`, `exception`, `warning`, and
|
|
52
|
+
`duration`.
|
|
53
|
+
- `lib/net/ping/{tcp,udp,icmp,external,http}.rb` implement socket, raw ICMP,
|
|
54
|
+
system-command, and HTTP pings. `wmi.rb` is loaded only on Windows
|
|
55
|
+
(`File::ALT_SEPARATOR` check).
|
|
56
|
+
- `lib/net/ping.rb` is the all-in-one entry point (`require 'net/ping'`);
|
|
57
|
+
requiring a protocol file directly (e.g. `require 'net/ping/tcp'`) loads
|
|
58
|
+
only that implementation and reduces memory footprint.
|
|
59
|
+
- Each protocol has a matching `test/test_net_ping_<protocol>.rb` file. The
|
|
60
|
+
aggregate `test/test_net_ping.rb` requires the supported protocol suites
|
|
61
|
+
based on the platform/privilege checks described above.
|
|
62
|
+
|
|
63
|
+
## Repository-specific conventions
|
|
64
|
+
|
|
65
|
+
- A subclass `ping` method calls `super(host)` first. The base implementation
|
|
66
|
+
validates that a host is present and resets `@exception`, `@warning`, and
|
|
67
|
+
`@duration` for each attempt.
|
|
68
|
+
- `ping` returns a truthy success value or `false`; callers inspect
|
|
69
|
+
`exception` after failures rather than receive connection errors. Set
|
|
70
|
+
`duration` only after a successful ping and leave it `nil` on failure.
|
|
71
|
+
`ping?` is the boolean wrapper supplied by the base class (or an explicit
|
|
72
|
+
alias in `External`).
|
|
73
|
+
- TCP and UDP treat connection refusal according to their class-level
|
|
74
|
+
`service_check` setting (aliased as `econnrefused`/`ecr`). Keep the
|
|
75
|
+
Boolean-only setter validation and test both modes when changing that
|
|
76
|
+
behavior.
|
|
77
|
+
- Preserve platform branches: `External` maps `ping`/`ping6` options to each
|
|
78
|
+
OS's `ping`/`ping6` syntax (Linux, AIX, BSD/macOS, Solaris, HP-UX, Windows),
|
|
79
|
+
ICMP requires raw-socket privileges, and WMI is Windows-only.
|
|
80
|
+
- HTTP tests stub requests with FakeWeb/webmock and reset proxy environment
|
|
81
|
+
variables in `setup`; register any new HTTP cases rather than making
|
|
82
|
+
ordinary tests depend on live services.
|
|
83
|
+
|
|
84
|
+
## Repository layout notes
|
|
85
|
+
|
|
86
|
+
- `.worktrees/` contains git worktrees for in-progress branches; treat them
|
|
87
|
+
as separate checkouts, not part of the main tree.
|
|
88
|
+
- `docs/superpowers/` holds plan/spec documents from prior sessions using the
|
|
89
|
+
`superpowers` skill set — reference material, not source.
|
data/Gemfile
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
gemspec
|
|
3
|
+
gem 'win32-security', '>= 0.2.0' if Gem.win_platform?
|
|
4
|
+
|
|
5
|
+
# No longer a default gem as of Ruby 4.0. Used by the WMI ping class.
|
|
6
|
+
gem 'win32ole', '>= 1.8.8' if Gem.win_platform?
|
|
7
|
+
|
|
8
|
+
gem 'cap2', '>= 0.2.2' if RUBY_PLATFORM =~ /linux/i
|
data/Gemfile.lock
CHANGED
|
@@ -1,35 +1,53 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
net-ping (2.0
|
|
4
|
+
net-ping (2.1.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
addressable (2.9.0)
|
|
10
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
11
|
+
bigdecimal (4.1.2)
|
|
12
|
+
byebug (13.0.0)
|
|
13
|
+
reline (>= 0.6.0)
|
|
14
|
+
coderay (1.1.3)
|
|
15
|
+
crack (1.0.1)
|
|
16
|
+
bigdecimal
|
|
17
|
+
rexml
|
|
18
|
+
hashdiff (1.2.1)
|
|
19
|
+
io-console (0.8.2)
|
|
20
|
+
method_source (1.1.0)
|
|
21
|
+
power_assert (3.0.1)
|
|
22
|
+
pry (0.16.0)
|
|
23
|
+
coderay (~> 1.1)
|
|
24
|
+
method_source (~> 1.0)
|
|
25
|
+
reline (>= 0.6.0)
|
|
26
|
+
pry-byebug (3.12.0)
|
|
27
|
+
byebug (~> 13.0)
|
|
28
|
+
pry (>= 0.13, < 0.17)
|
|
29
|
+
public_suffix (7.0.5)
|
|
30
|
+
rake (13.4.2)
|
|
31
|
+
reline (0.6.3)
|
|
32
|
+
io-console (~> 0.5)
|
|
33
|
+
rexml (3.4.4)
|
|
34
|
+
test-unit (3.7.8)
|
|
22
35
|
power_assert
|
|
36
|
+
webmock (3.26.2)
|
|
37
|
+
addressable (>= 2.8.0)
|
|
38
|
+
crack (>= 0.3.2)
|
|
39
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
23
40
|
|
|
24
41
|
PLATFORMS
|
|
25
42
|
ruby
|
|
43
|
+
x86_64-darwin-24
|
|
26
44
|
|
|
27
45
|
DEPENDENCIES
|
|
28
|
-
fakeweb
|
|
29
46
|
net-ping!
|
|
30
47
|
pry-byebug
|
|
31
48
|
rake
|
|
32
49
|
test-unit
|
|
50
|
+
webmock
|
|
33
51
|
|
|
34
52
|
BUNDLED WITH
|
|
35
|
-
2.
|
|
53
|
+
2.5.22
|
data/README.md
CHANGED
|
@@ -3,8 +3,10 @@ A collection of classes that provide different ways to ping computers.
|
|
|
3
3
|
|
|
4
4
|
## Prerequisites
|
|
5
5
|
* ffi
|
|
6
|
-
* win32-security (
|
|
7
|
-
*
|
|
6
|
+
* win32-security (installed from the Windows gem artifact)
|
|
7
|
+
* win32ole (installed from the Windows gem artifact)
|
|
8
|
+
* cap2 (installed from the Linux gem artifact)
|
|
9
|
+
* webmock (test only)
|
|
8
10
|
* test-unit (test only)
|
|
9
11
|
|
|
10
12
|
Ruby users should use Ruby 1.9.3 or later.
|
|
@@ -50,7 +52,7 @@ A collection of classes that provide different ways to ping computers.
|
|
|
50
52
|
|
|
51
53
|
## Contributions
|
|
52
54
|
Although this library is free, please consider having your company
|
|
53
|
-
|
|
55
|
+
set up a gittip if used by your company professionally.
|
|
54
56
|
|
|
55
57
|
http://www.gittip.com/djberg96/
|
|
56
58
|
|
data/Rakefile
CHANGED
|
@@ -5,25 +5,110 @@ include Object.const_defined?(:RbConfig) ? RbConfig : Config
|
|
|
5
5
|
|
|
6
6
|
CLEAN.include("**/*.gem", "**/*.rbc")
|
|
7
7
|
|
|
8
|
+
GEMSPEC_FILES = %w[
|
|
9
|
+
net-ping.gemspec
|
|
10
|
+
net-ping-universal-linux.gemspec
|
|
11
|
+
net-ping-universal-mingw-ucrt.gemspec
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
EXPECTED_GEM_METADATA = {
|
|
15
|
+
'net-ping.gemspec' => ['ruby', {}],
|
|
16
|
+
'net-ping-universal-linux.gemspec' => ['universal-linux', {'cap2' => '>= 0.2.2'}],
|
|
17
|
+
'net-ping-universal-mingw-ucrt.gemspec' => [
|
|
18
|
+
'universal-mingw-ucrt',
|
|
19
|
+
{'win32-security' => '>= 0.2.0', 'win32ole' => '>= 1.8.8'}
|
|
20
|
+
]
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
def load_gem_specifications
|
|
24
|
+
GEMSPEC_FILES.map do |path|
|
|
25
|
+
spec = Gem::Specification.load(path)
|
|
26
|
+
abort("Unable to load #{path}") unless spec
|
|
27
|
+
spec
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def with_unbundled_env
|
|
32
|
+
if defined?(Bundler) && Bundler.respond_to?(:with_unbundled_env)
|
|
33
|
+
Bundler.with_unbundled_env { yield }
|
|
34
|
+
elsif defined?(Bundler) && Bundler.respond_to?(:with_clean_env)
|
|
35
|
+
Bundler.with_clean_env { yield }
|
|
36
|
+
else
|
|
37
|
+
yield
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def platform_round_trips?(platform_string)
|
|
42
|
+
Gem::Platform.new(platform_string).to_s == platform_string
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def platform_installable?(spec)
|
|
46
|
+
if Gem::Platform.respond_to?(:installable?)
|
|
47
|
+
Gem::Platform.installable?(spec)
|
|
48
|
+
else
|
|
49
|
+
Gem::Platform.match(spec.platform)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def select_install_specification(specifications = load_gem_specifications)
|
|
54
|
+
specific = specifications.find do |spec|
|
|
55
|
+
spec.platform != Gem::Platform::RUBY && platform_installable?(spec)
|
|
56
|
+
end
|
|
57
|
+
spec = specific || specifications.find { |item| item.platform == Gem::Platform::RUBY }
|
|
58
|
+
abort('Unable to find a Ruby fallback gem specification') unless spec
|
|
59
|
+
spec
|
|
60
|
+
end
|
|
61
|
+
|
|
8
62
|
namespace 'gem' do
|
|
9
|
-
desc 'Create the net-ping gem'
|
|
63
|
+
desc 'Create the net-ping gem artifacts (ruby, universal-linux, universal-mingw-ucrt)'
|
|
10
64
|
task :create => [:clean] do
|
|
11
|
-
|
|
65
|
+
specifications = load_gem_specifications
|
|
12
66
|
if Gem::VERSION.to_f < 2.0
|
|
13
|
-
|
|
67
|
+
specifications.each do |spec|
|
|
68
|
+
Gem::Builder.new(spec).build
|
|
69
|
+
end
|
|
14
70
|
else
|
|
15
71
|
require 'rubygems/package'
|
|
16
|
-
|
|
72
|
+
specifications.each do |spec|
|
|
73
|
+
Gem::Package.build(spec)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
desc 'Validate the net-ping gem artifacts'
|
|
79
|
+
task :check do
|
|
80
|
+
require 'rubygems/package'
|
|
81
|
+
|
|
82
|
+
EXPECTED_GEM_METADATA.each do |path, expectation|
|
|
83
|
+
expected_platform, expected_dependencies = expectation
|
|
84
|
+
artifact = Gem::Specification.load(path).file_name
|
|
85
|
+
packaged_spec = Gem::Package.new(artifact).spec
|
|
86
|
+
actual_dependencies = packaged_spec.runtime_dependencies.each_with_object({}) do |dependency, memo|
|
|
87
|
+
memo[dependency.name] = dependency.requirement.to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if platform_round_trips?(expected_platform) && packaged_spec.platform.to_s != expected_platform
|
|
91
|
+
abort("#{artifact}: expected platform #{expected_platform.inspect}, got #{packaged_spec.platform.to_s.inspect}")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if actual_dependencies != expected_dependencies
|
|
95
|
+
abort("#{artifact}: expected dependencies #{expected_dependencies.inspect}, got #{actual_dependencies.inspect}")
|
|
96
|
+
end
|
|
17
97
|
end
|
|
18
98
|
end
|
|
19
99
|
|
|
20
100
|
desc 'Install the net-ping gem'
|
|
21
101
|
task :install => [:create] do
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
102
|
+
spec = select_install_specification
|
|
103
|
+
|
|
104
|
+
install_command = if RUBY_PLATFORM == 'java'
|
|
105
|
+
['jruby', '-S', 'gem', 'install', '-l', spec.file_name]
|
|
25
106
|
else
|
|
26
|
-
|
|
107
|
+
['gem', 'install', '-l', spec.file_name]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
with_unbundled_env do
|
|
111
|
+
sh(*install_command)
|
|
27
112
|
end
|
|
28
113
|
end
|
|
29
114
|
end
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Platform-specific Gem Dependencies Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Build and validate RubyGems artifacts that install `cap2` on Linux and `win32-security` on current Windows RubyInstaller systems.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Keep `net-ping.gemspec` OS-independent and create two small gemspec overlays for Linux and `mingw-ucrt`. Centralize artifact generation and metadata validation in the Rake gem namespace, then run that validation in the existing Linux/Windows CI matrix.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Ruby, RubyGems (`Gem::Specification`, `Gem::Package`, `Gem::Platform`), Rake, test-unit, GitHub Actions.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- Produce exactly three same-version `net-ping` gems: `ruby`, `universal-linux`, and `universal-mingw-ucrt`.
|
|
14
|
+
- `universal-linux` must add `cap2 (>= 0.2.2)`; `universal-mingw-ucrt` must add `win32-security (>= 0.2.0)`.
|
|
15
|
+
- The Ruby gem must not contain either OS-specific runtime dependency.
|
|
16
|
+
- Support `mingw-ucrt` only; legacy `mingw32` is out of scope.
|
|
17
|
+
- CI builds and validates artifacts but never publishes them.
|
|
18
|
+
- Do not create git commits for this work.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## File Structure
|
|
23
|
+
|
|
24
|
+
| File | Responsibility |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `net-ping.gemspec` | Define the OS-independent Ruby artifact and common metadata. |
|
|
27
|
+
| `net-ping-universal-linux.gemspec` | Overlay `universal-linux` and the `cap2` runtime dependency. |
|
|
28
|
+
| `net-ping-universal-mingw-ucrt.gemspec` | Overlay `universal-mingw-ucrt` and the `win32-security` runtime dependency. |
|
|
29
|
+
| `Rakefile` | Build, inspect, and locally install the platform-appropriate artifact. |
|
|
30
|
+
| `test/test_net_ping_gem_packaging.rb` | Build temporary artifacts and assert their platform/dependency metadata. |
|
|
31
|
+
| `test/test_net_ping.rb` | Load the packaging test in the aggregate suite. |
|
|
32
|
+
| `.github/workflows/test.yml` | Run gem artifact checks on Linux and Windows. |
|
|
33
|
+
| `README.md` | Explain automatic platform-specific dependency installation. |
|
|
34
|
+
| `CHANGES` | Record the metadata correction for the next release. |
|
|
35
|
+
|
|
36
|
+
### Task 1: Define and test platform gem specifications
|
|
37
|
+
|
|
38
|
+
**Files:**
|
|
39
|
+
- Create: `net-ping-universal-linux.gemspec`
|
|
40
|
+
- Create: `net-ping-universal-mingw-ucrt.gemspec`
|
|
41
|
+
- Create: `test/test_net_ping_gem_packaging.rb`
|
|
42
|
+
- Modify: `net-ping.gemspec:1-40`
|
|
43
|
+
- Modify: `test/test_net_ping.rb`
|
|
44
|
+
|
|
45
|
+
**Interfaces:**
|
|
46
|
+
- Consumes: `net-ping.gemspec`, which supplies the shared `Gem::Specification`.
|
|
47
|
+
- Produces: three loadable gemspecs whose `platform` and `runtime_dependencies` describe their target platform.
|
|
48
|
+
|
|
49
|
+
- [ ] **Step 1: Write the failing package-metadata test**
|
|
50
|
+
|
|
51
|
+
Create `test/test_net_ping_gem_packaging.rb`. Load every gemspec before building any artifact so `spec.files` cannot include an artifact created for an earlier specification. Build the loaded specifications into temporary `.gem` files, open each using `Gem::Package`, and assert the platform and runtime dependencies:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require 'rubygems/package'
|
|
55
|
+
require 'test/unit'
|
|
56
|
+
|
|
57
|
+
class TestNetPingGemPackaging < Test::Unit::TestCase
|
|
58
|
+
EXPECTATIONS = {
|
|
59
|
+
'net-ping.gemspec' => ['ruby', {}],
|
|
60
|
+
'net-ping-universal-linux.gemspec' => ['universal-linux', {'cap2' => '>= 0.2.2'}],
|
|
61
|
+
'net-ping-universal-mingw-ucrt.gemspec' => [
|
|
62
|
+
'universal-mingw-ucrt',
|
|
63
|
+
{'win32-security' => '>= 0.2.0'}
|
|
64
|
+
]
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
def setup
|
|
68
|
+
@specifications = EXPECTATIONS.keys.map do |path|
|
|
69
|
+
[path, Gem::Specification.load(path)]
|
|
70
|
+
end
|
|
71
|
+
@gem_files = @specifications.map { |_, spec| Gem::Package.build(spec) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def teardown
|
|
75
|
+
@gem_files.each { |path| File.delete(path) if File.exist?(path) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_platforms_and_runtime_dependencies
|
|
79
|
+
@specifications.each do |path, spec|
|
|
80
|
+
expected_platform, expected_dependencies = EXPECTATIONS.fetch(path)
|
|
81
|
+
packaged_spec = Gem::Package.new(spec.file_name).spec
|
|
82
|
+
dependencies = packaged_spec.runtime_dependencies.to_h do |dependency|
|
|
83
|
+
[dependency.name, dependency.requirement.to_s]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
assert_equal(expected_platform, packaged_spec.platform.to_s, path)
|
|
87
|
+
assert_equal(expected_dependencies, dependencies, path)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add `require 'test_net_ping_gem_packaging'` to `test/test_net_ping.rb`.
|
|
94
|
+
|
|
95
|
+
- [ ] **Step 2: Run the new test to verify it fails**
|
|
96
|
+
|
|
97
|
+
Run:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
bundle exec ruby -Itest test/test_net_ping_gem_packaging.rb
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Expected: failure because the Linux and Windows overlay gemspec files do not exist.
|
|
104
|
+
|
|
105
|
+
- [ ] **Step 3: Make the base gemspec OS-independent and add overlays**
|
|
106
|
+
|
|
107
|
+
Remove the `File::ALT_SEPARATOR`, `RbConfig`, and `RUBY_PLATFORM` conditional runtime dependency logic from `net-ping.gemspec`; leave only shared metadata and development dependencies.
|
|
108
|
+
|
|
109
|
+
Create `net-ping-universal-linux.gemspec`:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
spec = Gem::Specification.load('net-ping.gemspec')
|
|
113
|
+
spec.platform = Gem::Platform.new(['universal', 'linux'])
|
|
114
|
+
spec.add_dependency('cap2', '>= 0.2.2')
|
|
115
|
+
spec
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Create `net-ping-universal-mingw-ucrt.gemspec`:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
spec = Gem::Specification.load('net-ping.gemspec')
|
|
122
|
+
spec.platform = Gem::Platform.new(['universal', 'mingw-ucrt'])
|
|
123
|
+
spec.add_dependency('win32-security', '>= 0.2.0')
|
|
124
|
+
spec
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Use the project’s existing block-style `Gem::Specification.new` format for the base gemspec. Verify the installed RubyGems version accepts the two platform strings with `Gem::Platform.new`.
|
|
128
|
+
|
|
129
|
+
- [ ] **Step 4: Run the package-metadata test to verify it passes**
|
|
130
|
+
|
|
131
|
+
Run:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
bundle exec ruby -Itest test/test_net_ping_gem_packaging.rb
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Expected: PASS; all three artifacts have the expected platform and exactly the expected runtime dependencies.
|
|
138
|
+
|
|
139
|
+
- [ ] **Step 5: Run the aggregate test suite**
|
|
140
|
+
|
|
141
|
+
Run:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
bundle exec rake test
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Expected: PASS.
|
|
148
|
+
|
|
149
|
+
### Task 2: Make Rake build, validate, and install platform artifacts deterministically
|
|
150
|
+
|
|
151
|
+
**Files:**
|
|
152
|
+
- Modify: `Rakefile:6-29`
|
|
153
|
+
|
|
154
|
+
**Interfaces:**
|
|
155
|
+
- Consumes: the three gemspec paths from Task 1.
|
|
156
|
+
- Produces: `gem:create` builds all artifacts; `gem:check` aborts on invalid artifact metadata; `gem:install` installs the local platform’s specific artifact or the Ruby fallback.
|
|
157
|
+
|
|
158
|
+
- [ ] **Step 1: Add a failing artifact-validation command**
|
|
159
|
+
|
|
160
|
+
Add `gem:check` to the `gem` namespace. It must load the three expected gem files with `Gem::Package`, map each runtime dependency to `name => requirement.to_s`, and abort if the platform or dependency hash differs from:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
{
|
|
164
|
+
'ruby' => {},
|
|
165
|
+
'universal-linux' => {'cap2' => '>= 0.2.2'},
|
|
166
|
+
'universal-mingw-ucrt' => {'win32-security' => '>= 0.2.0'}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Run it before changing `gem:create`:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
bundle exec rake clean gem:create gem:check
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Expected: FAIL because `gem:create` still builds only one artifact.
|
|
177
|
+
|
|
178
|
+
- [ ] **Step 2: Implement deterministic specification loading and artifact creation**
|
|
179
|
+
|
|
180
|
+
Define the shared list once in `Rakefile`:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
GEMSPEC_FILES = %w[
|
|
184
|
+
net-ping.gemspec
|
|
185
|
+
net-ping-universal-linux.gemspec
|
|
186
|
+
net-ping-universal-mingw-ucrt.gemspec
|
|
187
|
+
].freeze
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Update `gem:create` to load all files before it builds any artifact:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
specifications = GEMSPEC_FILES.map { |path| Gem::Specification.load(path) }
|
|
194
|
+
specifications.each { |spec| Gem::Package.build(spec) }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Retain the existing RubyGems pre-2.0 builder branch if support for it is still required. In either branch, load every specification before beginning the build loop.
|
|
198
|
+
|
|
199
|
+
Implement `gem:check` using `Gem::Package.new(file).spec`; use `abort` with the artifact filename and expected/actual values when a check fails.
|
|
200
|
+
|
|
201
|
+
Update `gem:install` to load the same specification list and select:
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
specific = specifications.find do |spec|
|
|
205
|
+
spec.platform != Gem::Platform::RUBY && Gem::Platform.installable?(spec)
|
|
206
|
+
end
|
|
207
|
+
spec = specific || specifications.find { |item| item.platform == Gem::Platform::RUBY }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Install `spec.file_name`, not `Dir['*.gem'].first`; abort when no Ruby fallback specification is found.
|
|
211
|
+
|
|
212
|
+
- [ ] **Step 3: Run artifact validation to verify it passes**
|
|
213
|
+
|
|
214
|
+
Run:
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
bundle exec rake gem:create gem:check
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Expected: PASS and creation of `net-ping-<version>.gem`,
|
|
221
|
+
`net-ping-<version>-universal-linux.gem`, and
|
|
222
|
+
`net-ping-<version>-universal-mingw-ucrt.gem`.
|
|
223
|
+
|
|
224
|
+
- [ ] **Step 4: Verify local artifact selection**
|
|
225
|
+
|
|
226
|
+
Run:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
bundle exec rake gem:install
|
|
230
|
+
gem specification net-ping platform
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Expected on Linux: `universal-linux`; on Windows: `universal-mingw-ucrt`; on
|
|
234
|
+
other platforms: `ruby`.
|
|
235
|
+
|
|
236
|
+
- [ ] **Step 5: Re-run tests**
|
|
237
|
+
|
|
238
|
+
Run:
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
bundle exec rake test
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Expected: PASS.
|
|
245
|
+
|
|
246
|
+
### Task 3: Enforce packaging in CI and document the behavior
|
|
247
|
+
|
|
248
|
+
**Files:**
|
|
249
|
+
- Modify: `.github/workflows/test.yml:19-28`
|
|
250
|
+
- Modify: `README.md:4-15`
|
|
251
|
+
- Modify: `CHANGES:1-13`
|
|
252
|
+
|
|
253
|
+
**Interfaces:**
|
|
254
|
+
- Consumes: `gem:create` and `gem:check` from Task 2.
|
|
255
|
+
- Produces: CI verification on both matrix operating systems and accurate end-user dependency documentation.
|
|
256
|
+
|
|
257
|
+
- [ ] **Step 1: Add the CI packaging verification step**
|
|
258
|
+
|
|
259
|
+
After the existing `bundle exec rake test` step, add:
|
|
260
|
+
|
|
261
|
+
```yaml
|
|
262
|
+
- run: bundle exec rake gem:create gem:check
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Do not add RubyGems credentials, publishing actions, or tag triggers.
|
|
266
|
+
|
|
267
|
+
- [ ] **Step 2: Document platform-specific dependency resolution**
|
|
268
|
+
|
|
269
|
+
Replace the prerequisite list’s unconditional `win32-security (MS Windows
|
|
270
|
+
only)` wording with text that states RubyGems installs `win32-security` from
|
|
271
|
+
the Windows artifact and `cap2` from the Linux artifact when installing
|
|
272
|
+
`net-ping`. Keep the installation command `gem install net-ping`.
|
|
273
|
+
|
|
274
|
+
At the beginning of `CHANGES`, add:
|
|
275
|
+
|
|
276
|
+
```text
|
|
277
|
+
== Next Release
|
|
278
|
+
* Publish platform-specific gem metadata so Linux installs cap2 and current
|
|
279
|
+
Windows RubyInstaller installs win32-security for ICMP support.
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
- [ ] **Step 3: Run targeted packaging and full test verification**
|
|
283
|
+
|
|
284
|
+
Run:
|
|
285
|
+
|
|
286
|
+
```sh
|
|
287
|
+
bundle exec rake gem:create gem:check
|
|
288
|
+
bundle exec rake test
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Expected: both commands PASS.
|
|
292
|
+
|
|
293
|
+
- [ ] **Step 4: Inspect the final diff without committing**
|
|
294
|
+
|
|
295
|
+
Run:
|
|
296
|
+
|
|
297
|
+
```sh
|
|
298
|
+
git diff --check
|
|
299
|
+
git diff -- net-ping.gemspec net-ping-universal-linux.gemspec \
|
|
300
|
+
net-ping-universal-mingw-ucrt.gemspec Rakefile \
|
|
301
|
+
test/test_net_ping_gem_packaging.rb test/test_net_ping.rb \
|
|
302
|
+
.github/workflows/test.yml README.md CHANGES
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Expected: only the planned packaging, CI, test, and documentation changes;
|
|
306
|
+
no whitespace errors and no git commit.
|
|
307
|
+
|
|
308
|
+
## Plan Self-Review
|
|
309
|
+
|
|
310
|
+
- **Spec coverage:** Task 1 creates the three required artifacts and assigns
|
|
311
|
+
their dependencies; Task 2 validates metadata and selects a local artifact;
|
|
312
|
+
Task 3 runs validation in CI and documents the behavior. CI publishing,
|
|
313
|
+
legacy `mingw32`, and runtime protocol changes are excluded.
|
|
314
|
+
- **Placeholder scan:** No unresolved item, unspecified test, or ambiguous
|
|
315
|
+
implementation step remains.
|
|
316
|
+
- **Consistency:** The gemspec filenames, platform names, dependency
|
|
317
|
+
versions, and Rake task names are identical across all tasks.
|