New Upstream Release - ruby-async-io

Ready changes

Summary

Merged new upstream version: 1.34.3 (was: 1.34.1).

Resulting package

Built on 2023-05-22T16:45 (took 4m30s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ruby-async-io

Lintian Result

Diff

diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 538ba2b..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-root = true
-
-[*]
-indent_style = tab
-indent_size = 2
diff --git a/.github/workflows/async-head.yml b/.github/workflows/async-head.yml
deleted file mode 100644
index 8b8541a..0000000
--- a/.github/workflows/async-head.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Async head
-
-on: [push, pull_request]
-
-jobs:
-  test:
-    runs-on: ${{matrix.os}}-latest
-    
-    strategy:
-      matrix:
-        os:
-          - ubuntu
-        
-        ruby:
-          - head
-    
-    env:
-      BUNDLE_GEMFILE: gems/async-head.rb
-    
-    steps:
-    - uses: actions/checkout@v2
-    - uses: ruby/setup-ruby@v1
-      with:
-        ruby-version: ${{matrix.ruby}}
-        bundler-cache: true
-    
-    - name: Run tests
-      timeout-minutes: 5
-      run: bundle exec rspec
diff --git a/.github/workflows/async-v1.yml b/.github/workflows/async-v1.yml
deleted file mode 100644
index e013d50..0000000
--- a/.github/workflows/async-v1.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Async v1
-
-on: [push, pull_request]
-
-jobs:
-  test:
-    runs-on: ${{matrix.os}}-latest
-    
-    strategy:
-      matrix:
-        os:
-          - ubuntu
-        
-        ruby:
-          - 2.7
-    
-    env:
-      BUNDLE_GEMFILE: gems/async-v1.rb
-    
-    steps:
-    - uses: actions/checkout@v2
-    - uses: ruby/setup-ruby@v1
-      with:
-        ruby-version: ${{matrix.ruby}}
-        bundler-cache: true
-    
-    - name: Run tests
-      timeout-minutes: 5
-      run: bundle exec rspec
diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml
deleted file mode 100644
index 78e0341..0000000
--- a/.github/workflows/development.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-name: Development
-
-on: [push, pull_request]
-
-jobs:
-  test:
-    name: ${{matrix.ruby}} on ${{matrix.os}}
-    runs-on: ${{matrix.os}}-latest
-    continue-on-error: ${{matrix.experimental}}
-    
-    strategy:
-      matrix:
-        os:
-          - ubuntu
-          - macos
-        
-        ruby:
-          - "2.6"
-          - "2.7"
-          - "3.0"
-          - "3.1"
-          - "3.2"
-        
-        experimental: [false]
-        env: [""]
-        
-        include:
-          - os: ubuntu
-            ruby: truffleruby
-            experimental: true
-            env: JRUBY_OPTS="--debug -X+O"
-          - os: ubuntu
-            ruby: jruby
-            experimental: true
-            env: 'JRUBY_OPTS="-X+O --debug"'
-          - os: ubuntu
-            ruby: head
-            experimental: true
-    
-    steps:
-    - uses: actions/checkout@v2
-    - uses: ruby/setup-ruby@v1
-      with:
-        ruby-version: ${{matrix.ruby}}
-        bundler-cache: true
-    
-    - name: Run tests
-      timeout-minutes: 5
-      run: ${{matrix.env}} bundle exec rspec
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
deleted file mode 100644
index 61956e9..0000000
--- a/.github/workflows/documentation.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: Documentation
-
-on:
-  push:
-    branches:
-      - main
-
-jobs:
-  deploy:
-    runs-on: ubuntu-latest
-    
-    steps:
-    - uses: actions/checkout@v2
-    - uses: ruby/setup-ruby@v1
-      env:
-        BUNDLE_WITH: maintenance
-      with:
-        ruby-version: 3.0
-        bundler-cache: true
-    
-    - name: Installing packages
-      run: sudo apt-get install wget
-    
-    - name: Generate documentation
-      timeout-minutes: 5
-      run: bundle exec bake utopia:project:static
-    
-    - name: Deploy documentation
-      uses: JamesIves/github-pages-deploy-action@4.0.0
-      with:
-        branch: docs
-        folder: docs
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c9e5385..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-/.bundle/
-/.yardoc
-/gems.locked
-/_yardoc/
-/coverage/
-/doc/
-/pkg/
-/spec/reports/
-/tmp/
-
-# rspec failure tracking
-.rspec_status
-.tags
diff --git a/.rspec b/.rspec
deleted file mode 100644
index 8fbe32d..0000000
--- a/.rspec
+++ /dev/null
@@ -1,3 +0,0 @@
---format documentation
---warnings
---require spec_helper
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index b45d33e..0000000
--- a/README.md
+++ /dev/null
@@ -1,167 +0,0 @@
-# Async::IO
-
-Async::IO provides builds on [async](https://github.com/socketry/async) and provides asynchronous wrappers for `IO`, `Socket`, and related classes.
-
-[![Development Status](https://github.com/socketry/async-io/workflows/Development/badge.svg)](https://github.com/socketry/async-io/actions?workflow=Development)
-
-## Installation
-
-Add this line to your application's Gemfile:
-
-``` ruby
-gem 'async-io'
-```
-
-And then execute:
-
-    $ bundle
-
-Or install it yourself as:
-
-    $ gem install async-io
-
-## Usage
-
-Basic echo server (from `spec/async/io/echo_spec.rb`):
-
-``` ruby
-require 'async/io'
-
-def echo_server(endpoint)
-  Async do |task|
-    # This is a synchronous block within the current task:
-    endpoint.accept do |client|
-      # This is an asynchronous block within the current reactor:
-      data = client.read
-
-      # This produces out-of-order responses.
-      task.sleep(rand * 0.01)
-
-      client.write(data.reverse)
-      client.close_write
-    end
-  end
-end
-
-def echo_client(endpoint, data)
-  Async do |task|
-    endpoint.connect do |peer|
-      peer.write(data)
-      peer.close_write
-
-      message = peer.read
-
-      puts "Sent #{data}, got response: #{message}"
-    end
-  end
-end
-
-Async do
-  endpoint = Async::IO::Endpoint.tcp('0.0.0.0', 9000)
-
-  server = echo_server(endpoint)
-
-  5.times.map do |i|
-    echo_client(endpoint, "Hello World #{i}")
-  end.each(&:wait)
-
-  server.stop
-end
-```
-
-### Timeouts
-
-Timeouts add a temporal limit to the execution of your code. If the IO doesn't respond in time, it will fail. Timeouts are high level concerns and you generally shouldn't use them except at the very highest level of your program.
-
-``` ruby
-message = task.with_timeout(5) do
-  begin
-    peer.read
-  rescue Async::TimeoutError
-    nil # The timeout was triggered.
-  end
-end
-```
-
-Any `yield` operation can cause a timeout to trigger. Non-`async` functions might not timeout because they are outside the scope of `async`.
-
-#### Wrapper Timeouts
-
-Asynchronous operations may block forever. You can assign a per-wrapper operation timeout duration. All asynchronous operations will be bounded by this timeout.
-
-``` ruby
-peer.timeout = 1
-peer.read # If this takes more than 1 second, Async::TimeoutError will be raised.
-```
-
-The benefit of this approach is that it applies to all operations. Typically, this would be configured by the user, and set to something pretty high, e.g. 120 seconds.
-
-### Reading Characters
-
-This example shows how to read one character at a time as the user presses it on the keyboard, and echos it back out as uppercase:
-
-``` ruby
-require 'async'
-require 'async/io/stream'
-require 'io/console'
-
-$stdin.raw!
-$stdin.echo = false
-
-Async do |task|
-  stdin = Async::IO::Stream.new(
-    Async::IO::Generic.new($stdin)
-  )
-
-  while character = stdin.read(1)
-    $stdout.write character.upcase
-  end
-end
-```
-
-### Deferred Buffering
-
-`Async::IO::Stream.new(..., deferred:true)` creates a deferred stream which increases latency slightly, but reduces the number of total packets sent. It does this by combining all calls `Stream#flush` within a single iteration of the reactor. This is typically more useful on the client side, but can also be useful on the server side when individual packets have high latency. It should be preferable to send one 100 byte packet than 10x 10 byte packets.
-
-Servers typically only deal with one request per iteartion of the reactor so it's less useful. Clients which make multiple requests can benefit significantly e.g. HTTP/2 clients can merge many requests into a single packet. Because HTTP/2 recommends disabling Nagle's algorithm, this is often beneficial.
-
-## Contributing
-
-1.  Fork it
-2.  Create your feature branch (`git checkout -b my-new-feature`)
-3.  Commit your changes (`git commit -am 'Add some feature'`)
-4.  Push to the branch (`git push origin my-new-feature`)
-5.  Create new Pull Request
-
-## See Also
-
-  - [async](https://github.com/socketry/async) — Asynchronous event-driven reactor.
-  - [async-process](https://github.com/socketry/async-process) — Asynchronous process spawning/waiting.
-  - [async-websocket](https://github.com/socketry/async-websocket) — Asynchronous client and server websockets.
-  - [async-dns](https://github.com/socketry/async-dns) — Asynchronous DNS resolver and server.
-  - [async-rspec](https://github.com/socketry/async-rspec) — Shared contexts for running async specs.
-  - [rubydns](https://github.com/ioquatix/rubydns) — A easy to use Ruby DNS server.
-
-## License
-
-Released under the MIT license.
-
-Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/async-io.gemspec b/async-io.gemspec
index d767c99..dd9c012 100644
--- a/async-io.gemspec
+++ b/async-io.gemspec
@@ -1,27 +1,43 @@
-# frozen_string_literal: true
+#########################################################
+# This file has been automatically generated by gem2tgz #
+#########################################################
+# -*- encoding: utf-8 -*-
+# stub: async-io 1.34.3 ruby lib
 
-require_relative "lib/async/io/version"
+Gem::Specification.new do |s|
+  s.name = "async-io".freeze
+  s.version = "1.34.3"
 
-Gem::Specification.new do |spec|
-	spec.name = "async-io"
-	spec.version = Async::IO::VERSION
-	
-	spec.summary = "Provides support for asynchonous TCP, UDP, UNIX and SSL sockets."
-	spec.authors = ["Samuel Williams", "Aurora", "Olle Jonsson", "Bruno Sutic", "Benoit Daloze", "Cyril Roelandt", "Thibaut Girka", "Jiang Jinyang", "Janko Marohnić"]
-	spec.license = "MIT"
-	
-	spec.homepage = "https://github.com/socketry/async-io"
-	
-	spec.files = Dir.glob('{lib}/**/*', File::FNM_DOTMATCH, base: __dir__)
-	
-	spec.required_ruby_version = ">= 2.5"
-	
-	spec.add_dependency "async"
-	
-	spec.add_development_dependency "async-container", "~> 0.15"
-	spec.add_development_dependency "async-rspec", "~> 1.10"
-	spec.add_development_dependency "bake"
-	spec.add_development_dependency "covered"
-	spec.add_development_dependency "rack-test"
-	spec.add_development_dependency "rspec", "~> 3.6"
+  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
+  s.require_paths = ["lib".freeze]
+  s.authors = ["Samuel Williams".freeze, "Aurora".freeze, "Olle Jonsson".freeze, "Bruno Sutic".freeze, "Benoit Daloze".freeze, "Cyril Roelandt".freeze, "Thibaut Girka".freeze, "Jiang Jinyang".freeze, "Janko Marohni\u0107".freeze]
+  s.date = "2023-01-30"
+  s.files = ["lib/async/io.rb".freeze, "lib/async/io/address.rb".freeze, "lib/async/io/address_endpoint.rb".freeze, "lib/async/io/binary_string.rb".freeze, "lib/async/io/buffer.rb".freeze, "lib/async/io/composite_endpoint.rb".freeze, "lib/async/io/endpoint.rb".freeze, "lib/async/io/endpoint/each.rb".freeze, "lib/async/io/generic.rb".freeze, "lib/async/io/host_endpoint.rb".freeze, "lib/async/io/notification.rb".freeze, "lib/async/io/peer.rb".freeze, "lib/async/io/protocol/generic.rb".freeze, "lib/async/io/protocol/line.rb".freeze, "lib/async/io/server.rb".freeze, "lib/async/io/shared_endpoint.rb".freeze, "lib/async/io/socket.rb".freeze, "lib/async/io/socket_endpoint.rb".freeze, "lib/async/io/ssl_endpoint.rb".freeze, "lib/async/io/ssl_socket.rb".freeze, "lib/async/io/standard.rb".freeze, "lib/async/io/stream.rb".freeze, "lib/async/io/tcp_socket.rb".freeze, "lib/async/io/threads.rb".freeze, "lib/async/io/trap.rb".freeze, "lib/async/io/udp_socket.rb".freeze, "lib/async/io/unix_endpoint.rb".freeze, "lib/async/io/unix_socket.rb".freeze, "lib/async/io/version.rb".freeze]
+  s.homepage = "https://github.com/socketry/async-io".freeze
+  s.licenses = ["MIT".freeze]
+  s.required_ruby_version = Gem::Requirement.new(">= 2.5".freeze)
+  s.rubygems_version = "3.2.5".freeze
+  s.summary = "Provides support for asynchonous TCP, UDP, UNIX and SSL sockets.".freeze
+
+  if s.respond_to? :specification_version then
+    s.specification_version = 4
+  end
+
+  if s.respond_to? :add_runtime_dependency then
+    s.add_runtime_dependency(%q<async>.freeze, [">= 0"])
+    s.add_development_dependency(%q<async-container>.freeze, ["~> 0.15"])
+    s.add_development_dependency(%q<async-rspec>.freeze, ["~> 1.10"])
+    s.add_development_dependency(%q<bake>.freeze, [">= 0"])
+    s.add_development_dependency(%q<covered>.freeze, [">= 0"])
+    s.add_development_dependency(%q<rack-test>.freeze, [">= 0"])
+    s.add_development_dependency(%q<rspec>.freeze, ["~> 3.6"])
+  else
+    s.add_dependency(%q<async>.freeze, [">= 0"])
+    s.add_dependency(%q<async-container>.freeze, ["~> 0.15"])
+    s.add_dependency(%q<async-rspec>.freeze, ["~> 1.10"])
+    s.add_dependency(%q<bake>.freeze, [">= 0"])
+    s.add_dependency(%q<covered>.freeze, [">= 0"])
+    s.add_dependency(%q<rack-test>.freeze, [">= 0"])
+    s.add_dependency(%q<rspec>.freeze, ["~> 3.6"])
+  end
 end
diff --git a/benchmark/pipe.rb b/benchmark/pipe.rb
deleted file mode 100755
index 0d000d8..0000000
--- a/benchmark/pipe.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'async'
-require 'async/io'
-
-require 'benchmark/ips'
-
-def measure(pipe, count)
-	i, o = pipe
-	
-	count.times do
-		o.write("Hello World")
-		i.read(11)
-	end
-end
-
-Benchmark.ips do |benchmark|
-	benchmark.time = 10
-	benchmark.warmup = 2
-	
-	benchmark.report("Async::IO.pipe") do |count|
-		Async do |task|
-			measure(::Async::IO.pipe, count)
-		end
-	end
-	
-	benchmark.report("IO.pipe") do |count|
-		Async do |task|
-			measure(::IO.pipe, count)
-		end
-	end
-	
-	benchmark.compare!
-end
diff --git a/debian/changelog b/debian/changelog
index dbf6cfd..e047f7a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-async-io (1.34.3-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 22 May 2023 16:41:57 -0000
+
 ruby-async-io (1.34.1-1) unstable; urgency=medium
 
   * New upstream release
diff --git a/examples/allocations/byteslice.rb b/examples/allocations/byteslice.rb
deleted file mode 100644
index 5bb95cf..0000000
--- a/examples/allocations/byteslice.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require_relative 'memory'
-
-string = nil
-
-measure_memory("Initial allocation") do
-	string = "a" * 5*1024*1024
-	string.freeze
-end # => 5.0 MB
-
-measure_memory("Byteslice from start to middle") do
-	# Why does this need to allocate memory? Surely it can share the original allocation?
-	x = string.byteslice(0, string.bytesize / 2)
-end # => 2.5 MB
-
-measure_memory("Byteslice from middle to end") do
-	string.byteslice(string.bytesize / 2, string.bytesize)
-end # => 0.0 MB
-
-measure_memory("Slice! from start to middle") do
-	string.dup.slice!(0, string.bytesize / 2)
-end # => 7.5 MB
-
-measure_memory("Byte slice into two halves") do
-	head = string.byteslice(0, string.bytesize / 2) # 2.5 MB
-	remainder = string.byteslice(string.bytesize / 2, string.bytesize) # Shared
-end # 2.5 MB
diff --git a/examples/allocations/memory.rb b/examples/allocations/memory.rb
deleted file mode 100644
index d0c3441..0000000
--- a/examples/allocations/memory.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-def measure_memory(annotation = "Memory allocated")
-	GC.disable
-	
-	start_memory = `ps -p #{Process::pid} -o rss`.split("\n")[1].chomp.to_i
-
-	yield
-	
-ensure
-	end_memory = `ps -p #{Process::pid} -o rss`.split("\n")[1].chomp.to_i
-	memory_usage = (end_memory - start_memory).to_f / 1024
-	
-	puts "#{memory_usage.round(1)} MB: #{annotation}"
-	GC.enable
-end
diff --git a/examples/allocations/read_chunks.rb b/examples/allocations/read_chunks.rb
deleted file mode 100755
index da2fd6f..0000000
--- a/examples/allocations/read_chunks.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require_relative 'memory'
-
-require_relative "../../lib/async/io/stream"
-require "stringio"
-
-measure_memory("Stream setup") do
-	@io = StringIO.new("a" * (50*1024*1024))
-	@stream = Async::IO::Stream.new(@io)
-end # 50.0 MB
-
-measure_memory("Read all chunks") do
-	while chunk = @stream.read_partial
-		chunk.clear
-	end
-end # 0.5 MB
diff --git a/examples/chat/client.rb b/examples/chat/client.rb
deleted file mode 100755
index 9277067..0000000
--- a/examples/chat/client.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH << File.expand_path("../../lib", __dir__)
-
-require 'async'
-require 'async/notification'
-require 'async/io/stream'
-require 'async/io/host_endpoint'
-require 'async/io/protocol/line'
-
-class User < Async::IO::Protocol::Line
-end
-
-endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7138")
-
-input = Async::IO::Protocol::Line.new(
-	Async::IO::Stream.new(
-		Async::IO::Generic.new($stdin)
-	)
-)
-
-Async do |task|
-	socket = endpoint.connect
-	stream = Async::IO::Stream.new(socket)
-	user = User.new(stream)
-	
-	# This is used to track whether either reading from stdin failed or reading from network failed.
-	finished = Async::Notification.new
-	
-	# Read lines from stdin and write to network.
-	terminal = task.async do
-		while line = input.read_line
-			user.write_lines line
-		end
-	rescue EOFError
-		# It's okay, we are disconnecting, because stdin has closed.
-	ensure
-		finished.signal
-	end
-	
-	# Read lines from network and write to stdout.
-	network = task.async do
-		while line = user.read_line
-			puts line
-		end
-	ensure
-		finished.signal
-	end
-	
-	# Wait for any of the above processes to finish:
-	finished.wait
-ensure
-	# Stop all the nested tasks if we are exiting:
-	network.stop if network
-	terminal.stop if terminal
-	user.close if user
-end
diff --git a/examples/chat/server.rb b/examples/chat/server.rb
deleted file mode 100755
index 6c03514..0000000
--- a/examples/chat/server.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH << File.expand_path("../../lib", __dir__)
-
-require 'set'
-require 'logger'
-
-require 'async'
-require 'async/io/host_endpoint'
-require 'async/io/protocol/line'
-
-class User < Async::IO::Protocol::Line
-	attr_accessor :name
-	
-	def login!
-		self.write_lines "Tell me your name, traveller:"
-		self.name = self.read_line
-	end
-	
-	def to_s
-		@name || "unknown"
-	end
-end
-
-class Server
-	def initialize
-		@users = Set.new
-	end
-	
-	def broadcast(*message)
-		puts *message
-		
-		@users.each do |user|
-			begin
-				user.write_lines(*message)
-			rescue EOFError
-				# In theory, it's possible this will fail if the remote end has disconnected. Each user has it's own task running `#connected`, and eventually `user.read_line` will fail. When it does, the disconnection logic will be invoked. A better way to do this would be to have a message queue, but for the sake of keeping this example simple, this is by far the better option.
-			end
-		end
-	end
-	
-	def connected(user)
-		user.login!
-		
-		broadcast("#{user} has joined")
-		
-		user.write_lines("currently connected: #{@users.map(&:to_s).join(', ')}")
-		
-		while message = user.read_line
-			broadcast("#{user.name}: #{message}")
-		end
-	rescue EOFError
-		# It's okay, client has disconnected.
-	ensure
-		disconnected(user)
-	end
-	
-	def disconnected(user, reason = "quit")
-		@users.delete(user)
-		
-		broadcast("#{user} has disconnected: #{reason}")
-	end
-	
-	def run(endpoint)
-		Async do |task|
-			endpoint.accept do |peer|
-				stream = Async::IO::Stream.new(peer)
-				user = User.new(stream)
-				
-				@users << user
-				
-				connected(user)
-			end
-		end
-	end
-end
-
-Console.logger.level = Logger::INFO
-Console.logger.info("Starting server...")
-server = Server.new
-
-endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7138")
-server.run(endpoint)
diff --git a/examples/defer/worker.rb b/examples/defer/worker.rb
deleted file mode 100644
index 79b1673..0000000
--- a/examples/defer/worker.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'async'
-require 'async/io/notification'
-
-def defer(*args, &block)
-	Async do
-		notification = Async::IO::Notification.new
-		
-		thread = Thread.new(*args) do
-			yield
-		ensure
-			notification.signal
-		end
-		
-		notification.wait
-		thread.join
-	end
-end
-
-Async do
-	10.times do
-		defer do
-			puts "I'm going to sleep"
-			sleep 1
-			puts "I'm going to wake up"
-		end
-	end
-end
diff --git a/examples/echo/client.rb b/examples/echo/client.rb
deleted file mode 100755
index 0306baf..0000000
--- a/examples/echo/client.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
-
-require 'async'
-require 'async/io/trap'
-require 'async/io/host_endpoint'
-require 'async/io/stream'
-
-endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
-
-Async do |task|
-	endpoint.connect do |peer|
-		stream = Async::IO::Stream.new(peer)
-		
-		while true
-			task.sleep 1
-			stream.puts "Hello World!"
-			puts stream.gets.inspect
-		end
-	end
-end
diff --git a/examples/echo/server.rb b/examples/echo/server.rb
deleted file mode 100755
index 45d7190..0000000
--- a/examples/echo/server.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
-
-require 'async'
-require 'async/io/trap'
-require 'async/io/host_endpoint'
-require 'async/io/stream'
-
-endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
-
-interrupt = Async::IO::Trap.new(:INT)
-
-Async do |top|
-	interrupt.install!
-	
-	endpoint.bind do |server, task|
-		Console.logger.info(server) {"Accepting connections on #{server.local_address.inspect}"}
-		
-		task.async do |subtask|
-			interrupt.wait
-			
-			Console.logger.info(server) {"Closing server socket..."}
-			server.close
-			
-			interrupt.default!
-			
-			Console.logger.info(server) {"Waiting for connections to close..."}
-			subtask.sleep(4)
-			
-			Console.logger.info(server) do |buffer|
-				buffer.puts "Stopping all tasks..."
-				task.print_hierarchy(buffer)
-				buffer.puts "", "Reactor Hierarchy"
-				task.reactor.print_hierarchy(buffer)
-			end
-			
-			task.stop
-		end
-		
-		server.listen(128)
-		
-		server.accept_each do |peer|
-			stream = Async::IO::Stream.new(peer)
-			
-			while chunk = stream.read_partial
-				Console.logger.debug(self) {chunk.inspect}
-				stream.write(chunk)
-				stream.flush
-				
-				Console.logger.info(server) do |buffer|
-					task.reactor.print_hierarchy(buffer)
-				end
-			end
-		end
-	end
-end
diff --git a/examples/issues/broken_ssl.rb b/examples/issues/broken_ssl.rb
deleted file mode 100644
index 5971dea..0000000
--- a/examples/issues/broken_ssl.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'socket'
-require 'openssl'
-
-server = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
-server.bind(Addrinfo.tcp('127.0.0.1', 4433))
-server.listen(128)
-
-ssl_server = OpenSSL::SSL::SSLServer.new(server, OpenSSL::SSL::SSLContext.new)
-
-puts ssl_server.addr
-
-# openssl/ssl.rb:234:in `addr': undefined method `addr' for #<Socket:fd 8> (NoMethodError)
diff --git a/examples/issues/pipes.rb b/examples/issues/pipes.rb
deleted file mode 100644
index ff6e504..0000000
--- a/examples/issues/pipes.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-# wat.rb
-require 'async'
-require_relative '../../lib/async/io'
-require 'digest/sha1'
-require 'securerandom'
-
-Async.run do |task|
-	r, w = IO.pipe.map { |io| Async::IO.try_convert(io) }
-
-	task.async do |subtask|
-		s = Digest::SHA1.new
-		l = 0
-		100.times do
-			bytes = SecureRandom.bytes(4000)
-			s << bytes
-			w << bytes
-			l += bytes.bytesize
-		end
-		w.close
-		p [:write, l, s.hexdigest]
-	end
-	
-	task.async do |subtask|
-		s = Digest::SHA1.new
-		l = 0
-		while b = r.read(4096)
-			s << b
-			l += b.bytesize
-		end
-		p [:read, l, s.hexdigest]
-	end
-end
diff --git a/examples/millions/client.rb b/examples/millions/client.rb
deleted file mode 100755
index c253a08..0000000
--- a/examples/millions/client.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH << File.expand_path("../../lib", __dir__)
-
-require 'async/reactor'
-require 'async/io/host_endpoint'
-
-require 'async/container'
-require 'async/container/forked'
-
-endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7234")
-
-CONNECTIONS = 1_000_000
-
-CONCURRENCY = Async::Container.processor_count
-TASKS = 16
-REPEATS = (CONNECTIONS.to_f / (TASKS * CONCURRENCY)).ceil
-
-puts "Starting #{CONCURRENCY} processes, running #{TASKS} tasks, making #{REPEATS} connections."
-puts "Total number of connections: #{CONCURRENCY * TASKS * REPEATS}!"
-
-begin
-	container = Async::Container::Forked.new
-	
-	container.run(count: CONCURRENCY) do
-		Async do |task|
-			connections = []
-			
-			TASKS.times do
-				task.async do
-					REPEATS.times do
-						$stdout.write "."
-						connections << endpoint.connect
-					end
-				end
-			end
-		end
-	end
-	
-	container.wait
-ensure
-	container.stop if container
-end
diff --git a/examples/millions/server.rb b/examples/millions/server.rb
deleted file mode 100755
index ae4623a..0000000
--- a/examples/millions/server.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-$LOAD_PATH << File.expand_path("../../lib", __dir__)
-
-require 'set'
-require 'logger'
-
-require 'async'
-require 'async/reactor'
-require 'async/io/host_endpoint'
-require 'async/io/protocol/line'
-
-class Server
-	def initialize
-		@connections = []
-	end
-	
-	def run(endpoint)
-		Async do |task|
-			task.async do |subtask|
-				while true
-					subtask.sleep 10
-					puts "Connection count: #{@connections.size}"
-				end
-			end
-				
-			
-			endpoint.accept do |peer|
-				stream = Async::IO::Stream.new(peer)
-				
-				@connections << stream
-			end
-		end
-	end
-end
-
-Console.logger.level = Logger::INFO
-Console.logger.info("Starting server...")
-server = Server.new
-
-endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7234")
-server.run(endpoint)
diff --git a/examples/udp.rb b/examples/udp.rb
deleted file mode 100644
index 5968740..0000000
--- a/examples/udp.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'async'
-require_relative '../lib/async/io'
-
-endpoint = Async::IO::Endpoint.udp("localhost", 5300)
-
-Async do |task|
-	endpoint.bind do |socket|
-		# This block executes for both IPv4 and IPv6 UDP sockets:
-		loop do
-			data, address = socket.recvfrom(1024)
-			pp data
-			pp address
-		end
-	end
-	
-	# This will try connecting to all addresses and yield for the first one that successfully connects:
-	endpoint.connect do |socket|
-		loop do
-			task.sleep rand(1..10)
-			socket.send "Hello World!", 0
-		end
-	end
-end
-
diff --git a/examples/udp/client.rb b/examples/udp/client.rb
deleted file mode 100755
index 9376dae..0000000
--- a/examples/udp/client.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'async'
-require 'async/io'
-
-endpoint = Async::IO::Endpoint.udp("localhost", 5678)
-
-Async do |task|
-	endpoint.connect do |socket|
-		socket.send("Hello World")
-		pp socket.recv(1024)
-	end
-end
diff --git a/examples/udp/server.rb b/examples/udp/server.rb
deleted file mode 100755
index 441a3f2..0000000
--- a/examples/udp/server.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'async'
-require 'async/io'
-
-endpoint = Async::IO::Endpoint.udp("localhost", 5678)
-
-Async do |task|
-	endpoint.bind do |socket|
-		while true
-			data, address = socket.recvfrom(1024)
-			socket.send(data.reverse, 0, address)
-		end
-	end
-end
diff --git a/gems.rb b/gems.rb
deleted file mode 100644
index 0ee744c..0000000
--- a/gems.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gemspec
-
-group :maintenance, optional: true do
-	gem "bake-modernize"
-	gem "bake-gem"
-	
-	gem "utopia-project"
-end
-
-group :test do
-	gem 'benchmark-ips'
-	gem 'ruby-prof', platforms: :mri
-	
-	gem 'http'
-end
diff --git a/gems/async-head.rb b/gems/async-head.rb
deleted file mode 100644
index 50345f7..0000000
--- a/gems/async-head.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gemspec path: "../"
-
-gem 'async', git: "https://github.com/socketry/async"
diff --git a/gems/async-v1.rb b/gems/async-v1.rb
deleted file mode 100644
index cc6730c..0000000
--- a/gems/async-v1.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gemspec path: "../"
-
-gem 'async', '~> 1.0'
diff --git a/lib/async/io/stream.rb b/lib/async/io/stream.rb
index 24f121b..7c954ca 100644
--- a/lib/async/io/stream.rb
+++ b/lib/async/io/stream.rb
@@ -114,7 +114,9 @@ module Async
 				raise exception, "encountered eof while reading data"
 			end
 			
-			alias readpartial read_partial
+			def readpartial(size = nil)
+				read_partial(size) or raise EOFError, "Encountered eof while reading data!"
+			end
 			
 			# Efficiently read data from the stream until encountering pattern.
 			# @param pattern [String] The pattern to match.
diff --git a/lib/async/io/version.rb b/lib/async/io/version.rb
index 150f026..94b26a8 100644
--- a/lib/async/io/version.rb
+++ b/lib/async/io/version.rb
@@ -22,6 +22,6 @@
 
 module Async
 	module IO
-		VERSION = "1.34.1"
+		VERSION = "1.34.3"
 	end
 end
diff --git a/spec/addrinfo.rb b/spec/addrinfo.rb
deleted file mode 100644
index c64ee02..0000000
--- a/spec/addrinfo.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-# This is useful for specs, but I hesitate to monkey patch a core class in the library itself.
-class Addrinfo
-	def == other
-		self.to_s == other.to_s
-	end
-	
-	def != other
-		self.to_s != other.to_s
-	end
-	
-	def <=> other
-		self.to_s <=> other.to_s
-	end
-end
diff --git a/spec/async/io/buffer_spec.rb b/spec/async/io/buffer_spec.rb
deleted file mode 100644
index 6d21187..0000000
--- a/spec/async/io/buffer_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/buffer'
-
-RSpec.describe Async::IO::Buffer do
-	include_context Async::RSpec::Memory
-	
-	let!(:string) {"Hello World!".b}
-	subject! {described_class.new}
-	
-	it "should be binary encoding" do
-		expect(subject.encoding).to be Encoding::BINARY
-	end
-	
-	it "should not allocate strings when concatenating" do
-		expect do
-			subject << string
-		end.to limit_allocations.of(String, size: 0, count: 0)
-	end
-	
-	it "can append unicode strings to binary buffer" do
-		2.times do
-			subject << "Føøbar"
-		end
-		
-		expect(subject).to eq "FøøbarFøøbar".b
-	end
-end
diff --git a/spec/async/io/c10k_spec.rb b/spec/async/io/c10k_spec.rb
deleted file mode 100644
index f187e5f..0000000
--- a/spec/async/io/c10k_spec.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io'
-require 'benchmark'
-require 'open3'
-
-# require 'ruby-prof'
-
-RSpec.describe "c10k echo client/server", if: Process.respond_to?(:fork) do
-	# macOS has a rediculously hard time to do this.
-	# sudo sysctl -w net.inet.ip.portrange.first=10000
-	# sudo sysctl -w net.inet.ip.portrange.hifirst=10000
-	# Probably due to the use of select.
-	
-	let(:repeats) do
-		if limit = Async::IO.file_descriptor_limit
-			if limit > 1024*10
-				10_000
-			else
-				[1, limit - 100].max
-			end
-		else
-			10_000
-		end
-	end
-	
-	let(:server_address) {Async::IO::Address.tcp('0.0.0.0', 10101)}
-	
-	def echo_server(server_address)
-		Async do |task|
-			connections = []
-			
-			Async::IO::Socket.bind(server_address) do |server|
-				server.listen(Socket::SOMAXCONN)
-				
-				while connections.size < repeats
-					peer, address = server.accept
-					connections << peer
-				end
-			end.wait
-			
-			Console.logger.info("Releasing #{connections.size} connections...")
-			
-			while connection = connections.pop
-				connection.write(".")
-				connection.close
-			end
-		end
-	end
-	
-	def echo_client(server_address, data, responses)
-		Async do |task|
-			begin
-				Async::IO::Socket.connect(server_address) do |peer|
-					responses << peer.read(1)
-				end
-			rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EADDRINUSE
-				Console.logger.warn(data, $!)
-				# If the connection was refused, it means the server probably can't accept connections any faster than it currently is, so we simply retry.
-				retry
-			end
-		end
-	end
-	
-	def fork_server
-		pid = fork do
-			# profile = RubyProf::Profile.new(merge_fibers: true)
-			# profile.start
-			
-			echo_server(server_address)
-		# ensure
-		# 	result = profile.stop
-		# 	printer = RubyProf::FlatPrinter.new(result)
-		# 	printer.print(STDOUT)
-		end
-
-		yield
-	ensure
-		Process.kill(:KILL, pid)
-		Process.wait(pid)
-	end
-	
-	around(:each) do |example|
-		duration = Benchmark.realtime do
-			example.run
-		end
-		
-		example.reporter.message "Handled #{repeats} connections in #{duration.round(2)}s: #{(repeats/duration).round(2)}req/s"
-	end
-	
-	it "should wait until all clients are connected" do
-		fork_server do
-			# profile = RubyProf::Profile.new(merge_fibers: true)
-			# profile.start
-			
-			Async do |task|
-				responses = []
-				
-				tasks = repeats.times.map do |i|
-					# puts "Starting client #{i} on #{task}..." if (i % 1000) == 0
-					
-					echo_client(server_address, "Hello World #{i}", responses)
-				end
-				
-				# task.reactor.print_hierarchy
-				
-				tasks.each(&:wait)
-				
-				expect(responses.size).to be repeats
-			end
-			
-		# ensure
-		# 	result = profile.stop
-		# 	printer = RubyProf::FlatPrinter.new(result)
-		# 	printer.print(STDOUT)
-		end
-	end
-end
diff --git a/spec/async/io/echo_spec.rb b/spec/async/io/echo_spec.rb
deleted file mode 100644
index 6bc8ef1..0000000
--- a/spec/async/io/echo_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io'
-
-RSpec.describe "echo client/server" do
-	include_context Async::RSpec::Reactor
-	
-	let(:server_address) {Async::IO::Address.tcp('0.0.0.0', 9002)}
-	
-	def echo_server(server_address)
-		Async do |task|
-			# This is a synchronous block within the current task:
-			Async::IO::Socket.accept(server_address) do |client|
-				# This is an asynchronous block within the current reactor:
-				data = client.read(512)
-				
-				# This produces out-of-order responses.
-				task.sleep(rand * 0.01)
-				
-				client.write(data)
-			end
-		end
-	end
-	
-	def echo_client(server_address, data, responses)
-		Async do |task|
-			Async::IO::Socket.connect(server_address) do |peer|
-				result = peer.write(data)
-				peer.close_write
-				
-				message = peer.read(data.bytesize)
-				
-				responses << message
-			end
-		end
-	end
-	
-	let(:repeats) {10}
-
-	it "should echo several messages" do
-		server = echo_server(server_address)
-		responses = []
-		
-		tasks = repeats.times.map do |i|
-			echo_client(server_address, "Hello World #{i}", responses)
-		end
-		
-		# task.reactor.print_hierarchy
-		
-		tasks.each(&:wait)
-		server.stop
-		
-		expect(responses.size).to be repeats
-	end
-end
diff --git a/spec/async/io/endpoint_spec.rb b/spec/async/io/endpoint_spec.rb
deleted file mode 100644
index c9386be..0000000
--- a/spec/async/io/endpoint_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/endpoint'
-
-require 'async/io/tcp_socket'
-require 'async/io/socket_endpoint'
-require 'async/io/ssl_endpoint'
-
-RSpec.describe Async::IO::Endpoint do
-	include_context Async::RSpec::Reactor
-	
-	describe Async::IO::Endpoint.ssl('0.0.0.0', 5234, hostname: "lolcathost") do
-		it "should have hostname" do
-			expect(subject.hostname).to be == "lolcathost"
-		end
-		
-		it "shouldn't have a timeout duration" do
-			expect(subject.timeout).to be_nil
-		end
-	end
-	
-	describe Async::IO::Endpoint.tcp('0.0.0.0', 5234, reuse_port: true, timeout: 10) do
-		it "should be a tcp binding" do
-			subject.bind do |server|
-				expect(server.local_address.socktype).to be == ::Socket::SOCK_STREAM
-			end
-		end
-		
-		it "should have a timeout duration" do
-			expect(subject.timeout).to be 10
-		end
-		
-		it "should print nicely" do
-			expect(subject.to_s).to include('0.0.0.0', '5234')
-		end
-		
-		it "has options" do
-			expect(subject.options[:reuse_port]).to be true
-		end
-		
-		it "has hostname" do
-			expect(subject.hostname).to be == '0.0.0.0'
-		end
-		
-		it "has local address" do
-			address = Async::IO::Address.tcp('127.0.0.1', 8080)
-			expect(subject.with(local_address: address).local_address).to be == address
-		end
-		
-		let(:message) {"Hello World!"}
-		
-		it "can connect to bound server" do
-			server_task = reactor.async do
-				subject.accept do |io|
-					expect(io.timeout).to be == 10
-					io.write message
-					io.close
-				end
-			end
-			
-			io = subject.connect
-			expect(io.timeout).to be == 10
-			expect(io.read(message.bytesize)).to be == message
-			io.close
-			
-			server_task.stop
-		end
-	end
-	
-	describe Async::IO::Endpoint.tcp('0.0.0.0', 0) do
-		it "should be a tcp binding" do
-			subject.bind do |server|
-				expect(server.local_address.ip_port).to be > 10000
-			end
-		end
-	end
-	
-	describe Async::IO::SocketEndpoint.new(TCPServer.new('0.0.0.0', 1234)) do
-		it "should bind to given socket" do
-			subject.bind do |server|
-				expect(server).to be == subject.socket
-			end
-		end
-	end
-end
diff --git a/spec/async/io/generic_examples.rb b/spec/async/io/generic_examples.rb
deleted file mode 100644
index 542307c..0000000
--- a/spec/async/io/generic_examples.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-RSpec.shared_examples Async::IO::Generic do |ignore_methods|
-	let(:instance_methods) {described_class.wrapped_klass.public_instance_methods(false) - (ignore_methods || [])}
-	let(:wrapped_instance_methods) {described_class.public_instance_methods}
-	
-	it "should wrap a class" do
-		expect(described_class.wrapped_klass).to_not be_nil
-	end
-	
-	it "should wrap underlying instance methods" do
-		expect(wrapped_instance_methods.sort).to include(*instance_methods.sort)
-	end
-	
-	# This needs to be reviewed in more detail.
-	#
-	# let(:singleton_methods) {described_class.wrapped_klass.singleton_methods(false)}
-	# let(:wrapped_singleton_methods) {described_class.singleton_methods(false)}
-	# 
-	# it "should wrap underlying class methods" do
-	# 	singleton_methods.each do |method|
-	# 		expect(wrapped_singleton_methods).to include(method)
-	# 	end
-	# end
-end
-
-RSpec.shared_examples Async::IO do
-	let(:data) {"Hello World!"}
-	
-	it "should read data" do
-		io.write(data)
-		expect(subject.read(data.bytesize)).to be == data
-	end
-	
-	it "should read less than available data" do
-		io.write(data)
-		expect(subject.read(1)).to be == data[0]
-	end
-	
-	it "should read all available data" do
-		io.write(data)
-		io.close_write
-		
-		expect(subject.read(data.bytesize * 2)).to be == data
-	end
-	
-	it "should read all available data" do
-		io.write(data)
-		io.close_write
-		
-		expect(subject.read).to be == data
-	end
-	
-	context "has the right encoding" do
-		it "with a normal read" do
-			io.write(data)
-			expect(subject.read(1).encoding).to be == Encoding::BINARY
-		end
-		
-		it "with a zero-length read" do
-			expect(subject.read(0).encoding).to be == Encoding::BINARY
-		end
-	end
-
-	context "are not frozen" do
-		it "with a normal read" do
-			io.write(data)
-			expect(subject.read(1).frozen?).to be == false
-		end
-		
-		it "with a zero-length read" do
-			expect(subject.read(0).frozen?).to be == false
-		end
-	end
-end
diff --git a/spec/async/io/generic_spec.rb b/spec/async/io/generic_spec.rb
deleted file mode 100644
index 3ccbd16..0000000
--- a/spec/async/io/generic_spec.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io'
-require 'async/clock'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::Generic do
-	include_context Async::RSpec::Reactor
-	
-	CONSOLE_METHODS = [:beep, :cooked, :cooked!, :cursor, :cursor=, :echo=, :echo?,:getch, :getpass, :goto, :iflush, :ioflush, :noecho, :oflush,:pressed?, :raw, :raw!, :winsize, :winsize=]
-	# On TruffleRuby, IO#encode_with needs to be defined for YAML.dump as a public method, allow it
-	ignore = [:encode_with, :check_winsize_changed, :clear_screen, :console_mode, :console_mode=, :cursor_down, :cursor_left, :cursor_right, :cursor_up, :erase_line, :erase_screen, :goto_column, :scroll_backward, :scroll_forward, :wait_priority]
-	
-	it_should_behave_like Async::IO::Generic, [
-		:bytes, :chars, :codepoints, :each, :each_byte, :each_char, :each_codepoint, :each_line, :getbyte, :getc, :gets, :lineno, :lineno=, :lines, :print, :printf, :putc, :puts, :readbyte, :readchar, :readline, :readlines, :ungetbyte, :ungetc
-	] + CONSOLE_METHODS + ignore
-	
-	let(:message) {"Hello World!"}
-	
-	let(:pipe) {IO.pipe}
-	let(:input) {Async::IO::Generic.new(pipe.first)}
-	let(:output) {Async::IO::Generic.new(pipe.last)}
-	
-	it "should send and receive data within the same reactor" do
-		received = nil
-		
-		output_task = reactor.async do
-			received = input.read(1024)
-			input.close
-		end
-		
-		reactor.async do
-			output.write(message)
-			output.close
-		end
-		
-		output_task.wait
-		expect(received).to be == message
-	end
-	
-	describe '#wait' do
-		let(:wait_duration) {0.1}
-		
-		it "can wait for :read and :write" do
-			reader = reactor.async do |task|
-				duration = Async::Clock.measure do
-					input.wait(1, :read)
-				end
-				
-				expect(duration).to be >= wait_duration
-				expect(input.read(1024)).to be == message
-				
-				input.close
-			end
-			
-			writer = reactor.async do |task|
-				duration = Async::Clock.measure do
-					output.wait(1, :write)
-				end
-				
-				task.sleep(wait_duration)
-				
-				output.write(message)
-				output.close
-			end
-			
-			[reader, writer].each(&:wait)
-		end
-		
-		it "can return nil when timeout is exceeded" do
-			reader = reactor.async do |task|
-				duration = Async::Clock.measure do
-					expect(input.wait(wait_duration, :read)).to be_nil
-				end
-				
-				expect(duration).to be >= wait_duration
-				
-				input.close
-			end
-			
-			[reader].each(&:wait)
-			
-			output.close
-		end
-	end
-end
diff --git a/spec/async/io/notification_spec.rb b/spec/async/io/notification_spec.rb
deleted file mode 100644
index 2c36c7c..0000000
--- a/spec/async/io/notification_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/notification'
-
-RSpec.describe Async::IO::Notification do
-	include_context Async::RSpec::Reactor
-	
-	it "should wait for notification" do
-		waiting_task = reactor.async do
-			subject.wait
-		end
-		
-		expect(waiting_task.status).to be :running
-		
-		signalling_task = reactor.async do
-			subject.signal
-		end
-		
-		signalling_task.wait
-		waiting_task.wait
-		
-		expect(waiting_task.status).to be :complete
-		
-		subject.close
-	end
-end
diff --git a/spec/async/io/protocol/line_spec.rb b/spec/async/io/protocol/line_spec.rb
deleted file mode 100755
index 8b3bd89..0000000
--- a/spec/async/io/protocol/line_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/protocol/line'
-require 'async/io/socket'
-
-RSpec.describe Async::IO::Protocol::Line do
-	include_context Async::RSpec::Reactor
-	
-	let(:pipe) {@pipe = Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)}
-	let(:remote) {pipe.first}
-	subject {described_class.new(Async::IO::Stream.new(pipe.last, deferred: true), "\n")}
-	
-	after(:each) {defined?(@pipe) && @pipe&.each(&:close)}
-	
-	context "default line ending" do
-		subject {described_class.new(nil)}
-		
-		it "should have default eol terminator" do
-			expect(subject.eol).to_not be_nil
-		end
-	end
-	
-	describe '#write_lines' do
-		it "should write line" do
-			subject.write_lines "Hello World"
-			subject.close
-			
-			expect(remote.read).to be == "Hello World\n"
-		end
-	end
-	
-	describe '#read_line' do
-		before(:each) do
-			remote.write "Hello World\n"
-			remote.close
-		end
-		
-		it "should read one line" do
-			expect(subject.read_line).to be == "Hello World"
-		end
-		
-		it "should be binary encoding" do
-			expect(subject.read_line.encoding).to be == Encoding::BINARY
-		end
-	end
-	
-	describe '#read_lines' do
-		before(:each) do
-			remote.write "Hello\nWorld\n"
-			remote.close
-		end
-		
-		it "should read multiple lines" do
-			expect(subject.read_lines).to be == ["Hello", "World"]
-		end
-		
-		it "should be binary encoding" do
-			expect(subject.read_lines.first.encoding).to be == Encoding::BINARY
-		end
-	end
-end
diff --git a/spec/async/io/shared_endpoint/server_spec.rb b/spec/async/io/shared_endpoint/server_spec.rb
deleted file mode 100644
index d971112..0000000
--- a/spec/async/io/shared_endpoint/server_spec.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/ssl_socket'
-require 'async/rspec/ssl'
-
-require 'async/io/host_endpoint'
-require 'async/io/shared_endpoint'
-
-require 'async/container'
-
-RSpec.shared_examples_for Async::IO::SharedEndpoint do |container_class|
-	include_context Async::RSpec::SSL::VerifiedContexts
-	include_context Async::RSpec::SSL::ValidCertificate
-	
-	let!(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6781, reuse_port: true)}
-	let!(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context)}
-	let!(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: client_context)}
-	
-	let!(:bound_endpoint) do
-		Async do
-			Async::IO::SharedEndpoint.bound(server_endpoint)
-		end.wait
-	end
-	
-	let(:container) {container_class.new}
-	
-	it "can use bound endpoint in container" do
-		container.async do
-			bound_endpoint.accept do |peer|
-				peer.write "Hello World"
-				peer.close
-			end
-		end
-		
-		Async do
-			client_endpoint.connect do |peer|
-				expect(peer.read(11)).to eq "Hello World"
-			end
-		end
-		
-		container.stop
-		bound_endpoint.close
-	end
-end
-
-RSpec.describe Async::Container::Forked, if: Process.respond_to?(:fork) do
-	it_behaves_like Async::IO::SharedEndpoint, described_class
-end
-
-RSpec.describe Async::Container::Threaded, if: (RUBY_PLATFORM !~ /darwin/ && RUBY_ENGINE != "jruby") do
-	it_behaves_like Async::IO::SharedEndpoint, described_class
-end
diff --git a/spec/async/io/shared_endpoint_spec.rb b/spec/async/io/shared_endpoint_spec.rb
deleted file mode 100644
index 0bb2fbd..0000000
--- a/spec/async/io/shared_endpoint_spec.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/host_endpoint'
-require 'async/io/shared_endpoint'
-
-RSpec.describe Async::IO::SharedEndpoint do
-	include_context Async::RSpec::Reactor
-	
-	describe '#bound' do
-		let(:endpoint) {Async::IO::Endpoint.udp("localhost", 5123, timeout: 10)}
-		
-		it "can bind to shared endpoint" do
-			bound_endpoint = described_class.bound(endpoint)
-			expect(bound_endpoint.wrappers).to_not be_empty
-			
-			wrapper = bound_endpoint.wrappers.first
-			expect(wrapper).to be_a Async::IO::Socket
-			expect(wrapper.timeout).to be == endpoint.timeout
-			expect(wrapper).to_not be_close_on_exec
-			
-			bound_endpoint.close
-		end
-		
-		it "can specify close_on_exec" do
-			bound_endpoint = described_class.bound(endpoint, close_on_exec: true)
-			expect(bound_endpoint.wrappers).to_not be_empty
-			
-			wrapper = bound_endpoint.wrappers.first
-			expect(wrapper).to be_close_on_exec
-			
-			bound_endpoint.close
-		end
-	end
-	
-	describe '#connected' do
-		let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 5124, timeout: 10)}
-		
-		it "can connect to shared endpoint" do
-			server_task = reactor.async do
-				endpoint.accept do |io|
-					io.close
-				end
-			end
-			
-			connected_endpoint = described_class.connected(endpoint)
-			expect(connected_endpoint.wrappers).to_not be_empty
-			
-			wrapper = connected_endpoint.wrappers.first
-			expect(wrapper).to be_a Async::IO::Socket
-			expect(wrapper.timeout).to be == endpoint.timeout
-			expect(wrapper).to_not be_close_on_exec
-			
-			connected_endpoint.close
-			server_task.stop
-		end
-	end
-end
diff --git a/spec/async/io/socket/tcp_spec.rb b/spec/async/io/socket/tcp_spec.rb
deleted file mode 100644
index ea5b2c7..0000000
--- a/spec/async/io/socket/tcp_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/tcp_socket'
-require 'async/io/address'
-
-RSpec.describe Async::IO::Socket do
-	include_context Async::RSpec::Reactor
-	
-	# Shared port for localhost network tests.
-	let(:server_address) {Async::IO::Address.tcp("127.0.0.1", 6788)}
-	let(:local_address) {Async::IO::Address.tcp("127.0.0.1", 0)}
-	let(:data) {"The quick brown fox jumped over the lazy dog."}
-	
-	let!(:server_task) do
-		# Accept a single incoming connection and then finish.
-		Async::IO::Socket.bind(server_address) do |server|
-			server.listen(10)
-			
-			server.accept do |peer, address|
-				data = peer.read(512)
-				peer.write(data)
-			end
-		end
-	end
-	
-	describe 'basic tcp server' do
-		it "should start server and send data" do
-			Async::IO::Socket.connect(server_address) do |client|
-				client.write(data)
-				client.close_write
-				
-				expect(client.read(512)).to be == data
-			end
-		end
-	end
-	
-	describe 'non-blocking tcp connect' do
-		it "can specify local address" do
-			Async::IO::Socket.connect(server_address, local_address: local_address) do |client|
-				client.write(data)
-				client.close_write
-				
-				expect(client.read(512)).to be == data
-			end
-		end
-		
-		it "should start server and send data" do
-			Async::IO::Socket.connect(server_address) do |client|
-				client.write(data)
-				client.close_write
-				
-				expect(client.read(512)).to be == data
-			end
-		end
-		
-		it "can connect socket and read/write in a different task" do
-			socket = Async::IO::Socket.connect(server_address)
-			
-			expect(socket).to_not be_nil
-			expect(socket).to be_kind_of Async::Wrapper
-			
-			reactor.async do
-				socket.write(data)
-				socket.close_write
-				
-				expect(socket.read(512)).to be == data
-			end.wait
-			
-			socket.close
-		end
-	end
-end
diff --git a/spec/async/io/socket/udp_spec.rb b/spec/async/io/socket/udp_spec.rb
deleted file mode 100644
index 0b3b69e..0000000
--- a/spec/async/io/socket/udp_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/udp_socket'
-
-RSpec.describe Async::IO::Socket do
-	include_context Async::RSpec::Reactor
-	
-	# Shared port for localhost network tests.
-	let!(:server_address) {Async::IO::Address.udp("127.0.0.1", 6778)}
-	let(:data) {"The quick brown fox jumped over the lazy dog."}
-	
-	let!(:server_task) do
-		reactor.async do
-			Async::IO::Socket.bind(server_address) do |server|
-				packet, address = server.recvfrom(512)
-				
-				server.send(packet, 0, address)
-			end
-		end
-	end
-	
-	describe 'basic udp server' do
-		it "should echo data back to peer" do
-			Async::IO::Socket.connect(server_address) do |client|
-				client.send(data)
-				response = client.recv(512)
-				
-				expect(response).to be == data
-			end
-		end
-		
-		it "should use unconnected socket" do
-			Async::IO::UDPSocket.wrap(server_address.afamily) do |client|
-				client.send(data, 0, server_address)
-				response, address = client.recvfrom(512)
-				
-				expect(response).to be == data
-			end
-		end
-	end
-end
diff --git a/spec/async/io/socket_spec.rb b/spec/async/io/socket_spec.rb
deleted file mode 100644
index f9cf303..0000000
--- a/spec/async/io/socket_spec.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/socket'
-require 'async/io/address'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::BasicSocket do
-	it_should_behave_like Async::IO::Generic
-end
-
-RSpec.describe Async::IO::Socket do
-	include_context Async::RSpec::Reactor
-	
-	it_should_behave_like Async::IO::Generic
-	
-	describe '#connect' do
-		let(:address) {Async::IO::Address.tcp('127.0.0.1', 12345)}
-		
-		it "should fail to connect if no listening server" do
-			expect do
-				Async::IO::Socket.connect(address)
-			end.to raise_exception(Errno::ECONNREFUSED)
-		end
-		
-		it "should close the socket when interrupted by a timeout" do
-			wrapper = double()
-			expect(Async::IO::Socket).to receive(:build).and_return(wrapper)
-			expect(wrapper).to receive(:connect).and_raise Async::TimeoutError
-			expect(wrapper).to receive(:close)
-			expect do
-				Async::IO::Socket.connect(address)
-			end.to raise_exception(Async::TimeoutError)
-		end
-	end
-	
-	describe '#bind' do
-		it "should fail to bind to port < 1024" do
-			address = Async::IO::Address.tcp('127.0.0.1', 1)
-			
-			expect do
-				Async::IO::Socket.bind(address)
-			end.to raise_exception(Errno::EACCES)
-		end
-		
-		it "can bind to port 0" do
-			address = Async::IO::Address.tcp('127.0.0.1', 0)
-			
-			Async::IO::Socket.bind(address) do |socket|
-				expect(socket.local_address.ip_port).to be > 10000
-				
-				expect(Async::Task.current.annotation).to include("#{socket.local_address.ip_port}")
-			end
-		end
-	end
-	
-	describe '#sync' do
-		it "should set TCP_NODELAY" do
-			address = Async::IO::Address.tcp('127.0.0.1', 0)
-			
-			socket = Async::IO::Socket.wrap(::Socket::AF_INET, ::Socket::SOCK_STREAM, ::Socket::IPPROTO_TCP)
-			
-			socket.sync = true
-			expect(socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY).bool).to be true
-			
-			socket.close
-		end
-	end
-	
-	describe '#timeout' do
-		subject{described_class.pair(:UNIX, :STREAM, 0)}
-		
-		it "should timeout while waiting to receive data" do
-			s1, s2 = *subject
-			
-			s2.timeout = 1
-			
-			expect{s2.recv(32)}.to raise_exception(Async::TimeoutError, "execution expired")
-			
-			s1.close
-			s2.close
-		end
-	end
-	
-	describe '.pair' do
-		subject{described_class.pair(:UNIX, :STREAM, 0)}
-		
-		it "should be able to send and recv" do
-			s1, s2 = *subject
-			
-			s1.send "Hello World", 0
-			s1.close
-			
-			expect(s2.recv(32)).to be == "Hello World"
-			s2.close
-		end
-		
-		it "should be connected" do
-			s1, s2 = *subject
-			
-			expect(s1).to be_connected
-			
-			s1.close
-			
-			expect(s2).to_not be_connected
-			
-			s2.close
-		end
-	end
-	
-	context '.pipe' do
-		let(:sockets) do
-			@sockets = described_class.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
-		end
-		
-		after do
-			@sockets&.each(&:close)
-		end
-		
-		let(:io) {sockets.first}
-		subject {sockets.last}
-		
-		it_should_behave_like Async::IO
-	end
-end
-
-RSpec.describe Async::IO::IPSocket do
-	it_should_behave_like Async::IO::Generic, [:inspect]
-end
diff --git a/spec/async/io/ssl_server_spec.rb b/spec/async/io/ssl_server_spec.rb
deleted file mode 100644
index 9ccd5f7..0000000
--- a/spec/async/io/ssl_server_spec.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/ssl_socket'
-require 'async/io/ssl_endpoint'
-
-require 'async/rspec/ssl'
-require 'async/queue'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::SSLServer do
-	include_context Async::RSpec::Reactor
-	
-	context 'single host' do
-		include_context Async::RSpec::SSL::VerifiedContexts
-		include_context Async::RSpec::SSL::ValidCertificate
-		
-		let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6780, reuse_port: true)}
-		let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context)}
-		let(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: client_context)}
-		
-		let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
-		
-		it "can see through to address" do
-			expect(server_endpoint.address).to be == endpoint.address
-		end
-		
-		it 'can accept_each connections' do
-			ready = Async::Queue.new
-			
-			# Accept a single incoming connection and then finish.
-			server_task = reactor.async do |task|
-				server_endpoint.bind do |server|
-					server.listen(10)
-					
-					ready.enqueue(true)
-					
-					server.accept_each do |peer, address|
-						data = peer.read(512)
-						peer.write(data)
-					end
-				end
-			end
-			
-			reactor.async do |task|
-				ready.dequeue
-				
-				client_endpoint.connect do |client|
-					client.write(data)
-					client.close_write
-					
-					expect(client.read(512)).to be == data
-				end
-				
-				server_task.stop
-			end
-		end
-	end
-	
-	context 'multiple hosts' do
-		let(:hosts) {['test.com', 'example.com']}
-		
-		include_context Async::RSpec::SSL::HostCertificates
-		
-		let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6782, reuse_port: true)}
-		let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context)}
-		let(:valid_client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, hostname: 'example.com', ssl_context: client_context)}
-		let(:invalid_client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, hostname: 'fleeb.com', ssl_context: client_context)}
-		
-		let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
-		
-		before do
-			certificates
-		end
-		
-		it 'can select correct host' do
-			ready = Async::Queue.new
-			
-			# Accept a single incoming connection and then finish.
-			server_task = reactor.async do |task|
-				server_endpoint.bind do |server|
-					server.listen(10)
-					
-					ready.enqueue(true)
-					
-					server.accept_each do |peer, address|
-						expect(peer.hostname).to be == 'example.com'
-						
-						data = peer.read(512)
-						peer.write(data)
-					end
-				end
-			end
-			
-			reactor.async do
-				ready.dequeue
-				
-				valid_client_endpoint.connect do |client|
-					client.write(data)
-					client.close_write
-					
-					expect(client.read(512)).to be == data
-				end
-				
-				server_task.stop
-			end
-		end
-		
-		it 'it fails with invalid host' do
-			ready = Async::Queue.new
-			
-			# Accept a single incoming connection and then finish.
-			server_task = reactor.async do |task|
-				server_endpoint.bind do |server|
-					server.listen(10)
-					
-					ready.enqueue(true)
-					
-					server.accept_each do |peer, address|
-						peer.close
-					end
-				end
-			end
-			
-			reactor.async do
-				ready.dequeue
-				
-				expect do
-					invalid_client_endpoint.connect do |client|
-					end
-				end.to raise_exception(OpenSSL::SSL::SSLError, /handshake failure/)
-				
-				server_task.stop
-			end.wait
-		end
-	end
-end
diff --git a/spec/async/io/ssl_socket_spec.rb b/spec/async/io/ssl_socket_spec.rb
deleted file mode 100644
index a2f640d..0000000
--- a/spec/async/io/ssl_socket_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/ssl_endpoint'
-require 'async/queue'
-require 'async/rspec/ssl'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::SSLSocket do
-	it_should_behave_like Async::IO::Generic
-	
-	describe "#connect" do
-		include_context Async::RSpec::Reactor
-		include_context Async::RSpec::SSL::VerifiedContexts
-		
-		# Shared port for localhost network tests.
-		let!(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6779, reuse_port: true, timeout: 10)}
-		let!(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context, timeout: 20)}
-		let!(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: client_context, timeout: 20)}
-		
-		let(:data) {"The quick brown fox jumped over the lazy dog."}
-		
-		let!(:server_task) do
-			ready = Async::Queue.new
-			
-			# Accept a single incoming connection and then finish.
-			reactor.async do |task|
-				server_endpoint.bind do |server|
-					ready.enqueue(server)
-					server.listen(10)
-					
-					begin
-						server.accept do |peer, address|
-							expect(peer.timeout).to be == 10
-							
-							data = peer.read(512)
-							peer.write(data)
-						end
-					rescue OpenSSL::SSL::SSLError
-						# ignore.
-					end
-				end
-			end
-			
-			ready.dequeue
-		end
-		
-		context "with a trusted certificate" do
-			include_context Async::RSpec::SSL::ValidCertificate
-			
-			it "should start server and send data" do
-				reactor.async do
-					client_endpoint.connect do |client|
-						# expect(client).to be_connected
-						expect(client.timeout).to be == 10
-						
-						client.write(data)
-						client.close_write
-						
-						expect(client.read(512)).to be == data
-					end
-				end
-			end
-		end
-		
-		context "with an untrusted certificate" do
-			include_context Async::RSpec::SSL::InvalidCertificate
-			
-			it "should fail to connect" do
-				reactor.async do
-					expect do
-						client_endpoint.connect
-					end.to raise_exception(OpenSSL::SSL::SSLError)
-				end.wait
-			end
-		end
-	end
-end
diff --git a/spec/async/io/standard_spec.rb b/spec/async/io/standard_spec.rb
deleted file mode 100644
index b8f4111..0000000
--- a/spec/async/io/standard_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/standard'
-
-RSpec.describe Async::IO::STDIN do
-	include_context Async::RSpec::Reactor
-	
-	it "should be able to read" do
-		expect(subject.read(0)).to be == ""
-	end
-end
-
-RSpec.describe Async::IO::STDOUT do
-	include_context Async::RSpec::Reactor
-	
-	it "should be able to write" do
-		expect(subject.write("")).to be == 0
-	end
-end
-
-RSpec.describe Async::IO::STDERR do
-	include_context Async::RSpec::Reactor
-	
-	it "should be able to write" do
-		expect(subject.write("")).to be == 0
-	end
-end
\ No newline at end of file
diff --git a/spec/async/io/stream_context.rb b/spec/async/io/stream_context.rb
deleted file mode 100644
index b389724..0000000
--- a/spec/async/io/stream_context.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/rspec/buffer'
-require 'async/io/stream'
-
-RSpec.shared_context Async::IO::Stream do
-	include_context Async::RSpec::Buffer
-	subject {described_class.new(buffer)}
-	let(:io) {subject.io}
-end
diff --git a/spec/async/io/stream_spec.rb b/spec/async/io/stream_spec.rb
deleted file mode 100644
index 7c1ec31..0000000
--- a/spec/async/io/stream_spec.rb
+++ /dev/null
@@ -1,355 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io'
-require 'async/io/socket'
-require 'async/clock'
-
-require_relative 'generic_examples'
-require_relative 'stream_context'
-
-RSpec.describe Async::IO::Stream do
-	# This constant is part of the public interface, but was renamed to `Async::IO::BLOCK_SIZE`.
-	describe "::BLOCK_SIZE" do
-		it "should exist and be reasonable" do
-			expect(Async::IO::Stream::BLOCK_SIZE).to be_between(1024, 1024*128)
-		end
-	end
-	
-	context "socket I/O" do
-		let(:sockets) do
-			@sockets = Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
-		end
-		
-		after do
-			@sockets&.each(&:close)
-		end
-		
-		let(:io) {sockets.first}
-		subject {described_class.new(sockets.last)}
-		
-		it_should_behave_like Async::IO
-		
-		describe '#drain_write_buffer' do
-			include_context Async::RSpec::Reactor
-			let(:output) {described_class.new(sockets.last)}
-			subject {described_class.new(sockets.first)}
-			
-			let(:buffer_size) {1024*6}
-			
-			it "can interleave calls to flush" do
-				tasks = 2.times.map do |i|
-					reactor.async do
-						buffer = i.to_s * buffer_size
-						128.times do
-							output.write(buffer)
-							output.flush
-						end
-					end
-				end
-				
-				reactor.async do
-					tasks.each(&:wait)
-					output.close
-				end
-				
-				Async::Task.current.sleep(1)
-				
-				while buffer = subject.read(buffer_size)
-					expect(buffer).to be == (buffer[0] * buffer_size)
-				end
-			end
-			
-			it "handles write failures" do
-				subject.close
-				
-				task = reactor.async do
-					output.write("Hello World")
-					output.flush
-				end
-				
-				expect do
-					task.wait
-				end.to raise_error(Errno::EPIPE)
-				
-				write_buffer = output.instance_variable_get(:@write_buffer)
-				drain_buffer = output.instance_variable_get(:@drain_buffer)
-				
-				expect(write_buffer).to be_empty
-				expect(drain_buffer).to be_empty
-			end
-		end
-		
-		describe '#close_read' do
-			subject {described_class.new(sockets.last)}
-			
-			it "can close the reading end of the stream" do
-				expect(subject.io).to receive(:close_read).and_call_original
-				
-				subject.close_read
-				
-				# Ruby <= 2.4 raises an exception even with exception: false
-				# expect(stream.read).to be_nil
-			end
-			
-			it "can close the writing end of the stream" do
-				expect(subject.io).to receive(:close_write).and_call_original
-				
-				subject.write("Oh yes!")
-				subject.close_write
-				
-				expect do
-					subject.write("Oh no!")
-					subject.flush
-				end.to raise_error(IOError, /not opened for writing/)
-			end
-		end
-		
-		describe '#read_exactly' do
-			it "can read several bytes" do
-				io.write("hello\nworld\n")
-				
-				expect(subject.read_exactly(4)).to be == 'hell'
-			end
-			
-			it "can raise exception if io is eof" do
-				io.close
-				
-				expect do
-					subject.read_exactly(4)
-				end.to raise_error(EOFError)
-			end
-		end
-	end
-	
-	context "performance (BLOCK_SIZE: #{Async::IO::BLOCK_SIZE} MAXIMUM_READ_SIZE: #{Async::IO::MAXIMUM_READ_SIZE})" do
-		include_context Async::RSpec::Reactor
-		
-		let!(:stream) {described_class.open("/dev/zero")}
-		after {stream.close}
-		
-		it "can read data quickly" do |example|
-			data = nil
-			
-			duration = Async::Clock.measure do
-				data = stream.read(1024**3)
-			end
-			
-			size = data.bytesize / 1024**2
-			rate = size / duration
-			
-			example.reporter.message "Read #{size.round(2)}MB of data at #{rate.round(2)}MB/s."
-			
-			expect(rate).to be > 128
-		end
-	end
-	
-	context "buffered I/O" do
-		include_context Async::IO::Stream
-		include_context Async::RSpec::Memory
-		include_context Async::RSpec::Reactor
-		
-		describe '#read' do
-			it "can read zero length" do
-				result = subject.read(0)
-				
-				expect(result).to be == ""
-				expect(result.encoding).to be == Encoding::BINARY
-			end
-			
-			it "should read everything" do
-				io.write "Hello World"
-				io.seek(0)
-				
-				expect(subject.io).to receive(:read_nonblock).and_call_original.twice
-				
-				expect(subject.read).to be == "Hello World"
-				expect(subject).to be_eof
-			end
-		
-			it "should read only the amount requested" do
-				io.write "Hello World"
-				io.seek(0)
-				
-				expect(subject.io).to receive(:read_nonblock).and_call_original.once
-				
-				expect(subject.read_partial(4)).to be == "Hell"
-				expect(subject).to_not be_eof
-				
-				expect(subject.read_partial(20)).to be == "o World"
-				expect(subject).to be_eof
-			end
-		
-			context "with large content", if: !Async::IO.buffer? do
-				it "allocates expected amount of bytes" do
-					io.write("." * 16*1024)
-					io.seek(0)
-					
-					buffer = nil
-					
-					expect do
-						# The read buffer is already allocated, and it will be resized to fit the incoming data. It will be swapped with an empty buffer.
-						buffer = subject.read(16*1024)
-					end.to limit_allocations.of(String, count: 1, size: 0)
-					
-					expect(buffer.size).to be == 16*1024
-				end
-			end
-		end
-		
-		describe '#read_until' do
-			it "can read a line" do
-				io.write("hello\nworld\n")
-				io.seek(0)
-				
-				expect(subject.read_until("\n")).to be == 'hello'
-				expect(subject.read_until("\n")).to be == 'world'
-				expect(subject.read_until("\n")).to be_nil
-			end
-		
-			context "with 1-byte block size" do
-				subject! {Async::IO::Stream.new(buffer, block_size: 1)}
-				
-				it "can read a line with a multi-byte pattern" do
-					io.write("hello\r\nworld\r\n")
-					io.seek(0)
-					
-					expect(subject.read_until("\r\n")).to be == 'hello'
-					expect(subject.read_until("\r\n")).to be == 'world'
-					expect(subject.read_until("\r\n")).to be_nil
-				end
-			end
-			
-			context "with large content", if: !Async::IO.buffer? do
-				it "allocates expected amount of bytes" do
-					subject
-					
-					expect do
-						subject.read_until("b")
-					end.to limit_allocations.of(String, size: 0, count: 1)
-				end
-			end
-		end
-		
-		describe '#flush' do
-			it "should not call write if write buffer is empty" do
-				expect(subject.io).to_not receive(:write)
-				
-				subject.flush
-			end
-		
-			it "should flush underlying data when it exceeds block size" do
-				expect(subject.io).to receive(:write).and_call_original.once
-				
-				subject.block_size.times do
-					subject.write("!")
-				end
-			end
-		end
-		
-		describe '#read_partial' do
-			before(:each) do
-				string = "Hello World!"
-				
-				io.write(string * (1 + (Async::IO::BLOCK_SIZE / string.bytesize)))
-				io.seek(0)
-			end
-			
-			it "should avoid calling read" do
-				expect(subject.io).to receive(:read_nonblock).and_call_original.once
-				
-				expect(subject.read_partial(12)).to be == "Hello World!"
-			end
-			
-			context "with large content", if: !Async::IO.buffer? do
-				it "allocates only the amount required" do
-					expect do
-						subject.read(4*1024)
-					end.to limit_allocations.of(String, count: 2, size: 4*1024+1)
-				end
-				
-				it "allocates exact number of bytes being read" do
-					expect do
-						subject.read_partial(subject.block_size * 2)
-					end.to limit_allocations.of(String, count: 1, size: 0)
-				end
-				
-				it "allocates expected amount of bytes" do
-					buffer = nil
-					
-					expect do
-						buffer = subject.read_partial
-					end.to limit_allocations.of(String, count: 1)
-					
-					expect(buffer.size).to be == subject.block_size
-				end
-			end
-			
-			context "has the right encoding" do
-				it "with a normal partial_read" do
-					expect(subject.read_partial(1).encoding).to be == Encoding::BINARY
-				end
-				
-				it "with a zero-length partial_read" do
-					expect(subject.read_partial(0).encoding).to be == Encoding::BINARY
-				end
-			end
-		end
-		
-		describe '#write' do
-			it "should read one line" do
-				expect(subject.io).to receive(:write).and_call_original.once
-				
-				subject.write "Hello World\n"
-				subject.flush
-				
-				io.seek(0)
-				expect(subject.read).to be == "Hello World\n"
-			end
-		end
-		
-		describe '#eof' do
-			it "should terminate subject" do
-				expect do
-					subject.eof!
-				end.to raise_exception(EOFError)
-				
-				expect(subject).to be_eof
-			end
-		end
-		
-		describe '#close' do
-			it 'can be closed even if underlying io is closed' do
-				io.close
-				
-				expect(subject.io).to be_closed
-				
-				# Put some data in the write buffer
-				subject.write "."
-				
-				expect do
-					subject.close
-				end.to_not raise_exception
-			end
-		end
-	end
-end
diff --git a/spec/async/io/tcp_socket_spec.rb b/spec/async/io/tcp_socket_spec.rb
deleted file mode 100644
index e15d954..0000000
--- a/spec/async/io/tcp_socket_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, reactor to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/tcp_socket'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::TCPSocket do
-	include_context Async::RSpec::Reactor
-	
-	it_should_behave_like Async::IO::Generic
-	
-	# Shared port for localhost network tests.
-	let(:server_address) {Async::IO::Address.tcp("localhost", 6788)}
-	let(:data) {"The quick brown fox jumped over the lazy dog."}
-	
-	describe Async::IO::TCPServer do
-		it_should_behave_like Async::IO::Generic
-	end
-	
-	describe Async::IO::TCPServer do
-		let!(:server_task) do
-			reactor.async do |task|
-				server = Async::IO::TCPServer.new("localhost", 6788)
-				
-				peer, address = server.accept
-				
-				data = peer.gets
-				peer.puts(data)
-				peer.flush
-				
-				peer.close
-				server.close
-			end
-		end
-		
-		let(:client) {Async::IO::TCPSocket.new("localhost", 6788)}
-		
-		it "can read into output buffer" do
-			client.puts("Hello World")
-			client.flush
-			
-			buffer = String.new
-			# 20 is bigger than echo response...
-			data = client.read(20, buffer)
-			
-			expect(buffer).to_not be_empty
-			expect(buffer).to be == data
-			
-			client.close
-			server_task.wait
-		end
-		
-		it "should start server and send data" do
-			# Accept a single incoming connection and then finish.
-			client.puts(data)
-			client.flush
-			
-			expect(client.gets).to be == data
-			
-			client.close
-			server_task.wait
-		end
-	end
-end
diff --git a/spec/async/io/threads_spec.rb b/spec/async/io/threads_spec.rb
deleted file mode 100644
index a06d289..0000000
--- a/spec/async/io/threads_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/threads'
-
-RSpec.describe Async::IO::Threads do
-	include_context Async::RSpec::Reactor
-	
-	describe '#async' do
-		it "can schedule work on a different thread" do
-			thread = subject.async do
-				Thread.current
-			end.wait
-			
-			expect(thread).to be_kind_of Thread
-			expect(thread).to_not be Thread.current
-		end
-		
-		it "can kill thread when stopping task" do
-			sleeping = Async::IO::Notification.new
-			
-			thread = nil
-			
-			task = subject.async do
-				thread = Thread.current
-				sleeping.signal
-				sleep
-			end
-			
-			sleeping.wait
-			
-			task.stop
-			10.times do
-				pp thread
-				sleep(0.1)
-				break unless thread.status
-			end
-			
-			expect(thread.status).to be_nil
-		ensure
-			sleeping.close
-		end
-	end
-end
diff --git a/spec/async/io/trap_spec.rb b/spec/async/io/trap_spec.rb
deleted file mode 100644
index a25dea9..0000000
--- a/spec/async/io/trap_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/trap'
-
-RSpec.describe Async::IO::Trap do
-	include_context Async::RSpec::Reactor
-	
-	subject {described_class.new(:USR2)}
-	
-	it "can ignore signal" do
-		subject.ignore!
-		
-		Process.kill(:USR2, Process.pid)
-	end
-	
-	it "should wait for signal" do
-		trapped = false
-		
-		waiting_task = reactor.async do
-			subject.wait do
-				trapped = true
-				break
-			end
-		end
-		
-		subject.trigger
-		
-		waiting_task.wait
-		
-		expect(trapped).to be_truthy
-	end
-	
-	it "should create transient task" do
-		task = subject.async(transient: true) do
-			# Trapped.
-		end
-		
-		expect(task).to be_transient
-	end
-end
diff --git a/spec/async/io/udp_socket_spec.rb b/spec/async/io/udp_socket_spec.rb
deleted file mode 100644
index 5af5cd2..0000000
--- a/spec/async/io/udp_socket_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/udp_socket'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::UDPSocket do
-	include_context Async::RSpec::Reactor
-	
-	it_should_behave_like Async::IO::Generic
-	
-	let(:data) {"The quick brown fox jumped over the lazy dog."}
-	
-	it "should echo data back to peer" do
-		reactor.async do
-			server = Async::IO::UDPSocket.new(Socket::AF_INET)
-			server.bind("127.0.0.1", 6778)
-			
-			packet, address = server.recvfrom(512)
-			server.send(packet, 0, address[3], address[1])
-			
-			server.close
-		end
-		
-		reactor.async do
-			client = Async::IO::UDPSocket.new(Socket::AF_INET)
-			client.connect("127.0.0.1", 6778)
-			
-			client.send(data, 0)
-			response = client.recv(512)
-			client.close
-			
-			expect(response).to be == data
-		end.wait
-	end
-end
diff --git a/spec/async/io/unix_endpoint_spec.rb b/spec/async/io/unix_endpoint_spec.rb
deleted file mode 100644
index 373dacc..0000000
--- a/spec/async/io/unix_endpoint_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/unix_endpoint'
-require 'async/io/stream'
-require 'fileutils'
-
-RSpec.describe Async::IO::UNIXEndpoint do
-	include_context Async::RSpec::Reactor
-	
-	let(:data) {"The quick brown fox jumped over the lazy dog."} 
-	let(:path) {File.join(__dir__, "unix-socket")}
-	subject {described_class.unix(path)}
-	
-	before(:each) do
-		FileUtils.rm_f path
-	end
-	
-	after do
-		FileUtils.rm_f path
-	end
-	
-	it "should echo data back to peer" do
-		server_task = reactor.async do
-			subject.accept do |peer|
-				peer.send(peer.recv(512))
-			end
-		end
-		
-		subject.connect do |client|
-			client.send(data)
-			
-			response = client.recv(512)
-			
-			expect(response).to be == data
-		end
-		
-		server_task.stop
-	end
-	
-	it "should fails to bind if there is an existing binding" do
-		condition = Async::Condition.new
-		
-		reactor.async do
-			condition.wait
-			
-			expect do
-				subject.bind
-			end.to raise_error(Errno::EADDRINUSE)
-		end
-		
-		server_task = reactor.async do
-			subject.bind do |server|
-				server.listen(1)
-				condition.signal
-			end
-		end
-		
-		server_task.stop
-	end
-	
-	context "using buffered stream" do
-		it "can use stream to read and write data" do
-			server_task = reactor.async do |task|
-				subject.accept do |peer|
-					stream = Async::IO::Stream.new(peer)
-					stream.write(stream.read)
-					stream.close
-				end
-			end
-			
-			reactor.async do
-				subject.connect do |client|
-					stream = Async::IO::Stream.new(client)
-					
-					stream.write(data)
-					stream.close_write
-					
-					expect(stream.read).to be == data
-				end
-			end.wait
-			
-			server_task.stop
-		end
-	end
-end
diff --git a/spec/async/io/unix_socket_spec.rb b/spec/async/io/unix_socket_spec.rb
deleted file mode 100644
index d9aa591..0000000
--- a/spec/async/io/unix_socket_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-
-# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
-# 
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-# 
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-# 
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-require 'async/io/unix_socket'
-
-require_relative 'generic_examples'
-
-RSpec.describe Async::IO::UNIXSocket do
-	include_context Async::RSpec::Reactor
-	
-	it_should_behave_like Async::IO::Generic
-	
-	let(:path) {File.join(__dir__, "unix-socket")}
-	let(:data) {"The quick brown fox jumped over the lazy dog."}
-	
-	before(:each) do
-		FileUtils.rm_f path
-	end
-	
-	after do
-		FileUtils.rm_f path
-	end
-	
-	it "should echo data back to peer" do
-		reactor.async do
-			Async::IO::UNIXServer.wrap(path) do |server|
-				server.accept do |peer|
-					peer.send(peer.recv(512))
-				end
-			end
-		end
-		
-		Async::IO::UNIXSocket.wrap(path) do |client|
-			client.send(data)
-			
-			response = client.recv(512)
-			
-			expect(response).to be == data
-		end
-	end
-end
-
-RSpec.describe Async::IO::UNIXServer do
-	it_should_behave_like Async::IO::Generic
-end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
deleted file mode 100644
index e13deed..0000000
--- a/spec/spec_helper.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'covered/rspec'
-require "async/rspec"
-
-require_relative 'addrinfo'
-
-RSpec.configure do |config|
-	# Enable flags like --only-failures and --next-failure
-	config.example_status_persistence_file_path = ".rspec_status"
-
-	config.expect_with :rspec do |c|
-		c.syntax = :expect
-	end
-end
-
-Signal.trap(:INT) { raise Interrupt }

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/address.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/address_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/binary_string.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/buffer.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/composite_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/endpoint/each.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/generic.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/host_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/notification.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/peer.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/protocol/generic.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/protocol/line.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/server.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/shared_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/socket_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/ssl_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/ssl_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/standard.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/stream.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/tcp_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/threads.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/trap.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/udp_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/unix_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/unix_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.3/lib/async/io/version.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/async-io-1.34.3.gemspec

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/address.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/address_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/binary_string.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/buffer.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/composite_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/endpoint/each.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/generic.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/host_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/notification.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/peer.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/protocol/generic.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/protocol/line.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/server.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/shared_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/socket_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/ssl_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/ssl_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/standard.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/stream.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/tcp_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/threads.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/trap.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/udp_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/unix_endpoint.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/unix_socket.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/async-io-1.34.1/lib/async/io/version.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/async-io-1.34.1.gemspec

No differences were encountered in the control files

More details

Full run details