net-ping 2.0.9 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3139e0db447950138a58ab9e60996ef49a89fc89e157ef1b66bf67ef5557450
4
- data.tar.gz: 7529e34db8bf6d258a830fd725969af4dd6eee3ee59a500423e1f13256372079
3
+ metadata.gz: 12d4bcbcdb97fb3b116be13a5bc7ad632b4efc116127d9b5859531b5605be3ae
4
+ data.tar.gz: 22603f15d676ac4e3a4137a0bdec76019b7a52b8ae5ca028b452b8760ad6bd15
5
5
  SHA512:
6
- metadata.gz: '0947a086f3da9bb83a81f16e84d4e5fa761508f6a71109051e2ec315c972c83806085863a67d4cc5299e7c337a8ecef9f4bf8aa4afd907064bbd589dc9ff7966'
7
- data.tar.gz: d16d032dcea9783d50305592c6dd4242436a1357f73233b2af787fafc68a03c6d408f5c1d3b328b2cc62395a7f7f64acd8ca4915fee647154fbb25b0474f98eb
6
+ metadata.gz: ab74625d886822f7801e5c9c6e7704664bb789f745b47a29ec54cf8e7baa4cbb1a86c332df8bc16a4757900987dc3389642c290cf4d38d98badbc1e60df7ffa1
7
+ data.tar.gz: bb55d09ac91ec4ac1e407e7050f655d7fd305f3fcab3fa2093613745509724d138b25b22282d2d00d63eb5880d50814d7bfe0ac4d9e414904fbeb2d0e2618ec5
data/CHANGES CHANGED
@@ -1,3 +1,25 @@
1
+ == 2.1.1 - 16-Aug-2026
2
+ * Fix the license format in net-ping.gemspec to use the SPDX identifier
3
+ "Artistic-2.0" [#47](https://github.com/eitoball/net-ping/pull/47).
4
+ * Exclude CLAUDE.md and docs/ from the packaged gem files
5
+ [#48](https://github.com/eitoball/net-ping/pull/48).
6
+
7
+ == 2.1.0 - 08-Aug-2026
8
+ * Publish platform-specific gem metadata so Linux installs cap2 and current
9
+ Windows RubyInstaller installs win32-security for ICMP support
10
+ [#44](https://github.com/eitoball/net-ping/pull/44).
11
+ * Fix the FreeBSD ping6 timeout option
12
+ [#43](https://github.com/eitoball/net-ping/pull/43).
13
+ * Add Ruby 4.0 to the test matrix and add win32ole as an explicit Windows
14
+ dependency, since it is no longer a default gem as of Ruby 4.0
15
+ [#41](https://github.com/eitoball/net-ping/pull/41).
16
+ * Move Net::Ping::VERSION into its own file so the gemspec version can no
17
+ longer drift out of sync with it
18
+ [#37](https://github.com/eitoball/net-ping/pull/37).
19
+ * Fix `Net::Ping::External#ping6` setting a spurious "undefined method '=~'
20
+ for false" exception on success
21
+ [#39](https://github.com/eitoball/net-ping/pull/39).
22
+
1
23
  == 2.0.9 - 25-Jul-2026
2
24
  * Add GitHub Actions CI [#33](https://github.com/eitoball/net-ping/pull/33)
3
25
  and update its supported Ruby versions [#38](https://github.com/eitoball/net-ping/pull/38).
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,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- net-ping (2.0.9)
4
+ net-ping (2.1.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -3,7 +3,9 @@ A collection of classes that provide different ways to ping computers.
3
3
 
4
4
  ## Prerequisites
5
5
  * ffi
6
- * win32-security (MS Windows only)
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)
7
9
  * webmock (test only)
8
10
  * test-unit (test only)
9
11
 
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
- spec = eval(IO.read('net-ping.gemspec'))
65
+ specifications = load_gem_specifications
12
66
  if Gem::VERSION.to_f < 2.0
13
- Gem::Builder.new(spec).build
67
+ specifications.each do |spec|
68
+ Gem::Builder.new(spec).build
69
+ end
14
70
  else
15
71
  require 'rubygems/package'
16
- Gem::Package.build(spec)
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
- gem_file = Dir["*.gem"].first
23
- if RUBY_PLATFORM == 'java'
24
- sh "jruby -S gem install -l #{gem_file}"
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
- sh "gem install -l #{gem_file}"
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
@@ -66,7 +66,7 @@ module Net
66
66
  bool = true # Success, at least one response.
67
67
  end
68
68
 
69
- if err & (err =~ /warning/i)
69
+ if err && (err =~ /warning/i)
70
70
  @warning = err.chomp
71
71
  end
72
72
  when 2
@@ -116,6 +116,8 @@ module Net
116
116
  pcmd += ['-i', interval.to_s] unless RbConfig::CONFIG['busybox']
117
117
  when /aix/i
118
118
  pcmd += ['-c', count.to_s, '-w', timeout.to_s, host]
119
+ when /freebsd/i
120
+ pcmd += ['-c', count.to_s, '-x', timeout.to_s, host]
119
121
  when /bsd|osx|mach|darwin/i
120
122
  pcmd += ['-c', count.to_s, '-i', interval.to_s, host]
121
123
  when /solaris|sunos/i
@@ -147,7 +149,7 @@ module Net
147
149
  bool = true # Success, at least one response.
148
150
  end
149
151
 
150
- if err & err =~ /warning/i
152
+ if err && (err =~ /warning/i)
151
153
  @warning = err.chomp
152
154
  end
153
155
  when 2
data/lib/net/ping/ping.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'socket'
2
2
  require 'timeout'
3
3
 
4
+ require_relative 'version'
5
+
4
6
  # The Net module serves as a namespace only.
5
7
  #
6
8
  module Net
@@ -9,9 +11,6 @@ module Net
9
11
  # types. You should not instantiate this class directly.
10
12
  #
11
13
  class Ping
12
- # The version of the net-ping library.
13
- VERSION = '2.0.9'
14
-
15
14
  # The host to ping. In the case of Ping::HTTP, this is the URI.
16
15
  attr_accessor :host
17
16
 
@@ -0,0 +1,6 @@
1
+ module Net
2
+ class Ping
3
+ # The version of the net-ping library.
4
+ VERSION = '2.1.1'
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'linux'])
3
+ spec.add_dependency('cap2', '>= 0.2.2')
4
+ spec
@@ -0,0 +1,7 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'mingw-ucrt'])
3
+ spec.add_dependency('win32-security', '>= 0.2.0')
4
+
5
+ # No longer a default gem as of Ruby 4.0. Used by the WMI ping class.
6
+ spec.add_dependency('win32ole', '>= 1.8.8')
7
+ spec
data/net-ping.gemspec CHANGED
@@ -1,15 +1,17 @@
1
- require 'rbconfig'
1
+ require_relative "lib/net/ping/version"
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'net-ping'
5
- spec.version = '2.0.9'
6
- spec.license = 'Artistic 2.0'
5
+ spec.version = Net::Ping::VERSION
6
+ spec.license = 'Artistic-2.0'
7
7
  spec.author = 'Chris Chernesky'
8
8
  spec.email = 'chris.netping@tinderglow.com'
9
9
  spec.homepage = 'https://github.com/chernesk/net-ping'
10
10
  spec.summary = 'A ping interface for Ruby.'
11
11
  spec.test_file = 'test/test_net_ping.rb'
12
- spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
12
+ spec.files = Dir['**/*'].reject do |f|
13
+ f.include?('git') || File.extname(f) == '.gem' || f == 'CLAUDE.md' || f == 'docs' || f.start_with?('docs/')
14
+ end
13
15
  spec.metadata = {
14
16
  'bug_tracker_uri' => "#{spec.homepage}/issues",
15
17
  'changelog_uri' => "#{spec.homepage}/blob/master/CHANGES",
@@ -28,17 +30,6 @@ Gem::Specification.new do |spec|
28
30
  spec.add_development_dependency('rake', '>= 0')
29
31
  spec.add_development_dependency('pry-byebug', '>= 0')
30
32
 
31
- if File::ALT_SEPARATOR
32
- require 'rbconfig'
33
- arch = RbConfig::CONFIG['build_os'] || 'mingw32' # JRuby
34
- spec.platform = Gem::Platform.new(['universal', arch])
35
- spec.platform.version = nil
36
-
37
- # Used for icmp pings.
38
- spec.add_dependency('win32-security', '>= 0.2.0')
39
- end
40
- spec.add_dependency('cap2', '>= 0.2.2') if RUBY_PLATFORM =~ /linux/i
41
-
42
33
  spec.description = <<-EOF
43
34
  The net-ping library provides a ping interface for Ruby. It includes
44
35
  separate TCP, HTTP, LDAP, ICMP, UDP, WMI (for Windows) and external ping
@@ -5,6 +5,7 @@
5
5
  # class test won't be run unless this is run as a privileged process.
6
6
  ######################################################################
7
7
  require 'test_net_ping_external'
8
+ require 'test_net_ping_gem_packaging'
8
9
  require 'test_net_ping_http'
9
10
  require 'test_net_ping_tcp'
10
11
  require 'test_net_ping_udp'
@@ -38,6 +39,6 @@ end
38
39
 
39
40
  class TC_Net_Ping < Test::Unit::TestCase
40
41
  def test_net_ping_version
41
- assert_equal('2.0.9', Net::Ping::VERSION)
42
+ assert_equal(Gem::Specification.load('net-ping.gemspec').version.to_s, Net::Ping::VERSION)
42
43
  end
43
44
  end
@@ -140,6 +140,30 @@ class TC_Net_Ping_External < Test::Unit::TestCase
140
140
  assert_false(@bad.ping?)
141
141
  end
142
142
 
143
+ test "ping6 uses timeout for FreeBSD" do
144
+ command = nil
145
+ original_os = RbConfig::CONFIG['host_os']
146
+ original_popen3 = Open3.method(:popen3)
147
+
148
+ RbConfig::CONFIG['host_os'] = 'freebsd'
149
+ Open3.define_singleton_method(:popen3) do |*args, &block|
150
+ command = args
151
+ stdin = StringIO.new
152
+ stdout = StringIO.new
153
+ stderr = StringIO.new
154
+ status = Struct.new(:exitstatus).new(0)
155
+ thread = Struct.new(:value).new(status)
156
+ block.call(stdin, stdout, stderr, thread)
157
+ end
158
+
159
+ @pe.ping6('example.test', 2, 3, 4)
160
+
161
+ assert_equal(['ping6', '-c', '2', '-x', '4', 'example.test'], command)
162
+ ensure
163
+ RbConfig::CONFIG['host_os'] = original_os
164
+ Open3.define_singleton_method(:popen3, original_popen3)
165
+ end
166
+
143
167
  test "ping6 uses interval for macOS" do
144
168
  command = nil
145
169
  original_os = RbConfig::CONFIG['host_os']
@@ -164,6 +188,41 @@ class TC_Net_Ping_External < Test::Unit::TestCase
164
188
  Open3.define_singleton_method(:popen3, original_popen3)
165
189
  end
166
190
 
191
+ test "ping6 succeeds without an exception when stderr is empty" do
192
+ stdin = StringIO.new
193
+ stdout = StringIO.new('64 bytes from ::1')
194
+ stderr = StringIO.new
195
+ status = Struct.new(:exitstatus).new(0)
196
+ thread = Struct.new(:value).new(status)
197
+ popen3 = Open3.method(:popen3)
198
+ nil_match = NilClass.instance_method(:=~) if NilClass.instance_methods(false).include?(:=~)
199
+ false_match = FalseClass.instance_method(:=~) if FalseClass.instance_methods(false).include?(:=~)
200
+
201
+ Open3.singleton_class.send(:define_method, :popen3) do |*args, &block|
202
+ block.call(stdin, stdout, stderr, thread)
203
+ end
204
+ [NilClass, FalseClass].each do |klass|
205
+ klass.send(:define_method, :=~) do |*args|
206
+ raise NoMethodError, "undefined method '=~' for #{self.inspect}"
207
+ end
208
+ end
209
+
210
+ assert_true(@pe.ping6('::1'))
211
+ assert_nil(@pe.exception)
212
+ ensure
213
+ Open3.singleton_class.send(:define_method, :popen3, popen3) if popen3
214
+ if nil_match
215
+ NilClass.send(:define_method, :=~, nil_match)
216
+ else
217
+ NilClass.send(:remove_method, :=~)
218
+ end
219
+ if false_match
220
+ FalseClass.send(:define_method, :=~, false_match)
221
+ else
222
+ FalseClass.send(:remove_method, :=~)
223
+ end
224
+ end
225
+
167
226
  def teardown
168
227
  @host = nil
169
228
  @bogus = nil
@@ -0,0 +1,343 @@
1
+ require 'open3'
2
+ require 'rake'
3
+ require 'rubygems/package'
4
+ require 'test/unit'
5
+
6
+ class TestNetPingGemPackaging < Test::Unit::TestCase
7
+ GemfileRecorder = Struct.new(:dependencies) do
8
+ def initialize
9
+ super({})
10
+ end
11
+
12
+ def source(*); end
13
+ def gemspec(*); end
14
+
15
+ def gem(name, *requirements)
16
+ dependencies[name] = requirements
17
+ end
18
+ end
19
+
20
+ EXPECTATIONS = {
21
+ 'net-ping.gemspec' => ['ruby', {}],
22
+ 'net-ping-universal-linux.gemspec' => ['universal-linux', {'cap2' => '>= 0.2.2'}],
23
+ 'net-ping-universal-mingw-ucrt.gemspec' => [
24
+ 'universal-mingw-ucrt',
25
+ {'win32-security' => '>= 0.2.0', 'win32ole' => '>= 1.8.8'}
26
+ ]
27
+ }.freeze
28
+ ROOT = File.expand_path('..', __dir__)
29
+
30
+ def test_platforms_and_runtime_dependencies
31
+ gem_files = nil
32
+ specifications = load_specifications
33
+
34
+ Dir.chdir(ROOT) do
35
+ gem_files = specifications.map { |_, spec| Gem::Package.build(spec) }
36
+ end
37
+
38
+ specifications.each do |path, spec|
39
+ expected_platform, expected_dependencies = EXPECTATIONS.fetch(path)
40
+ packaged_spec = Gem::Package.new(File.join(ROOT, spec.file_name)).spec
41
+ dependencies = packaged_spec.runtime_dependencies.each_with_object({}) do |dependency, memo|
42
+ memo[dependency.name] = dependency.requirement.to_s
43
+ end
44
+
45
+ assert_equal(expected_dependencies, dependencies, path)
46
+
47
+ if platform_round_trips_for_test?(expected_platform)
48
+ assert_equal(expected_platform, packaged_spec.platform.to_s, path)
49
+ else
50
+ omit("this RubyGems (#{Gem::VERSION}) cannot round-trip the #{expected_platform.inspect} platform string")
51
+ end
52
+ end
53
+ ensure
54
+ delete_files(gem_files)
55
+ end
56
+
57
+ def test_rake_create_builds_all_expected_artifacts_and_validates_them
58
+ stdout, stderr, status = run_rake('clean', 'gem:create', 'gem:check')
59
+
60
+ assert(status.success?, [stdout, stderr].join)
61
+ assert_equal(expected_gem_files, built_gem_files)
62
+ ensure
63
+ delete_files(built_gem_files)
64
+ end
65
+
66
+ def test_gem_create_excludes_generated_artifacts_from_spec_files_and_keeps_bundle_exec_usable
67
+ stdout, stderr, status = run_rake('clean', 'gem:create')
68
+
69
+ assert(status.success?, [stdout, stderr].join)
70
+ load_specifications.each do |path, spec|
71
+ assert_equal([], spec.files.grep(/\.gem$/).sort, path)
72
+ end
73
+
74
+ stdout, stderr, status = run_bundle_exec('ruby', '-e', 'puts :bundle_exec_after_gem_create')
75
+ assert(status.success?, [stdout, stderr].join)
76
+ assert_equal("bundle_exec_after_gem_create\n", stdout)
77
+ ensure
78
+ delete_files(built_gem_files)
79
+ end
80
+
81
+ def test_gem_create_excludes_non_distributable_project_files_from_spec_files
82
+ load_specifications.each do |path, spec|
83
+ non_distributable = spec.files.select do |f|
84
+ f == 'CLAUDE.md' || f == 'docs' || f.start_with?('docs/')
85
+ end
86
+
87
+ assert_equal([], non_distributable, path)
88
+ end
89
+ end
90
+
91
+ def test_gem_check_uses_fixed_expectations_instead_of_loaded_specifications
92
+ stdout, stderr, status = run_rake('clean', 'gem:create')
93
+
94
+ assert(status.success?, [stdout, stderr].join)
95
+
96
+ specifications = load_specifications.map do |path, spec|
97
+ if path == 'net-ping-universal-linux.gemspec'
98
+ [path, specification_with_reported_platform(spec, Gem::Platform::RUBY)]
99
+ else
100
+ [path, spec]
101
+ end
102
+ end
103
+
104
+ with_rakefile do |application|
105
+ with_stubbed_load_gem_specifications(specifications.map(&:last)) do
106
+ assert_nothing_raised { application['gem:check'].invoke }
107
+ end
108
+ end
109
+ ensure
110
+ delete_files(built_gem_files)
111
+ end
112
+
113
+ def test_gem_install_selects_local_compatible_specification
114
+ with_rakefile do
115
+ assert_equal(expected_install_platform, select_install_specification.platform.to_s)
116
+ end
117
+ end
118
+
119
+ def test_gemfile_adds_win32_security_only_for_windows_development
120
+ assert_nil(gemfile_dependencies_for(win_platform: false)['win32-security'])
121
+ assert_equal(
122
+ ['>= 0.2.0'],
123
+ gemfile_dependencies_for(win_platform: true)['win32-security']
124
+ )
125
+ end
126
+
127
+ def test_with_unbundled_env_prefers_with_unbundled_env_when_available
128
+ calls = []
129
+
130
+ with_rakefile do
131
+ with_stubbed_bundler_methods(
132
+ :with_unbundled_env => proc do |&block|
133
+ calls << :with_unbundled_env
134
+ block.call
135
+ end,
136
+ :with_clean_env => proc do |&block|
137
+ calls << :with_clean_env
138
+ block.call
139
+ end
140
+ ) do
141
+ assert_equal(:ran, with_unbundled_env { calls << :block; :ran })
142
+ end
143
+ end
144
+
145
+ assert_equal([:with_unbundled_env, :block], calls)
146
+ end
147
+
148
+ def test_with_unbundled_env_falls_back_to_with_clean_env
149
+ calls = []
150
+
151
+ with_rakefile do
152
+ with_stubbed_bundler_methods(
153
+ :with_clean_env => proc do |&block|
154
+ calls << :with_clean_env
155
+ block.call
156
+ end
157
+ ) do
158
+ assert_equal(:ran, with_unbundled_env { calls << :block; :ran })
159
+ end
160
+ end
161
+
162
+ assert_equal([:with_clean_env, :block], calls)
163
+ end
164
+
165
+ def test_platform_installable_prefers_installable_when_available
166
+ spec = Struct.new(:platform).new(:preferred_platform)
167
+ calls = []
168
+
169
+ with_rakefile do
170
+ with_stubbed_platform_methods(
171
+ :installable? => proc do |candidate|
172
+ calls << [:installable?, candidate.platform]
173
+ true
174
+ end,
175
+ :match => proc do |platform|
176
+ calls << [:match, platform]
177
+ false
178
+ end
179
+ ) do
180
+ assert_equal(true, platform_installable?(spec))
181
+ end
182
+ end
183
+
184
+ assert_equal([[:installable?, :preferred_platform]], calls)
185
+ end
186
+
187
+ def test_platform_installable_falls_back_to_match
188
+ spec = Struct.new(:platform).new(:fallback_platform)
189
+ calls = []
190
+
191
+ with_rakefile do
192
+ with_stubbed_platform_methods(
193
+ :match => proc do |platform|
194
+ calls << [:match, platform]
195
+ true
196
+ end
197
+ ) do
198
+ assert_equal(true, platform_installable?(spec))
199
+ end
200
+ end
201
+
202
+ assert_equal([[:match, :fallback_platform]], calls)
203
+ end
204
+
205
+ private
206
+
207
+ def load_specifications
208
+ Dir.chdir(ROOT) do
209
+ EXPECTATIONS.keys.map do |path|
210
+ assert(File.exist?(path), "#{path} does not exist")
211
+
212
+ loaded_spec = Gem::Specification.load(path)
213
+ spec = loaded_spec ? loaded_spec.dup : nil
214
+ assert_not_nil(spec, "expected #{path} to load")
215
+
216
+ [path, spec]
217
+ end
218
+ end
219
+ end
220
+
221
+ def expected_gem_files
222
+ load_specifications.map { |_, spec| spec.file_name }.sort
223
+ end
224
+
225
+ def built_gem_files
226
+ Dir.chdir(ROOT) { Dir['net-ping-*.gem'].sort }
227
+ end
228
+
229
+ def expected_install_platform
230
+ specifications = load_specifications.map(&:last)
231
+ specific = specifications.find do |spec|
232
+ spec.platform != Gem::Platform::RUBY && platform_installable_for_test?(spec)
233
+ end
234
+ (specific || specifications.find { |spec| spec.platform == Gem::Platform::RUBY }).platform.to_s
235
+ end
236
+
237
+ def run_rake(*tasks, env: {})
238
+ Open3.capture3(env, Gem.ruby, '-S', 'bundle', 'exec', 'rake', *tasks, chdir: ROOT)
239
+ end
240
+
241
+ def run_bundle_exec(*command, env: {})
242
+ Open3.capture3(env, Gem.ruby, '-S', 'bundle', 'exec', *command, chdir: ROOT)
243
+ end
244
+
245
+ def with_rakefile
246
+ original = Rake.application
247
+ application = Rake::Application.new
248
+ Rake.application = application
249
+
250
+ Dir.chdir(ROOT) do
251
+ load File.join(ROOT, 'Rakefile')
252
+ yield(application)
253
+ end
254
+ ensure
255
+ Rake.application = original
256
+ end
257
+
258
+ def gemfile_dependencies_for(win_platform:)
259
+ recorder = GemfileRecorder.new
260
+ singleton_class = class << Gem; self; end
261
+ original = singleton_class.instance_method(:win_platform?)
262
+ singleton_class.send(:define_method, :win_platform?) { win_platform }
263
+ recorder.instance_eval(File.read(File.join(ROOT, 'Gemfile')), File.join(ROOT, 'Gemfile'))
264
+
265
+ recorder.dependencies
266
+ ensure
267
+ singleton_class.send(:define_method, :win_platform?, original) if singleton_class && original
268
+ end
269
+
270
+ def delete_files(paths)
271
+ Array(paths).each do |path|
272
+ file = File.join(ROOT, path)
273
+ File.delete(file) if File.exist?(file)
274
+ end
275
+ end
276
+
277
+ def specification_with_reported_platform(spec, platform)
278
+ file_name = spec.file_name
279
+ mutated = spec.dup
280
+ mutated.platform = platform
281
+ mutated.define_singleton_method(:file_name) { file_name }
282
+ mutated
283
+ end
284
+
285
+ def with_stubbed_load_gem_specifications(specifications)
286
+ original = Object.instance_method(:load_gem_specifications)
287
+ Object.send(:remove_method, :load_gem_specifications)
288
+ Object.send(:define_method, :load_gem_specifications) { specifications }
289
+ Object.send(:private, :load_gem_specifications)
290
+ yield
291
+ ensure
292
+ Object.send(:remove_method, :load_gem_specifications)
293
+ Object.send(:define_method, :load_gem_specifications, original)
294
+ Object.send(:private, :load_gem_specifications)
295
+ end
296
+
297
+ def with_stubbed_bundler_methods(methods)
298
+ bundler = Module.new
299
+ methods.each do |name, implementation|
300
+ bundler.define_singleton_method(name, &implementation)
301
+ end
302
+
303
+ with_replaced_constant(Object, :Bundler, bundler) do
304
+ yield
305
+ end
306
+ end
307
+
308
+ def with_stubbed_platform_methods(methods)
309
+ platform = Module.new
310
+ methods.each do |name, implementation|
311
+ platform.define_singleton_method(name, &implementation)
312
+ end
313
+ platform.const_set(:RUBY, Gem::Platform::RUBY)
314
+
315
+ with_replaced_constant(Gem, :Platform, platform) do
316
+ yield
317
+ end
318
+ end
319
+
320
+ def with_replaced_constant(container, name, replacement)
321
+ original = container.const_get(name) if container.const_defined?(name, false)
322
+ container.send(:remove_const, name) if container.const_defined?(name, false)
323
+ container.const_set(name, replacement)
324
+ yield
325
+ ensure
326
+ container.send(:remove_const, name) if container.const_defined?(name, false)
327
+ if original
328
+ container.const_set(name, original)
329
+ end
330
+ end
331
+
332
+ def platform_round_trips_for_test?(platform_string)
333
+ Gem::Platform.new(platform_string).to_s == platform_string
334
+ end
335
+
336
+ def platform_installable_for_test?(spec)
337
+ if Gem::Platform.respond_to?(:installable?)
338
+ Gem::Platform.installable?(spec)
339
+ else
340
+ Gem::Platform.match(spec.platform)
341
+ end
342
+ end
343
+ end
@@ -131,12 +131,11 @@ class TC_Net_Ping_HTTP < Test::Unit::TestCase
131
131
  assert_equal(5, @bad.timeout)
132
132
  end
133
133
 
134
- # TODO: Figure out how to do this with WebMock.
135
134
  test 'ping fails if timeout exceeded' do
136
- WebMock.allow_net_connect!
135
+ stub_request(:head, 'https://www.google.com/').to_timeout
137
136
  @http = Net::Ping::HTTP.new('https://www.google.com', 443, 0.001)
138
137
  assert_false(@http.ping?)
139
- assert(['Failed to open TCP connection to www.google.com:443 (execution expired)', 'execution expired', 'Net::OpenTimeout'].include?(@http.exception))
138
+ assert_include(['execution expired', 'Net::OpenTimeout'], @http.exception)
140
139
  end
141
140
 
142
141
  test 'exception attribute basic functionality' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ping
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.9
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Chernesky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-25 00:00:00.000000000 Z
11
+ date: 2026-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -97,10 +97,14 @@ files:
97
97
  - lib/net/ping/ping.rb
98
98
  - lib/net/ping/tcp.rb
99
99
  - lib/net/ping/udp.rb
100
+ - lib/net/ping/version.rb
100
101
  - lib/net/ping/wmi.rb
102
+ - net-ping-universal-linux.gemspec
103
+ - net-ping-universal-mingw-ucrt.gemspec
101
104
  - net-ping.gemspec
102
105
  - test/test_net_ping.rb
103
106
  - test/test_net_ping_external.rb
107
+ - test/test_net_ping_gem_packaging.rb
104
108
  - test/test_net_ping_http.rb
105
109
  - test/test_net_ping_icmp.rb
106
110
  - test/test_net_ping_tcp.rb
@@ -108,7 +112,7 @@ files:
108
112
  - test/test_net_ping_wmi.rb
109
113
  homepage: https://github.com/chernesk/net-ping
110
114
  licenses:
111
- - Artistic 2.0
115
+ - Artistic-2.0
112
116
  metadata:
113
117
  bug_tracker_uri: https://github.com/chernesk/net-ping/issues
114
118
  changelog_uri: https://github.com/chernesk/net-ping/blob/master/CHANGES