Skip to content
This repository was archived by the owner on Sep 5, 2025. It is now read-only.
8 changes: 6 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
ruby: ['3.1', '3.2', 'head']
ruby: ['3.2', '3.3', '3.4', 'head']

name: >-
${{matrix.os}}, ${{matrix.ruby}}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{matrix.os}}-${{matrix.ruby}}-libev
cancel-in-progress: true

runs-on: ${{matrix.os}}

env:
POLYPHONY_LIBEV: "1"

steps:
- name: Setup machine
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/test_io_uring.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
ruby: ['3.1', '3.2', 'head']
ruby: ['3.2', '3.3', '3.4', 'head']

name: >-
${{matrix.os}}, ${{matrix.ruby}}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{matrix.os}}-${{matrix.ruby}}-io_uring
cancel-in-progress: true

runs-on: ${{matrix.os}}

steps:
- name: Checkout repository and submodules
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Ruby
Expand Down
5 changes: 3 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
AllCops:
TargetRubyVersion: 3.2
TargetRubyVersion: 3.4
RubyInterpreters:
- ruby
Exclude:
Expand All @@ -9,6 +9,7 @@ AllCops:
- 'Gemfile*'
- 'ext/**/*.rb'
- lib/polyphony/adapters/irb.rb
NewCops: enable

Style/LambdaCall:
Enabled: false
Expand Down Expand Up @@ -202,4 +203,4 @@ Style/SlicingWithRange:

Style/RaiseArgs:
Exclude:
- lib/polyphony/extensions/fiber.rb
- lib/polyphony/extensions/fiber.rb
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

- Add support for Ruby 3.3 and 3.4
- Remove support for Ruby 3.1
- Forward keyword arguments in `Polyphony::ResourcePool`

## 1.6 2023-08-05

- Refactor exception instantiation
Expand Down Expand Up @@ -912,4 +918,4 @@
- Promised threads
- HTTP server
- Redis interface
- PostgreSQL interface
- PostgreSQL interface
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
## What is Polyphony?

