diff --git a/.github/workflows/documentation-coverage.yaml b/.github/workflows/documentation-coverage.yaml new file mode 100644 index 0000000..b3bac9a --- /dev/null +++ b/.github/workflows/documentation-coverage.yaml @@ -0,0 +1,25 @@ +name: Documentation Coverage + +on: [push, pull_request] + +permissions: + contents: read + +env: + CONSOLE_OUTPUT: XTerm + COVERAGE: PartialSummary + +jobs: + validate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - name: Validate coverage + timeout-minutes: 5 + run: bundle exec bake decode:index:coverage lib diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 8dc5227..f5f553a 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -40,7 +40,7 @@ jobs: run: bundle exec bake utopia:project:static --force no - name: Upload documentation artifact - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@v3 with: path: docs @@ -55,4 +55,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v3 + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/rubocop.yaml b/.github/workflows/rubocop.yaml new file mode 100644 index 0000000..287c06d --- /dev/null +++ b/.github/workflows/rubocop.yaml @@ -0,0 +1,24 @@ +name: RuboCop + +on: [push, pull_request] + +permissions: + contents: read + +env: + CONSOLE_OUTPUT: XTerm + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby + bundler-cache: true + + - name: Run RuboCop + timeout-minutes: 10 + run: bundle exec rubocop diff --git a/.github/workflows/coverage.yaml b/.github/workflows/test-coverage.yaml similarity index 90% rename from .github/workflows/coverage.yaml rename to .github/workflows/test-coverage.yaml index 68adbf2..ffa0927 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,4 +1,4 @@ -name: Coverage +name: Test Coverage on: [push, pull_request] @@ -33,8 +33,8 @@ jobs: - name: Run tests timeout-minutes: 5 run: bundle exec bake test - - - uses: actions/upload-artifact@v3 + + - uses: actions/upload-artifact@v4 with: name: coverage-${{matrix.os}}-${{matrix.ruby}} path: .covered.db @@ -50,7 +50,7 @@ jobs: ruby-version: "3.3" bundler-cache: true - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 - name: Validate coverage timeout-minutes: 5 diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..3b8d476 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,53 @@ +AllCops: + DisabledByDefault: true + +Layout/IndentationStyle: + Enabled: true + EnforcedStyle: tabs + +Layout/InitialIndentation: + Enabled: true + +Layout/IndentationWidth: + Enabled: true + Width: 1 + +Layout/IndentationConsistency: + Enabled: true + EnforcedStyle: normal + +Layout/BlockAlignment: + Enabled: true + +Layout/EndAlignment: + Enabled: true + EnforcedStyleAlignWith: start_of_line + +Layout/BeginEndAlignment: + Enabled: true + EnforcedStyleAlignWith: start_of_line + +Layout/ElseAlignment: + Enabled: true + +Layout/DefEndAlignment: + Enabled: true + +Layout/CaseIndentation: + Enabled: true + +Layout/CommentIndentation: + Enabled: true + +Layout/EmptyLinesAroundClassBody: + Enabled: true + +Layout/EmptyLinesAroundModuleBody: + Enabled: true + +Style/FrozenStringLiteralComment: + Enabled: true + +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes diff --git a/config/sus.rb b/config/sus.rb index ea9e963..f99b9c2 100644 --- a/config/sus.rb +++ b/config/sus.rb @@ -3,5 +3,5 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'covered/sus' +require "covered/sus" include Covered::Sus diff --git a/gems.rb b/gems.rb index 325a6f1..6d8c096 100644 --- a/gems.rb +++ b/gems.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2023-2024, by Samuel Williams. -source 'https://rubygems.org' +source "https://rubygems.org" gemspec @@ -17,6 +17,8 @@ group :test do gem "sus" gem "covered" + gem "decode" + gem "rubocop" gem "bake-test" gem "bake-test-external" diff --git a/io-stream.gemspec b/io-stream.gemspec index 1915fdc..d48f111 100644 --- a/io-stream.gemspec +++ b/io-stream.gemspec @@ -10,8 +10,8 @@ Gem::Specification.new do |spec| spec.authors = ["Samuel Williams"] spec.license = "MIT" - spec.cert_chain = ['release.cert'] - spec.signing_key = File.expand_path('~/.gem/release.pem') + spec.cert_chain = ["release.cert"] + spec.signing_key = File.expand_path("~/.gem/release.pem") spec.homepage = "https://github.com/socketry/io-stream" @@ -20,7 +20,7 @@ Gem::Specification.new do |spec| "source_code_uri" => "https://github.com/socketry/io-stream.git", } - spec.files = Dir.glob(['{lib}/**/*', '*.md'], File::FNM_DOTMATCH, base: __dir__) + spec.files = Dir.glob(["{lib}/**/*", "*.md"], File::FNM_DOTMATCH, base: __dir__) spec.required_ruby_version = ">= 3.1" end diff --git a/lib/io/stream.rb b/lib/io/stream.rb index 02b382c..f5b24e9 100644 --- a/lib/io/stream.rb +++ b/lib/io/stream.rb @@ -3,8 +3,8 @@ # Released under the MIT License. # Copyright, 2023-2024, by Samuel Williams. -require_relative 'stream/version' -require_relative 'stream/buffered' +require_relative "stream/version" +require_relative "stream/buffered" class IO module Stream diff --git a/lib/io/stream/buffered.rb b/lib/io/stream/buffered.rb index c762ac1..b0f6572 100644 --- a/lib/io/stream/buffered.rb +++ b/lib/io/stream/buffered.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require_relative 'generic' +require_relative "generic" module IO::Stream class Buffered < Generic diff --git a/lib/io/stream/generic.rb b/lib/io/stream/generic.rb index 5aef093..27fa561 100644 --- a/lib/io/stream/generic.rb +++ b/lib/io/stream/generic.rb @@ -3,20 +3,20 @@ # Released under the MIT License. # Copyright, 2023-2024, by Samuel Williams. -require_relative 'string_buffer' +require_relative "string_buffer" -require_relative 'shim/buffered' -require_relative 'shim/readable' -require_relative 'shim/timeout' +require_relative "shim/buffered" +require_relative "shim/readable" +require_relative "shim/timeout" -require_relative 'openssl' +require_relative "openssl" module IO::Stream # The default block size for IO buffers. Defaults to 64KB (typical pipe buffer size). - BLOCK_SIZE = ENV.fetch('IO_STREAM_BLOCK_SIZE', 1024*64).to_i + BLOCK_SIZE = ENV.fetch("IO_STREAM_BLOCK_SIZE", 1024*64).to_i # The maximum read size when appending to IO buffers. Defaults to 8MB. - MAXIMUM_READ_SIZE = ENV.fetch('IO_STREAM_MAXIMUM_READ_SIZE', BLOCK_SIZE * 128).to_i + MAXIMUM_READ_SIZE = ENV.fetch("IO_STREAM_MAXIMUM_READ_SIZE", BLOCK_SIZE * 128).to_i class Generic def initialize(block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE) diff --git a/lib/io/stream/openssl.rb b/lib/io/stream/openssl.rb index e162bf9..4cf0e67 100644 --- a/lib/io/stream/openssl.rb +++ b/lib/io/stream/openssl.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'openssl' +require "openssl" module OpenSSL module SSL diff --git a/lib/io/stream/shim/buffered.rb b/lib/io/stream/shim/buffered.rb index 29a3013..84b777b 100644 --- a/lib/io/stream/shim/buffered.rb +++ b/lib/io/stream/shim/buffered.rb @@ -15,7 +15,7 @@ def buffered=(value) end end -require 'socket' +require "socket" unless BasicSocket.method_defined?(:buffered?, false) class BasicSocket @@ -50,7 +50,7 @@ def buffered=(value) end end -require 'stringio' +require "stringio" unless StringIO.method_defined?(:buffered?, false) class StringIO diff --git a/lib/io/stream/shim/readable.rb b/lib/io/stream/shim/readable.rb index b13aeb8..9d89c3d 100644 --- a/lib/io/stream/shim/readable.rb +++ b/lib/io/stream/shim/readable.rb @@ -12,7 +12,7 @@ def readable? end end -require 'socket' +require "socket" class BasicSocket unless method_defined?(:readable?, false) @@ -32,7 +32,7 @@ def readable? end end -require 'stringio' +require "stringio" class StringIO unless method_defined?(:readable?, false) @@ -42,7 +42,7 @@ def readable? end end -require 'openssl' +require "openssl" class OpenSSL::SSL::SSLSocket unless method_defined?(:readable?, false) diff --git a/lib/io/stream/shim/timeout.rb b/lib/io/stream/shim/timeout.rb index 9246318..613bef3 100644 --- a/lib/io/stream/shim/timeout.rb +++ b/lib/io/stream/shim/timeout.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + class IO unless const_defined?(:TimeoutError) # Compatibility shim. diff --git a/readme.md b/readme.md index d5b4e4a..260e815 100644 --- a/readme.md +++ b/readme.md @@ -20,11 +20,11 @@ We welcome contributions to this project. ### Developer Certificate of Origin -This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted. +In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. -### Contributor Covenant +### Community Guidelines -This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms. +This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers. ## See Also diff --git a/test/io/stream.rb b/test/io/stream.rb index 910bf1b..d60cc47 100644 --- a/test/io/stream.rb +++ b/test/io/stream.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'io/stream' +require "io/stream" describe IO::Stream do it "can wrap an IO object" do @@ -22,4 +22,4 @@ expect(stream2).to be_equal(stream) end -end \ No newline at end of file +end diff --git a/test/io/stream/buffered.rb b/test/io/stream/buffered.rb index b325321..b15acf4 100644 --- a/test/io/stream/buffered.rb +++ b/test/io/stream/buffered.rb @@ -3,11 +3,11 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'io/stream/buffered' +require "io/stream/buffered" -require 'sus/fixtures/async/reactor_context' -require 'sus/fixtures/openssl/verified_certificate_context' -require 'sus/fixtures/openssl/valid_certificate_context' +require "sus/fixtures/async/reactor_context" +require "sus/fixtures/openssl/verified_certificate_context" +require "sus/fixtures/openssl/valid_certificate_context" describe IO::Stream::Buffered do # This constant is part of the public interface, but was renamed to `Async::IO::BLOCK_SIZE`. @@ -32,7 +32,7 @@ expect(client.read(13)).to be == "Hello, World!" end - describe '#read' do + describe "#read" do it "can read zero length" do data = client.read(0) @@ -71,7 +71,7 @@ end end - describe '#peek' do + describe "#peek" do it "can peek at the read buffer" do server.write "Hello World" server.close @@ -122,12 +122,12 @@ end end - describe '#read_exactly' do + describe "#read_exactly" do it "can read several bytes" do server.write "Hello World" server.close - expect(client.read_exactly(4)).to be == 'Hell' + expect(client.read_exactly(4)).to be == "Hell" end it "can raise exception if io is eof" do @@ -139,13 +139,13 @@ end end - describe '#read_until' do + describe "#read_until" do it "can read a line" do server.write("hello\nworld\n") server.close - expect(client.read_until("\n")).to be == 'hello' - expect(client.read_until("\n")).to be == 'world' + expect(client.read_until("\n")).to be == "hello" + expect(client.read_until("\n")).to be == "world" expect(client.read_until("\n")).to be_nil end @@ -156,14 +156,14 @@ client.block_size = 1 - expect(client.read_until("\n")).to be == 'hello' - expect(client.read_until("\n")).to be == 'world' + expect(client.read_until("\n")).to be == "hello" + expect(client.read_until("\n")).to be == "world" expect(client.read_until("\n")).to be_nil end end end - describe '#read_partial' do + describe "#read_partial" do def before super @@ -188,7 +188,7 @@ def before end end - describe '#write' do + describe "#write" do it "should read one line" do expect(server).to receive(:syswrite) @@ -209,7 +209,7 @@ def before end end - describe '#flush' do + describe "#flush" do it "should not call write if write buffer is empty" do expect(server).not.to receive(:syswrite) @@ -227,7 +227,7 @@ def before end end - with '#eof?' do + with "#eof?" do it "should return true when there is no data available" do server.close expect(client.eof?).to be_truthy @@ -241,7 +241,7 @@ def before end end - with '#eof!' do + with "#eof!" do it "should immediately raise EOFError" do expect do client.eof! @@ -251,7 +251,7 @@ def before end end - with '#readable?' do + with "#readable?" do it "should return true when the stream might be open" do expect(client.readable?).to be_truthy end @@ -272,7 +272,7 @@ def before end end - with '#close_write' do + with "#close_write" do it "can close the write side of the stream" do server.write("Hello World!") @@ -284,7 +284,7 @@ def before end end - with '#close' do + with "#close" do it "should close the stream" do server.close expect(client.read).to be_nil @@ -322,7 +322,7 @@ def before end end - with '#drain_write_buffer' do + with "#drain_write_buffer" do include Sus::Fixtures::Async::ReactorContext let(:buffer_size) {1024*6} @@ -372,7 +372,7 @@ def before end ABidirectionalStream = Sus::Shared("a bidirectional stream") do - with '#close_write' do + with "#close_write" do it "can close the write side of the stream" do server.write("Hello World!") server.close_write @@ -394,7 +394,7 @@ def before let(:client) {IO::Stream::Buffered.wrap(pipe[0])} let(:server) {IO::Stream::Buffered.wrap(pipe[1])} - def after + def after(error = nil) pipe.each(&:close) super end @@ -425,7 +425,7 @@ def after let(:client) {IO::Stream::Buffered.wrap(sockets[0])} let(:server) {IO::Stream::Buffered.wrap(sockets[1])} - def after + def after(error = nil) sockets.each(&:close) super end @@ -458,7 +458,7 @@ def before ].each(&:wait) end - def after + def after(error = nil) sockets.each(&:close) super end diff --git a/test/io/stream/buffered/syswrite.rb b/test/io/stream/buffered/syswrite.rb index 7050f23..4ddc5b5 100644 --- a/test/io/stream/buffered/syswrite.rb +++ b/test/io/stream/buffered/syswrite.rb @@ -3,8 +3,8 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'io/stream/buffered' -require 'sus/fixtures/async/reactor_context' +require "io/stream/buffered" +require "sus/fixtures/async/reactor_context" describe "IO.pipe" do include Sus::Fixtures::Async::ReactorContext @@ -13,7 +13,7 @@ let(:client) {IO::Stream::Buffered.wrap(pipe[0])} let(:server) {IO::Stream::Buffered.wrap(pipe[1])} - def after + def after(error = nil) pipe.each(&:close) super end diff --git a/test/io/stream/performance.rb b/test/io/stream/performance.rb index 28661d2..a36ddbd 100644 --- a/test/io/stream/performance.rb +++ b/test/io/stream/performance.rb @@ -3,14 +3,14 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'io/stream/buffered' -require 'async/clock' +require "io/stream/buffered" +require "async/clock" describe IO::Stream::Buffered do with "performance (BLOCK_SIZE: #{IO::Stream::BLOCK_SIZE} MAXIMUM_READ_SIZE: #{IO::Stream::MAXIMUM_READ_SIZE})" do let(:stream) {subject.open("/dev/zero")} - def after + def after(error = nil) stream.close super diff --git a/test/io/stream/shim/buffered.rb b/test/io/stream/shim/buffered.rb index f3c804a..09ec761 100644 --- a/test/io/stream/shim/buffered.rb +++ b/test/io/stream/shim/buffered.rb @@ -3,10 +3,10 @@ # Released under the MIT License. # Copyright, 2023-2024, by Samuel Williams. -require 'io/stream/shim/buffered' +require "io/stream/shim/buffered" describe IO do - let(:io) {IO.new(IO.sysopen('/dev/null', 'w'))} + let(:io) {IO.new(IO.sysopen("/dev/null", "w"))} it "should be buffered by default" do expect(io).to be(:buffered?) @@ -20,13 +20,13 @@ end describe TCPSocket do - let(:client) {@client = TCPSocket.new('localhost', @server.local_address.ip_port)} + let(:client) {@client = TCPSocket.new("localhost", @server.local_address.ip_port)} def before - @server = TCPServer.new('localhost', 0) + @server = TCPServer.new("localhost", 0) end - def after + def after(error = nil) @server.close @client&.close @@ -53,7 +53,7 @@ def after let(:client) {sockets[0]} let(:server) {sockets[1]} - def after + def after(error = nil) client.close server.close diff --git a/test/io/stream/shim/readable.rb b/test/io/stream/shim/readable.rb index 4417cec..fa0fe84 100644 --- a/test/io/stream/shim/readable.rb +++ b/test/io/stream/shim/readable.rb @@ -1,9 +1,12 @@ # frozen_string_literal: true -require 'io/stream/shim/readable' +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require "io/stream/shim/readable" describe IO do - let(:io) {IO.new(IO.sysopen('/dev/null', 'w'))} + let(:io) {IO.new(IO.sysopen("/dev/null", "w"))} it "should be readable" do expect(io).to be(:readable?) @@ -22,11 +25,11 @@ attr :server def before - @server = TCPServer.new('localhost', 0) - @client = TCPSocket.new('localhost', @server.local_address.ip_port) + @server = TCPServer.new("localhost", 0) + @client = TCPSocket.new("localhost", @server.local_address.ip_port) end - def after + def after(error = nil) @server.close @client&.close diff --git a/test/io/stream/string_buffer.rb b/test/io/stream/string_buffer.rb index 9c45a90..1b68a66 100644 --- a/test/io/stream/string_buffer.rb +++ b/test/io/stream/string_buffer.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2024, by Samuel Williams. -require 'io/stream/string_buffer' +require "io/stream/string_buffer" describe IO::Stream::StringBuffer do let(:string_buffer) {subject.new}