class RuboCop::Cop::Lint::IncompatibleIoSelectWithFiberScheduler
io.wait_writable(timeout)
# good
IO.select([], [io], [], timeout)
# bad
io.wait_readable(timeout)
# good<br><br>IO.select(, [], [], timeout)
# bad
@example
if ‘require ’io/wait’‘ is not called.
This cop’s autocorrection is unsafe because ‘NoMethodError` occurs
@safety
It’s up to user how to handle the return value.
They are not autocorrected when assigning a return value because these types are different.
and the return value of ‘io.wait_readable` and `io.wait_writable` are `self`.
NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`,
is used as an argument, there is no alternative API, so offenses are not registered.
When an array of IO objects waiting for an exception (the third argument of `IO.select`)
Checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
def on_send(node)
def on_send(node) read, write, excepts, timeout = *io_select(node) return if excepts && !excepts.children.empty? return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read) preferred = preferred_method(read, write, timeout) message = format(MSG, preferred: preferred, current: node.source) add_offense(node, message: message) do |corrector| next if node.parent&.assignment? corrector.replace(node, preferred) end end
def preferred_method(read, write, timeout)
def preferred_method(read, write, timeout) timeout_argument = timeout.nil? ? '' : "(#{timeout.source})" if read.array_type? && read.values[0] "#{read.values[0].source}.wait_readable#{timeout_argument}" else "#{write.values[0].source}.wait_writable#{timeout_argument}" end end
def scheduler_compatible?(io1, io2)
def scheduler_compatible?(io1, io2) return false unless io1&.array_type? && io1.values.size == 1 io2&.array_type? ? io2.values.empty? : (io2.nil? || io2.nil_type?) end