Polyphony is a library for building concurrent applications in Ruby. Polyphony
harnesses the power of [Ruby fibers](https://rubyapi.org/3.2/o/fiber) to provide
harnesses the power of [Ruby fibers](https://rubyapi.org/3.4/o/fiber) to provide
a cooperative, sequential coroutine-based concurrency model. Under the hood,
Polyphony uses [io_uring](https://unixism.net/loti/what_is_io_uring.html) or
[libev](https://github.com/enki/libev) to maximize I/O performance.
Expand Down
4 changes: 2 additions & 2 deletions docs/advanced-io.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ minimizing memory use and GC pressure.
## Compressing and decompressing in-flight data

You might be familiar with Ruby's [zlib](https://github.com/ruby/zlib) gem (docs
[here](https://rubyapi.org/3.2/o/zlib)), which can be used to compress and
[here](https://rubyapi.org/3.4/o/zlib)), which can be used to compress and
uncompress data using the popular gzip format. Imagine we want to implement an
HTTP server that can serve files compressed using gzip:

Expand Down Expand Up @@ -318,4 +318,4 @@ provided by Polyphony, which lets us write less code, have it run faster, have
it run concurrently, and minimize memory allocations and pressure on the Ruby
GC. Feel free to browse the [IO
examples](https://github.com/digital-fabric/polyphony/tree/master/examples/io)
included in Polyphony.
included in Polyphony.
2 changes: 1 addition & 1 deletion docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
## What is Polyphony?

Polyphony is a library for building concurrent applications in Ruby. Polyphony
harnesses the power of [Ruby fibers](https://rubyapi.org/3.2/o/fiber) to provide
harnesses the power of [Ruby fibers](https://rubyapi.org/3.3/o/fiber) to provide
a cooperative, sequential coroutine-based concurrency model. Under the hood,
Polyphony uses [io_uring](https://unixism.net/loti/what_is_io_uring.html) or
[libev](https://github.com/enki/libev) to maximize I/O performance.
Expand Down
5 changes: 3 additions & 2 deletions lib/polyphony/core/resource_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ def acquire(&block)
#
# @param sym [Symbol] method name
# @param args [Array<any>] method arguments
# @param kwargs [Hash] keyword arguments
# @return [any] result of method call
def method_missing(sym, *args, &block)
acquire { |r| r.send(sym, *args, &block) }
def method_missing(sym, *args, **kwargs, &block)
acquire { |r| r.send(sym, *args, **kwargs, &block) }
end

# @!visibility private
Expand Down
21 changes: 9 additions & 12 deletions lib/polyphony/extensions/io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,48 @@ def binwrite(name, string, offset = nil)
end
end

# @!visibility private
EMPTY_HASH = {}.freeze

# @!visibility private
alias_method :orig_foreach, :foreach

# @!visibility private
def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
def foreach(name, sep = $/, limit = nil, **kwargs, &block)
if sep.is_a?(Integer)
sep = $/
limit = sep
end
File.open(name, 'r') do |f|
f.each_line(sep, limit, chomp: getline_args[:chomp], &block)
f.each_line(sep, limit, chomp: kwargs[:chomp], &block)
end
end

# @!visibility private
alias_method :orig_read, :read

# @!visibility private
def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
def read(name, length = nil, offset = nil, **kwargs)
if length.is_a?(Hash)
opt = length
kwargs = length
length = nil
end
File.open(name, opt[:mode] || 'r') do |f|
File.open(name, kwargs[:mode] || 'r') do |f|
f.seek(offset) if offset
length ? f.read(length) : f.read
end
end

alias_method :orig_readlines, :readlines
def readlines(name, sep = $/, limit = nil, getline_args = EMPTY_HASH)
def readlines(name, sep = $/, limit = nil, **kwargs)
File.open(name, 'r') do |f|
f.readlines(sep, **getline_args)
f.readlines(sep, **kwargs)
end
end

# @!visibility private
alias_method :orig_write, :write

# @!visibility private
def write(name, string, offset = nil, opt = EMPTY_HASH)
File.open(name, opt[:mode] || 'w') do |f|
def write(name, string, offset = nil, **kwargs)
File.open(name, kwargs[:mode] || 'w') do |f|
f.seek(offset) if offset
f.write(string)
end
Expand Down
26 changes: 16 additions & 10 deletions polyphony.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@ Gem::Specification.new do |s|
s.extra_rdoc_files = ["README.md"]
s.extensions = ["ext/polyphony/extconf.rb"]
s.require_paths = ["lib"]
s.required_ruby_version = '>= 3.1'
s.required_ruby_version = '>= 3.2'

s.add_development_dependency 'rake-compiler', '1.2.1'
s.add_development_dependency 'minitest', '5.17.0'
s.add_development_dependency 'rake-compiler', '1.3.0'
s.add_development_dependency 'minitest', '5.25.5'
s.add_development_dependency 'simplecov', '0.22.0'
s.add_development_dependency 'rubocop', '1.45.1'
s.add_development_dependency 'pry', '0.14.2'
s.add_development_dependency 'rubocop', '1.62.1'
s.add_development_dependency 'pry', '0.15.2'

s.add_development_dependency 'msgpack', '1.6.0'
s.add_development_dependency 'httparty', '0.21.0'
s.add_development_dependency 'localhost', '1.1.10'
s.add_development_dependency 'debug', '1.8.0'
s.add_development_dependency 'benchmark-ips', '2.10.0'
s.add_development_dependency 'msgpack', '1.8.0'
s.add_development_dependency 'httparty', '0.23.1'
s.add_development_dependency 'localhost', '1.5.0'
s.add_development_dependency 'debug', '1.10.0'
s.add_development_dependency 'benchmark-ips', '2.14.0'

# FIXME: remove gems when all other dependencies have bundled them (not part of stdlib since Ruby 3.4)
s.add_development_dependency 'base64', '0.2.0'
s.add_development_dependency 'bigdecimal', '3.1.9'
s.add_development_dependency 'csv', '3.3.4'
s.add_development_dependency 'mutex_m', '0.3.0'
end
9 changes: 9 additions & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
require_relative './eg'

require 'minitest/autorun'
require 'minitest/unit'

::Exception.__disable_sanitized_backtrace__ = true

Expand Down Expand Up @@ -44,6 +45,14 @@ def format_trace(args)
def monotonic_clock
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
end

def inspect_method_name_for(klass_name, method_name)
if RUBY_VERSION < '3.4.0'
"`#{method_name}'"
else
"'#{klass_name}##{method_name}'"
end
end
end

class MiniTest::Test
Expand Down
5 changes: 3 additions & 2 deletions test/test_fiber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -619,16 +619,17 @@ def test_inspect
f = spin(:baz) { :foo }

expected = format(
'#<Fiber baz:%s %s:%d:in `test_inspect\' (runnable)>',
"#<Fiber baz:%s %s:%d:in #{inspect_method_name_for(self.class.name, __method__.to_s)} (runnable)>",
f.object_id,
__FILE__,
spin_line_no
)
assert_equal expected, f.inspect

f.await

expected = format(
'#<Fiber baz:%s %s:%d:in `test_inspect\' (dead)>',
"#<Fiber baz:%s %s:%d:in #{inspect_method_name_for(self.class.name, __method__.to_s)} (dead)>",
f.object_id,
__FILE__,
spin_line_no
Expand Down
2 changes: 1 addition & 1 deletion test/test_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def test_that_suspend_returns_immediately_if_no_watchers
Thread.backend.trace_proc = proc {|*r| records << r }
suspend
assert_equal [
[:block, Fiber.current, ["#{__FILE__}:#{__LINE__ - 2}:in `test_that_suspend_returns_immediately_if_no_watchers'"] + caller]
[:block, Fiber.current, ["#{__FILE__}:#{__LINE__ - 2}:in #{inspect_method_name_for(self.class.name, __method__.to_s)}"] + caller]
], records
ensure
Thread.backend.trace_proc = nil
Expand Down
Loading